web-dev-qa-db-ja.com

Functions.php内からWordpress XMLファイルをインポートする

私は、コンテンツを追加する方法が異なるテーマを開発しています。そのため、Wordpressのデフォルトのインストールでは、コンテンツが表示されません。内部関数を使用してXMLファイルを自動的にインポートしたり、テーマをアクティブにした後にフックしたりすることが可能かどうかを考えていましたか。

ユーザーがテーマをインストールします > ユーザーがテーマをアクティブにします > 舞台裏のコードはXMLファイルをロードしてその内容のサイレントインポートを実行します

現在XMLファイルをインポートするには、WordpressのWordpressインポータープラグインをインストールしてから手動でファイルをインポートする必要があります。インポートしたコンテンツを関連付けるメディアを添付するユーザーを選択します。私がターゲットとしているクライアントの種類に対するこのステップは、非常にわかりにくいので、このステップの必要性を効果的に排除したいと思います。

Wordpressのインポータースクリプトを掘り下げて、関数呼び出しがたくさんあります。ユーザー入力が必要な部分を取り除き、クラスとそのmethodsディレクトリを使用してファイルをインポートするにはどうすればいいですか。本当にどこから始めたらいいのかわかりません。

私のクライアントは商人なので、XMLファイルをインポートするのと同じくらい単純なものでさえそれらを切り刻みますし、それを実行する時間がないので、特に重複ページを引き起こす試みを2回以上試みるとエラーの余地があります。

前もって感謝します。

編集/説明

ここでは多くの混乱があるようです。テーマがアクティブになっているかどうかを確認する方法を尋ねるのではなく、その部分をソートしました。 XMLインポートファイルを解析し、ユーザーの操作なしで自動的にインポートする方法について説明します。私は本質的にあなたが手動でXMLファイルをインポートし、著者を選び、私のfunctions.phpの中で添付ファイルをダウンロードしてインポートするのを選ぶのに使うことができるWordpressインポートプラグインを自動化したいです。

プラグインを必要としたり、コンピュータの知識が不足してクライアントに要求したりするのではなく、プラグインを使用してプラグインを使用する方法を習得する必要もありません。

6

一部の投稿/ページを自動的にインポートする場合にのみ、質問は具体的です。 XMLエクスポートファイルを使用してこれを行う方法は他にもあります。

テキストのみの投稿がある場合は、 LOAD DATA INFILE を使用する必要があります。最初に、投稿をエクスポートする必要があります。

global $wpdb, $wp_filesystem;

$tables = array(
        'posts'    => array( 'posts', 'postmeta' ),
        'comments' => array( 'comments', 'commentmeta' ),
        'terms'    => array( 'terms', 'term_taxonomy', 'term_relationships' ),
        'users'    => array( 'user', 'usermeta' ),
        'links'    => array( 'links' ),
        'options'  => array( 'options' ),
        'other'    => array(),
        // for multiside
        'multiside' => array( 'blogs', 'signups', 'site', 'sitemeta', 'sitecategories', 'registration_log', 'blog_versions' )

);

$exports = array( 'posts', 'comments', 'users' );

$exportdir = TEMPLATEPATH . '/export';

if ( ! is_dir( $exportdir ) ) {
    $mkdir = wp_mkdir_p( $exportdir );
    if ( false == $mkdir || ! is_dir( $exportdir ) )
        throw new Exception( 'Cannot create export directory. Aborting.' );
}

// empty the export dir else MySQL throws errors
$files = glob( $exportdir . '/*' );
if ( ! empty( $files ) ) {
    foreach( $files as $file )
        unlink( $file );
}

