問題描述

我正在開發一個具有不同新增內容的方法的主題,因此預設安裝的 Wordpress 將不會顯示任何內容。我想知道是否可以透過內部函式的方式自動匯入 XML 檔案,還是在主題被啟用之後掛鉤?

User installs theme > User activates theme > Code behind the scenes loads up an XML file and performs a silent import of its contents

目前要匯入 XML 檔案,您必須安裝 Wordpress 的 Wordpress 匯入器外掛,然後手動匯入檔案,選擇用於關聯匯入的內容的使用者,並決定是否要匯入媒體附件。我發現這個步驟是為了令我困惑的客戶型別,並希望有效地消除這一步驟的需要。

我做了一些挖掘 Wordpress 進口商指令碼,並有很多函式呼叫,我需要做什麼來刪除需要使用者輸入的部分,並使用類和它的方法目錄匯入檔案?我不知道從哪裡開始。

我的客戶是貿易商,所以即使像匯入 XML 檔案一樣簡單,它們也沒有時間,所以有空間的錯誤,特別是如果他們多次嘗試匯入導致重複的頁面。

先謝謝你。

編輯/澄清

這裡似乎有很多的混亂。我不是問如何檢查一個主題是否被啟用,我已經把該部分排序了。我問我如何解析 XML 匯入檔案,並自動匯入它,而無需使用者的努力。我本來想自動化 Wordpress 匯入外掛,您可以使用它來手動匯入 XML 檔案,選擇作者,選擇在我的 functions.php 中下載和匯入附件。

而不是需要外掛或要求我的客戶缺乏計算機知識,也不想學習如何使用外掛。

最佳解決方案

如果”only” 想要自動匯入一些帖子/頁面,你的問題有一些特定的。還有其他方法可以使用 XML 匯出檔案。

如果你有 text-only 帖子,那麼你應該使用 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 定義要匯出的內容。我將大多數事情分組合或多或少是合乎邏輯的 (如果你想匯出帖子,比你還應該匯出 postsmeta 等等) 。

該解決方案的好處是,透過 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>";
}

如果帖子不包含任何附件,如影像,此解決方案是很好的。另一個問題是,沒有使用者和沒有類別將被匯入。確保兩者都被建立用於匯入啟動 (或者包括匯出中的使用者和類別) 。匯入東西是一種非常粗糙的方法,它會覆蓋現有的東西!

如果您還想匯出附件,您必須多做一些工作。

(Sidenote:請仔細閱讀完整的答案和最後的話!本主題不適用於初學者,我不會在每個危險的程式碼行中寫下警告)

WordPress Importer 外掛似乎是匯入整個內容並自動匯入/下載附件的好方法。所以我們來看看這個外掛會做什麼。

起初,外掛要求上傳一個 XML 檔案。然後它解析 XML 檔案,並要求作者對映,並且是否應該下載附件。

為了自動執行外掛,我們需要改變一些事情。起初我們不得不跳過上傳過程。這很簡單,因為您可以將 XML 檔案與主題捆綁在一起,並且您知道 XML 檔案在哪裡。然後,我們必須跳過上傳 XML 檔案後出現的問題。我們可以預先定義我們自己的值,並將它們傳遞給匯入過程。

從外掛的副本開始。在 autoimport 主題中建立一個目錄,並將檔案 wordpress-importer.phpparsers.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 檔案的完整路徑。第二個是現有使用者的 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()方法。此方法告訴您該類的工作原理。它做三步。首先上傳 XML 檔案,然後處理它,最後匯入資料。

案例零是第一步,這是問候。如果您是第一次呼叫匯入,您將看到這一點。它將要求一個檔案上傳。案例二處理上傳並顯示匯入選項的表單。案例三終於做了進口。換句話說:前兩個步驟只需要我們提供的資料。我們只需要步驟 3(情況 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 );
}

並用方法 handle_upload()替換 $file = wp_import_handle_upload(); 中的函式,使用我們的新方法 $file = $this->import_handle_upload();

