问题描述
我正在开发一个具有不同添加内容的方法的主题,因此默认安装的 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.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 文件的完整路径。第二个是现有用户的 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],而不是 「… 侵入导入插件…」 。我的意思是问自己,如果它真的值得你在现在的方案。但是,如果您愿意投入努力,请点击下面的代码。如果可以的话:
-
首先掌握基本面,更好地了解数据库
-
有一个方便的参考 all functions-old is gold
-
有一个方便的参考 all hooks-simplify simplify
我同意上面的 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 辅助翻译的英文资料结果。如果您对结果不满意,可以加入我们改善翻译效果:薇晓朵技术论坛。