foreach ( $exports as $export ) {

    if ( ! isset( $tables[$export] ) )
        continue;

    if ( ! empty( $tables[$export] ) ) {
        foreach ( $tables[$export] as $table ) {

            $outfile =  sprintf( '%s/%s_dump.sql', $exportdir, $table );
            $sql = "SELECT * FROM {$wpdb->$table} INTO OUTFILE '%s'";
            $res = $wpdb->query( $wpdb->prepare( $sql, $outfile ) );

            if ( is_wp_error( $res ) )
                echo "<p>Cannot export {$table} into {$outfile}</p>";
        }
    }
}

これにより、テーマフォルダーにディレクトリが作成され(書き込み可能であることを確認してください!)、投稿とコメント(メタを含む)をダンプファイルにエクスポートします。配列exportを使用して、エクスポートするものを定義します。私はほとんどのことを多かれ少なかれ論理的にグループ化しました(投稿をエクスポートしたい場合は、投稿メタなどもエクスポートする必要があります)。

このソリューションの利点は、SELECTステートメントを使用すると、特定のもの(たとえば、特別なカテゴリの投稿のみ、ページのみ、ゴミ箱に入れた投稿など)を定義できることです。

今、あなたは新しいものにこのようなものをインポートしたい

global $wpdb;

$exportdir = TEMPLATEPATH . '/export';

$files = glob( $exportdir . '/*_dump.sql' );

foreach ( $files as $file ) {

    preg_match( '#/([^/]+)_dump.sql$#is', $file, $match );

    if ( ! isset( $match[1] ) )
        continue;

    $sql = "LOAD DATA LOCAL INFILE '%s' INTO TABLE {$wpdb->$match[1]};";

    $res = $wpdb->query( $wpdb->prepare( $sql, $file ) );

    if ( is_wp_error( $res ) )
        echo "<p>Cannot import data from file {$file} into table {$wpdb->$match[1]}</p>";
}

このソリューションは、投稿did notに画像などの添付ファイルが含まれている場合に適しています。もう1つの問題は、ユーザーもカテゴリもインポートされないことです。インポート開始前に両方が作成されていることを確認してください(またはエクスポートにユーザーとカテゴリを含めてください)。インポートするのは非常に大まかな方法​​で、既存のものを上書きします!

添付ファイルもエクスポートする場合は、もう少し作業が必要です。

(補足:完全な答えと最後の最後の言葉を読んでください!このトピックは初心者向けではなく、危険なコード行ごとに警告を書くことはありません)

WordPress Importerプラグインは、全体をインポートし、添付ファイルを自動的にインポート/ダウンロードするための良い方法のようです。それでは、このプラグインが何をするのか見てみましょう。

最初に、プラグインはアップロードするXMLファイルを要求します。次に、XMLファイルを解析し、作成者のマッピングと、添付ファイルをダウンロードするかどうかを尋ねます。

プラグインを自動的に実行するには、いくつかの変更が必要です。最初に、アップロードプロセスをスキップする必要があります。 XMLファイルをテーマにバンドルでき、XMLファイルの場所がわかっているため、これは非常に簡単です。次に、XMLファイルをアップロードした後に表示される質問をスキップする必要があります。独自の値を事前に定義して、インポートプロセスに渡すことができます。

プラグインのコピーから始めます。テーマにautoimportなどのディレクトリを作成し、ファイルwordpress-importer.phpおよびparsers.phpをそこにコピーします。ファイルwordpress-importer.phpの名前をautoimporter.phpのような名前に変更することをお勧めします。テーマ関数に関数呼び出しを追加して、自動化されたimpoprtをトリガーします

/**
 * Auto import a XML file
 */
add_action( 'after_setup_theme', 'autoimport' );

function autoimport() {
    // get the file
    require_once TEMPLATEPATH . '/autoimport/autoimporter.php';

    if ( ! class_exists( 'Auto_Importer' ) )
        die( 'Auto_Importer not found' );

    // call the function
    $args = array(
        'file'        => TEMPLATEPATH . '/autoimport/import.xml',
        'map_user_id' => 1
    );

    auto_import( $args );

}