我們用自己的檔案替換了上傳過程 (應該已經存在) 。繼續並刪除更多不需要的方法。不再需要方法 gereet()header()footer()(頁首和頁尾僅列印一些文字),可以從類中刪除。在 dispatch()方法中,刪除對此方法的呼叫 ($this->header()$this->footer()) 。

第一步是完成,現在我們要關心第二步,匯入選項。匯入選項會詢問是否允許下載附件並對映作者。

第一部分很簡單。如果附件下載,設定為 true,否則為 false 。作者的對映有點複雜。如果允許建立新使用者 (來自匯入檔案的作者),請建立它們。如果沒有,請將 postss 分配給現有使用者。這是在方法 get_author_mapping()中完成的。我們必須用現有資料替換 $_POST 資料。在這裡,我們需要一個簡單的解決方案,因此如果不允許建立新使用者,我們只需將所有新作者對映到現有的作者。或者簡單地建立所有新使用者。在第二種情況下,確保所有新使用者都是虛擬使用者。如果沒有,每次匯入它們時,他們都會收到一封帶有登入名和密碼的電子郵件給新部落格!我不解釋每一行程式碼,這裡是完全重寫的方法

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();

}

在課後放置這個功能。此功能會錯過一些錯誤處理和檢查 (例如,對於空檔案引數) 。

如果你現在執行該類,你會收到很多錯誤訊息。第一個是,類失蹤了。這是因為開始時有一個 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;
}

基本上都是這樣。我在本地安裝測試這個與 test data XML 從 WordPress 。它適用於我,但它不是一個完美的生產解決方案!

還有一些關於設定一些選項的最後一句話。有兩個可以由過濾器修改的選項:

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

我想我不用說了。把這個過濾器放在你的 functions.php 和設定為 true 或 false(第一個是 PHP5.3 風格,其次是 WP 風格) 。

最後的話

我完全放在這個 gist 中。使用它自己承擔風險!我不負責任!請看一下這個要點中的檔案,我沒有在這裡解釋一下。

想想我還沒做過:設定值在匯入後的 (主題) 選項。否則每次啟動主題時都會啟動匯入。

也許我會在以後工作,清理一些事情,並對其進行更多的測試。

次佳解決方案

請允許我 re-introduce 這兩件事情:

(a)「我不是問如何… 我有那部分排序…」

»» 隨著時間的流逝,我已經學到了一個事實,即問題/修復方法並不一定需要一些’visible association’ 的問題。

(b)「… 我要做的是剝離零件…」「… 客戶是商人,所以即使是簡單的東西…」

» 為什麼為了讓客戶變得更容易?我肯定可以在可交付成果之後提供’services’,並建立一個遠端連線來為他們做 [Chargeable],而不是 「… 侵入匯入外掛…」 。我的意思是問自己,如果它真的值得你在現在的方案。但是,如果您願意投入努力,請點選下面的程式碼。如果可以的話:

我同意上面的 chrisguitarguy 和 amolv 。

正如克里斯指出,實現產出的方法的數量很多。這只是一個。雖然它有潛力耗費時間,但請參考最後幾行。

<?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 具有無可比擬的優勢,可以很容易地把事情搞清楚。

  • 雖然最初需要的努力似乎令人望而生畏,如果做得如此,你可以使其像鐘錶ф…

Finally

如何在 20 秒內將 2000 行資料推送到 2 個大括號內的最後 2 行?

phpMyAdmin» 選擇左側的資料»» 選擇右側的所有表格»» 匯出▼

➝ 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’ 部分到 $sql your_data()

  • 對於其餘的 WP 預設值,我使用 update_option(...)& update_post_meta(...)

參考文獻

注:本文內容整合自 Google/Baidu/Bing 輔助翻譯的英文資料結果。如果您對結果不滿意,可以加入我們改善翻譯效果:薇曉朵技術論壇。