最初にいくつかの引数を設定します。最初のことは、XMLファイルへの完全なパスです。 2つ目はexistingユーザーのIDです。著者のマッピングにはこのユーザーが必要です。これは、新しい著者を作成する必要がないときにすべての投稿がマッピングされるユーザーです。

次に、プラグインの仕組みを理解する必要があります。名前を変更したプラグインファイルを開き、最後までスクロールします。関数wordpress_importer_init()とアクション呼び出しがあります。両方とも削除してください。もう必要ありません。ファイルの先頭に移動して、プラグインヘッダー(ファイルの先頭にあるコメント)を削除します。その後、クラスの名前をWP_ImporterのようにAuto_Importerなどに変更します。function_existsステートメントと最初のメソッドWP_Importer(これはPHP4スタイルのコンストラクター)を調整することを忘れないでください。

後でXMLファイルをクラスコンストラクターに直接渡し、最初のメソッドをこれに変更します

var $xmlfile = '';
var $map_user_id = 0;

function Auto_Importer( $args ) {

    if ( file_exists( $args['file'] ) ) {

        // for windows systems
        $file = str_replace( '\\', '/', $args['file'] );

        $this->xmlfile = $file;
    }

    if ( isset( $args['map_user_id'] ) )
        $this->map_user_id = $args['map_user_id'];

}

これで、クラス内のいくつかのメソッドを削除および変更できます。最初のメソッドはdispatch()メソッドです。このメソッドは、クラスの動作方法を示します。 3つのステップを実行します。最初にXMLファイルをアップロードしてから処理し、最後にデータをインポートします。

ケース0は最初のステップであり、挨拶です。これは、初めてインポートを呼び出したときに表示される部分です。アップロードするファイルを要求します。ケース2は、アップロードを処理し、インポートオプションのフォームを表示します。ケース3が最終的にインポートを行います。つまり、最初の2つのステップでは、自分で提供できるデータのみを要求します。ステップ3(ケース2)のみが必要で、ステップ1と2で求められたデータを提供する必要があります。

ステップ2では、wp_import_handle_upload()への関数呼び出しが表示されます。この関数は、xmlファイルに関するいくつかの情報をセットアップします。ファイルをアップロードしていないため、この関数は使用できなくなりました。そのため、関数をコピーして変更する必要があります。クラス内に新しいメソッドを作成します

function import_handle_upload() {

    $url = get_template_directory_uri() . str_replace( TEMPLATEPATH, '', $this->xmlfile );
    $type = 'application/xml'; // we know the mime type of our file
    $file = $this->xmlfile;
    $filename = basename( $this->xmlfile );

    // Construct the object array
    $object = array( 'post_title' => $filename,
            'post_content' => $url,
            'post_mime_type' => $type,
            'guid' => $url,
            'context' => 'import',
            'post_status' => 'private'
    );

    // Save the data
    $id = wp_insert_attachment( $object, $file );

    // schedule a cleanup for one day from now in case of failed import or missing wp_import_cleanup() call
    wp_schedule_single_event( time() + DAY_IN_SECONDS, 'importer_scheduled_cleanup', array( $id ) );

    return array( 'file' => $file, 'id' => $id );
}

メソッド$file = wp_import_handle_upload();の関数呼び出しhandle_upload()を新しいメソッド$file = $this->import_handle_upload();に置き換えます

ここで、アップロードプロセスを独自のファイル(既に存在するはずのファイル)に置き換えました。続行して、不要なメソッドを削除します。メソッドgereet()header()およびfooter()は不要になり(ヘッダーとフッターは一部のテキストのみを印刷します)、クラスから削除できます。 dispatch()メソッドで、このメソッド($this->header()および$this->footer())への呼び出しを削除します。

最初のステップは完了しました。次に、2番目のステップであるインポートオプションに注意する必要があります。インポートオプションは、添付ファイルのダウンロードと作成者のマッピングを許可するかどうかを尋ねます。

最初の部分は簡単です。添付ファイルをダウンロードする必要がある場合はtrueに設定し、そうでない場合はfalseに設定します。著者のマッピングはもう少し複雑です。新しいユーザー(インポートファイルの作成者)の作成が許可されている場合は、作成します。そうでない場合は、投稿を既存のユーザーに割り当てます。これはget_author_mapping()メソッドで行われます。 $_POSTデータを既存のデータで置き換える必要があります。ここでは単純なソリューションが必要なので、新しいユーザーの作成が許可されていない場合は、すべての新しい作成者を既存の作成者に単純にマッピングします。または、すべての新しいユーザーを作成します。 2番目の場合、すべての新しいユーザーがダミーユーザーであることを確認してください。そうでない場合、インポートするたびに、新しいブログへのログインとパスワードが記載されたメールが届きます!!コードのすべての行を説明しません。

function get_author_mapping( $map_users_id ) {
    if ( empty( $this->authors ) )
        return;

    $create_users = $this->allow_create_users();

    foreach ( (array) $this->authors as $i => $data ) {

        $old_login = $data['author_login'];

        // Multisite adds strtolower to sanitize_user. Need to sanitize here to stop breakage in process_posts.
        $santized_old_login = sanitize_user( $old_login, true );
        $old_id = isset( $this->authors[$old_login]['author_id'] ) ? intval($this->authors[$old_login]['author_id']) : false;

        if ( ! $create_users ) {
            $user = get_userdata( intval($map_users_id) );
            if ( isset( $user->ID ) ) {
                if ( $old_id )
                    $this->processed_authors[$old_id] = $user->ID;
                $this->author_mapping[$santized_old_login] = $user->ID;
            }
        } else if ( $create_users ) {
            if ( ! empty($this->authors[$i]) ) {
                $user_id = wp_create_user( $this->authors[$i]['author_login'], wp_generate_password() );
            } else if ( $this->version != '1.0' ) {
                $user_data = array(
                    'user_login' => $old_login,
                    'user_pass' => wp_generate_password(),
                    'user_email' => isset( $this->authors[$old_login]['author_email'] ) ? $this->authors[$old_login]['author_email'] : '',
                    'display_name' => $this->authors[$old_login]['author_display_name'],
                    'first_name' => isset( $this->authors[$old_login]['author_first_name'] ) ? $this->authors[$old_login]['author_first_name'] : '',
                    'last_name' => isset( $this->authors[$old_login]['author_last_name'] ) ? $this->authors[$old_login]['author_last_name'] : '',
                );
                $user_id = wp_insert_user( $user_data );
            }

            if ( ! is_wp_error( $user_id ) ) {
                if ( $old_id )
                    $this->processed_authors[$old_id] = $user_id;
                $this->author_mapping[$santized_old_login] = $user_id;
            } else {
                printf( __( 'Failed to create new user for %s. Their posts will be attributed to the current user.', 'wordpress-importer' ), esc_html($this->authors[$old_login]['author_display_name']) );
                if ( defined('IMPORT_DEBUG') && IMPORT_DEBUG )
                    echo ' ' . $user_id->get_error_message();
                echo '<br />';
            }
        }

        // failsafe: if the user_id was invalid, default to the current user
        if ( ! isset( $this->author_mapping[$santized_old_login] ) ) {
            if ( $old_id )
                $this->processed_authors[$old_id] = (int) get_current_user_id();
            $this->author_mapping[$santized_old_login] = (int) get_current_user_id();
        }
    }
}

まだやるべきことが残っています。関数auto_import()を最初に追加

function auto_import( $args ) {

    $defaults = array( 'file' => '', 'map_user_id' => 0);
    $args = wp_parse_args( $args, $defaults );

    $autoimport = new Auto_Importer( $args );
    $autoimport->do_import();

}

この関数をクラスの後に配置します。この関数は、いくつかのエラー処理とチェックを逃します(たとえば、空のファイル引数)。

クラスを実行すると、多くのエラーメッセージが表示されます。 1つ目は、クラスが欠落していることです。これは、先頭にifステートメントがあるためです。

if ( ! defined( 'WP_LOAD_IMPORTERS' ) )
    return;

削除する必要があります。削除しないと、ファイルが完全に解析されません。この時点でロードされない関数がいくつかあります。いくつかのファイルを含める必要があります。

$required = array(
    'post_exists'                     => ABSPATH . 'wp-admin/includes/post.php',
    'wp_generate_attachment_metadata' => ABSPATH . 'wp-admin/includes/image.php',
    'comment_exists'                  => ABSPATH . 'wp-admin/includes/comment.php'
);

foreach ( $required as $func => $req_file ) {
    if ( ! function_exists( $func ) )
        require_once $req_file;
}

基本的にはすべてです。 WordPressの test data XML を使用して、ローカルインストールでこれをテストします。それは私のために働くが、それは生産のための完璧なソリューションではありません!

そして、いくつかのオプションの設定に関する最後の言葉。フィルターによって変更できる2つのオプションがあります。

add_filter( 'import_allow_create_users', function() { return false; } );
add_filter( 'import_allow_fetch_attachments', '__return_false' );

説明する必要はないと思います。 functions.phpにこのフィルターを設定し、trueまたはfalseをセットアップします(最初のフィルターはPHP5.3スタイル、2番目のフィルターはWPスタイルです)。

Very Last Words

私はこれをまとめて Gist に入れました。 ご自身の責任で使用してください!私は何の責任も負いません!。 Gistのファイルをご覧ください。ここでは小さなステップをすべて説明しませんでした。

私がやっていないと思う:値を設定します。インポート後の(テーマ)オプション。そうでない場合、テーマがアクティブ化されるたびにインポートが開始されます。

たぶん私は将来的にそれに取り組み、いくつかのものをクリーンアップし、さらにテストを実行するでしょう。

18
Ralf912

ここで2つのことを再紹介させてください。

(a)「方法を尋ねるのではなく、その部分をソートしました...」

""私は、問題/修正へのアプローチが必ずしも手元の問題との「目に見える関連」を必ずしも必要としないという事実で、大丈夫であることを学びました。

(b)「...部品を除去するためにやらなければならないのか...」「...クライアントは商人なので、単純なものでも...」

""なぜクライアントをもっと簡単にするのか費用はかかります自分自身を難しくするのですか?確かに、「...インポートプラグインをハッキングする...」の代わりに、成果物の後に「サービス」を提供し、それらのためにリモート接続を確立して[有料]できます。私が意味するのは、あなたの現在の事柄で本当にそれが価値があるかどうかを自問してください。しかし、あなたが努力をする気があるなら、以下のコードを試してみてください。可能な場合:

上記のchrisguitarguyとamolvの両方に同意します。

クリスが指摘したように、出力を達成する方法は数多くあります。これは1つです。面倒に長くなる可能性がありますが、他の何よりも前の最後の数行を参照してください。

<?php 
/* I usually dump ONE line in functions.php  */
require_once (TEMPLATEPATH . '/includes/whatever.php');

/* and then in that loc CHECK FIRST*/
if ((is_admin() && isset($_GET['activated']) && $pagenow == 'themes.php')||(is_admin() && isset($_GET['upgrade']) && $pagenow == 'admin.php' && $_GET['page'] == 'admin-options.php')) 
{

global $wpdb, $wp_rewrite, $hey;

// create tables
your_tables();

// insert value defaults
your_values();

// insert link defaults
your_links();

// pages and tpl
your_pages();

// create category or categories
// wp_create_categories     $categories, $post_id = ''
// wp_create_category   $cat_name, $parent

//flush rewrite
$wp_rewrite->flush_rules();

}

// create them db tables
function your_tables() {
global $wpdb, $hey;

$collate = '';
if($wpdb->supports_collation()) {
if(!empty($wpdb->charset)) $collate = "DEFAULT CHARACTER SET $wpdb->charset";
if(!empty($wpdb->collate)) $collate .= " COLLATE $wpdb->collate";
}

$sql = "CREATE TABLE IF NOT EXISTS ". $wpdb->prefix . "table1_name" ." (
`id` INT(10) NOT NULL auto_increment,
`some_name1` VARCHAR(255) NOT NULL,
`some_name2` VARCHAR(255) NOT NULL,
`some_name3` LONGTEXT,
`some_name4` LONGTEXT NOT NULL,
`some_name5` VARCHAR(255) DEFAULT NULL,
`some_name6` VARCHAR(255) DEFAULT NULL,
`some_name7` DATETIME NOT NULL DEFAULT '0000-00-00 00:00:00',
`some_name8` DATETIME NOT NULL DEFAULT '0000-00-00 00:00:00',
PRIMARY KEY id  (`id`)) $collate;";

$wpdb->query($sql);


$sql = "CREATE TABLE IF NOT EXISTS ". $wpdb->prefix . "table2_name" ." (
`meta_id` INT(10) NOT NULL AUTO_INCREMENT,
`some_name1` INT(10) NOT NULL,
`some_name2` INT(10) NOT NULL,
`some_name3` VARCHAR(255) NOT NULL,
`some_name4` INT(10) NOT NULL,
PRIMARY KEY id  (`meta_id`)) $collate;";

$wpdb->query($sql);

// and so on and so forth

/* Insert default/ALL data into tables */
// BUT CHECK FIRST IF DATA EXISTS. IF = YES DONT Push IN ANYTHING

$sql = "SELECT field_id " . "FROM " . $wpdb->prefix . "table1_name LIMIT 1";

$wpdb->get_results($sql);

if($wpdb->num_rows == 0) {

// more code will follow
// i have to get going now

} 

?>

注意

  • しばらくWPを使用している場合は、言うまでもありません最初にデータベースをバックアップします

  • phpMyAdminには生の力があり、慎重に物事を台無しにするのが非常に簡単です。

  • 必要な労力は最初は気が遠くなるように見えるかもしれませんが、正しくやれば時計仕掛けのように機能させることができます...

最後に

20行で2000行のデータをこれら2つのブレース内の最後の2行にプッシュする方法は?

phpMyAdmin"左側でDBを選択""右側ですべてのテーブルを選択""エクスポート▼

➝ Custom: display all options
➝ View output as text = ON
➝ Save output to a file = OFF
➝ Compression = NONE
➝ Format = SQL
➝ Dump Table = STRUCTURE & DATA
➝ Add DROP TABLE... = OFF (Important!)
➝ Syntax to use = "both of the above"

»» GO!
  • 次の画面から、[STRUCTURE]部分をyour_tables()の$ sql = "...."にコピーし、 'DATA'部分をyour_data()$sqlにコピーできます

  • 残りのWPデフォルトでは、update_option(...)update_post_meta(...)を使用します

4
user32057

functions.php条件で確認することができます

if( isset($_GET['activated']) && 'themes.php' == $GLOBALS['pagenow']) )
{ 
  // check duplicates 
   // call import class 
   //xml import code 
   // do whatever you want to 
}

テーマがアクティブになるとすぐに、これは自動的にデータをインポートします。

0
amolv

プラグイン用の register_activation_hook と同等のテーマはありません - いくつかの ハック があります。どうして?テーマは肌だからです。特にコンテンツの表示に関連する機能のみがテーマに含まれるべきで、コンテンツ自体には含まれません。

方法としては、コールバック関数を1回実行するには 上記の例 を使用してください。 WordPressインポーターは、PHPに 多く _ { 異なる方法 から XMLの解析 までのXMLファイルを処理します。あなたの選択を取り、ファイルを解析し、あなたがそれで望むことをする。

0
chrisguitarguy