Created
December 20, 2011 13:21
-
-
Save tott/1501546 to your computer and use it in GitHub Desktop.
Exporter for WP_CLI
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
WP_CLI::addCommand('export', 'ExportCommand'); | |
/** | |
* Implement export command | |
* | |
* @package wp-cli | |
* @subpackage commands/internals | |
*/ | |
class ExportCommand extends WP_CLI_Command { | |
protected $default_subcommand = 'validate_arguments'; | |
public $export_args = array(); | |
public static function help() { | |
WP_CLI::warning( <<<EOB | |
Please use the following parameters: | |
usage: wp export --path=<export-path> --user=<username/id> | |
wp export --path=/tmp/ --user=admin --post_type=post --start_date=2011-01-01 --end_date=2011-12-31 | |
Required parameters: | |
--path Full Path to directory where WXR export files should be stored | |
--user Username/ID the import should run as | |
Optional filters: | |
--start_date Export only posts new than this date in format YYYY-MM-DD | |
--end_date Export only posts older than this date in format YYYY-MM-DD | |
--post_type Export only posts with this post_type | |
--author Export only posts by this author | |
--category Export only posts in this category | |
--post_status Export only posts with this post_status | |
--skip_comments Don't export comments | |
EOB | |
); | |
} | |
private function dispatch() { | |
WP_CLI::line(); | |
WP_CLI::line( 'Starting export processs' ); | |
WP_CLI::line(); | |
$this->export_wp( $this->export_args ); | |
} | |
/** | |
* Argument validation functions below | |
*/ | |
public function validate_arguments( $args, $assoc_args ) { | |
$defaults = array( | |
'path' => NULL, | |
'user' => NULL, | |
'start_date' => NULL, | |
'end_date' => NULL, | |
'post_type' => NULL, | |
'author' => NULL, | |
'category' => NULL, | |
'post_status' => NULL, | |
'skip_comments' => NULL, | |
); | |
$args = wp_parse_args( $assoc_args, $defaults ); | |
$has_errors = false; | |
foreach( $defaults as $argument => $default_value ) { | |
if ( is_callable( array( &$this, 'check_' . $argument ) ) ) { | |
$result = call_user_func( array( &$this, 'check_' . $argument ), $args[$argument] ); | |
if ( false === $result && false === $has_errors ) | |
$has_errors = true; | |
} | |
} | |
if ( true === $has_errors ) { | |
WP_CLI::error( 'There were errors. Please review the items listed above' ); | |
exit; | |
} | |
$this->wxr_path = $assoc_args['path']; | |
$this->dispatch(); | |
} | |
private function check_path( $path ) { | |
if ( empty( $path ) ) { | |
$this->help(); | |
exit; | |
} | |
if ( !is_dir( $path ) ) { | |
WP_CLI::error( sprintf( "The path %s does not exist", $path ) ); | |
exit; | |
} | |
return true; | |
} | |
private function check_user( $user ) { | |
if ( empty( $user ) ) { | |
$this->help(); | |
exit; | |
} | |
if ( is_numeric( $user ) ) { | |
$user_id = (int) $user; | |
} else { | |
$user_id = (int) username_exists( $user ); | |
} | |
if ( !$user_id || !wp_set_current_user( $user_id ) ) { | |
WP_CLI::error( sprintf( "Could not get a user_id for this user: %s", var_export( $user_id, true ) ) ); | |
exit; | |
} | |
$current_user = wp_get_current_user(); | |
$this->user_id = (int) $user_id; | |
return true; | |
} | |
private function check_start_date( $date ) { | |
if ( is_null( $date ) ) | |
return true; | |
$time = strtotime( $date ); | |
if ( !empty( $date ) && !$time ) { | |
WP_CLI::warning( sprintf( "The start_date %s is invalid", $date ) ); | |
return false; | |
} | |
$this->export_args['start_date'] = date( 'Y-m-d', $time ); | |
return true; | |
} | |
private function check_end_date( $date ) { | |
if ( is_null( $date ) ) | |
return true; | |
$time = strtotime( $date ); | |
if ( !empty( $date ) && !$time ) { | |
WP_CLI::warning( sprintf( "The end_date %s is invalid", $date ) ); | |
return false; | |
} | |
$this->export_args['start_date'] = date( 'Y-m-d', $time ); | |
return true; | |
} | |
private function check_post_type( $post_type ) { | |
if ( is_null( $post_type ) ) | |
return true; | |
$post_types = get_post_types(); | |
if ( !in_array( $post_type, $post_types ) ) { | |
WP_CLI::warning( sprintf( 'The post type %s does not exists. Choose "all" or any of these existing post types instead: %s', $post_type, implode( ", ", $post_types ) ) ); | |
return false; | |
} | |
$this->export_args['content'] = $post_type; | |
return true; | |
} | |
private function check_author( $author ) { | |
if ( is_null( $author ) ) | |
return true; | |
$authors = get_users_of_blog(); | |
if ( empty( $authors ) || is_wp_error( $authors ) ) { | |
WP_CLI::warning( sprintf( "Could not find any authors in this blog" ) ); | |
return false; | |
} | |
$hit = false; | |
foreach( $authors as $user ) { | |
if ( $hit ) | |
break; | |
if ( (int) $author == $user->ID || $author == $user->user_login ) | |
$hit = $user->ID; | |
} | |
if ( false === $hit ) { | |
$authors_nice = array(); | |
foreach( $authors as $_author ) | |
$authors_nice[] = sprintf( '%s (%s)', $_author->user_login, $_author->display_name ); | |
WP_CLI::warning( sprintf( 'Could not find a matching author for %s. The following authors exist: %s', $author, implode( ", ", $authors_nice ) ) ); | |
return false; | |
} | |
$this->export_args['author'] = $hit; | |
return true; | |
} | |
private function check_category( $category ) { | |
if ( is_null( $category ) ) | |
return true; | |
$term = category_exists( $category ); | |
if ( empty( $term ) || is_wp_error( $term ) ) { | |
WP_CLI::warning( sprintf( 'Could not find a category matching %s', $category ) ); | |
return false; | |
} | |
$this->export_args['category'] = $category; | |
return true; | |
} | |
private function check_post_status( $status ) { | |
if ( is_null( $status ) ) | |
return true; | |
$stati = get_post_statuses(); | |
if ( empty( $stati ) || is_wp_error( $stati ) ) { | |
WP_CLI::warning( sprintf( 'Could not find any post stati', $category ) ); | |
return false; | |
} | |
if ( !isset( $stati[$status] ) ) { | |
WP_CLI::warning( sprintf( 'Could not find a post_status matching %s. Here is a list of available stati: %s', $status, implode( ", ", array_keys( $stati ) ) ) ); | |
return false; | |
} | |
$this->export_args['status'] = $status; | |
return true; | |
} | |
private function check_skip_comments( $skip ) { | |
if ( is_null( $skip ) ) | |
return true; | |
if ( (int) $skip <> 0 && (int) $skip <> 1 ) { | |
WP_CLI::warning( sprintf( 'skip_comments needs to be 0 (no) or 1 (yes)', $category ) ); | |
return false; | |
} | |
$this->export_args['skip_comments'] = $skip; | |
return true; | |
} | |
/** | |
* Workaround to prevent memory leaks from growing variables | |
*/ | |
private function stop_the_insanity() { | |
global $wpdb, $wp_object_cache; | |
$wpdb->queries = array(); // or define( 'WP_IMPORTING', true ); | |
if ( !is_object( $wp_object_cache ) ) | |
return; | |
$wp_object_cache->group_ops = array(); | |
$wp_object_cache->stats = array(); | |
$wp_object_cache->memcache_debug = array(); | |
$wp_object_cache->cache = array(); | |
$wp_object_cache->__remoteset(); // important | |
} | |
/** | |
* Export function as it is defined in the original code of export_wp defined in wp-admin/includes/export.php | |
*/ | |
private function export_wp( $args = array() ) { | |
require_once ABSPATH . 'wp-admin/includes/export.php'; | |
global $wpdb, $post; | |
// call export_wp as we need the functions defined in it. | |
$dummy_args = array( 'content' => 'i-do-not-exist' ); | |
ob_start(); | |
export_wp( $dummy_args ); | |
ob_end_clean(); | |
/** | |
* This is mostly the original code of export_wp defined in wp-admin/includes/export.php | |
*/ | |
$defaults = array( 'content' => 'all', 'author' => false, 'category' => false, | |
'start_date' => false, 'end_date' => false, 'status' => false, 'skip_comments' => false, | |
); | |
$args = wp_parse_args( $args, $defaults ); | |
WP_CLI::line( "Exporting with export_wp with arguments: " . var_export( $args, true ) ); | |
do_action( 'export_wp' ); | |
$sitename = sanitize_key( get_bloginfo( 'name' ) ); | |
if ( ! empty( $sitename ) ) | |
$sitename .= '.'; | |
$append = array( date( 'Y-m-d' ) ); | |
foreach( array_keys( $args ) as $arg_key ) { | |
if ( $defaults[$arg_key] <> $args[$arg_key] ) | |
$append[]= "$arg_key-" . (string) $args[$arg_key]; | |
} | |
$file_name_base = $sitename . 'wordpress.' . implode( ".", $append ); | |
if ( 'all' != $args['content'] && post_type_exists( $args['content'] ) ) { | |
$ptype = get_post_type_object( $args['content'] ); | |
if ( ! $ptype->can_export ) | |
$args['content'] = 'post'; | |
$where = $wpdb->prepare( "{$wpdb->posts}.post_type = %s", $args['content'] ); | |
} else { | |
$post_types = get_post_types( array( 'can_export' => true ) ); | |
$esses = array_fill( 0, count( $post_types ), '%s' ); | |
$where = $wpdb->prepare( "{$wpdb->posts}.post_type IN (" . implode( ',', $esses ) . ')', $post_types ); | |
} | |
if ( $args['status'] && ( 'post' == $args['content'] || 'page' == $args['content'] ) ) | |
$where .= $wpdb->prepare( " AND {$wpdb->posts}.post_status = %s", $args['status'] ); | |
else | |
$where .= " AND {$wpdb->posts}.post_status != 'auto-draft'"; | |
$join = ''; | |
if ( $args['category'] && 'post' == $args['content'] ) { | |
if ( $term = term_exists( $args['category'], 'category' ) ) { | |
$join = "INNER JOIN {$wpdb->term_relationships} ON ({$wpdb->posts}.ID = {$wpdb->term_relationships}.object_id)"; | |
$where .= $wpdb->prepare( " AND {$wpdb->term_relationships}.term_taxonomy_id = %d", $term['term_taxonomy_id'] ); | |
} | |
} | |
if ( 'post' == $args['content'] || 'page' == $args['content'] ) { | |
if ( $args['author'] ) | |
$where .= $wpdb->prepare( " AND {$wpdb->posts}.post_author = %d", $args['author'] ); | |
if ( $args['start_date'] ) | |
$where .= $wpdb->prepare( " AND {$wpdb->posts}.post_date >= %s", date( 'Y-m-d', strtotime( $args['start_date'] ) ) ); | |
if ( $args['end_date'] ) | |
$where .= $wpdb->prepare( " AND {$wpdb->posts}.post_date < %s", date( 'Y-m-d', strtotime( '+1 month', strtotime( $args['end_date'] ) ) ) ); | |
} | |
// grab a snapshot of post IDs, just in case it changes during the export | |
$post_ids = $wpdb->get_col( "SELECT ID FROM {$wpdb->posts} $join WHERE $where" ); | |
// get the requested terms ready, empty unless posts filtered by category or all content | |
$cats = $tags = $terms = array(); | |
if ( isset( $term ) && $term ) { | |
$cat = get_term( $term['term_id'], 'category' ); | |
$cats = array( $cat->term_id => $cat ); | |
unset( $term, $cat ); | |
} else if ( 'all' == $args['content'] ) { | |
$categories = (array) get_categories( array( 'get' => 'all' ) ); | |
$tags = (array) get_tags( array( 'get' => 'all' ) ); | |
$custom_taxonomies = get_taxonomies( array( '_builtin' => false ) ); | |
$custom_terms = (array) get_terms( $custom_taxonomies, array( 'get' => 'all' ) ); | |
// put categories in order with no child going before its parent | |
while ( $cat = array_shift( $categories ) ) { | |
if ( $cat->parent == 0 || isset( $cats[$cat->parent] ) ) | |
$cats[$cat->term_id] = $cat; | |
else | |
$categories[] = $cat; | |
} | |
// put terms in order with no child going before its parent | |
while ( $t = array_shift( $custom_terms ) ) { | |
if ( $t->parent == 0 || isset( $terms[$t->parent] ) ) | |
$terms[$t->term_id] = $t; | |
else | |
$custom_terms[] = $t; | |
} | |
unset( $categories, $custom_taxonomies, $custom_terms ); | |
} | |
WP_CLI::line( 'Exporting ' . count( $post_ids ) . ' items' ); | |
WP_CLI::line( 'Exporting ' . count( $cats ) . ' cateogries' ); | |
WP_CLI::line( 'Exporting ' . count( $tags ) . ' tags' ); | |
WP_CLI::line( 'Exporting ' . count( $terms ) . ' terms' ); | |
WP_CLI::line(); | |
$progress = $this->progress_bar( 'exporting', count( $post_ids ) ); | |
ob_start(); | |
echo '<?xml version="1.0" encoding="' . get_bloginfo( 'charset' ) . "\" ?>\n"; | |
?> | |
<!-- This is a WordPress eXtended RSS file generated by WordPress as an export of your site. --> | |
<!-- It contains information about your site's posts, pages, comments, categories, and other content. --> | |
<!-- You may use this file to transfer that content from one site to another. --> | |
<!-- This file is not intended to serve as a complete backup of your site. --> | |
<!-- To import this information into a WordPress site follow these steps: --> | |
<!-- 1. Log in to that site as an administrator. --> | |
<!-- 2. Go to Tools: Import in the WordPress admin panel. --> | |
<!-- 3. Install the "WordPress" importer from the list. --> | |
<!-- 4. Activate & Run Importer. --> | |
<!-- 5. Upload this file using the form provided on that page. --> | |
<!-- 6. You will first be asked to map the authors in this export file to users --> | |
<!-- on the site. For each author, you may choose to map to an --> | |
<!-- existing user on the site or to create a new user. --> | |
<!-- 7. WordPress will then import each of the posts, pages, comments, categories, etc. --> | |
<!-- contained in this file into your site. --> | |
<?php the_generator( 'export' ); ?> | |
<rss version="2.0" | |
xmlns:excerpt="http://wordpress.org/export/<?php echo WXR_VERSION; ?>/excerpt/" | |
xmlns:content="http://purl.org/rss/1.0/modules/content/" | |
xmlns:wfw="http://wellformedweb.org/CommentAPI/" | |
xmlns:dc="http://purl.org/dc/elements/1.1/" | |
xmlns:wp="http://wordpress.org/export/<?php echo WXR_VERSION; ?>/" | |
> | |
<channel> | |
<title><?php bloginfo_rss( 'name' ); ?></title> | |
<link><?php bloginfo_rss( 'url' ); ?></link> | |
<description><?php bloginfo_rss( 'description' ); ?></description> | |
<pubDate><?php echo date( 'D, d M Y H:i:s +0000' ); ?></pubDate> | |
<language><?php echo get_option( 'rss_language' ); ?></language> | |
<wp:wxr_version><?php echo WXR_VERSION; ?></wp:wxr_version> | |
<wp:base_site_url><?php echo wxr_site_url(); ?></wp:base_site_url> | |
<wp:base_blog_url><?php bloginfo_rss( 'url' ); ?></wp:base_blog_url> | |
<?php wxr_authors_list(); ?> | |
<?php foreach ( $cats as $c ) : ?> | |
<wp:category><wp:term_id><?php echo $c->term_id ?></wp:term_id><wp:category_nicename><?php echo $c->slug; ?></wp:category_nicename><wp:category_parent><?php echo $c->parent ? $cats[$c->parent]->slug : ''; ?></wp:category_parent><?php wxr_cat_name( $c ); ?><?php wxr_category_description( $c ); ?></wp:category> | |
<?php endforeach; ?> | |
<?php foreach ( $tags as $t ) : ?> | |
<wp:tag><wp:term_id><?php echo $t->term_id ?></wp:term_id><wp:tag_slug><?php echo $t->slug; ?></wp:tag_slug><?php wxr_tag_name( $t ); ?><?php wxr_tag_description( $t ); ?></wp:tag> | |
<?php endforeach; ?> | |
<?php foreach ( $terms as $t ) : ?> | |
<wp:term><wp:term_id><?php echo $t->term_id ?></wp:term_id><wp:term_taxonomy><?php echo $t->taxonomy; ?></wp:term_taxonomy><wp:term_slug><?php echo $t->slug; ?></wp:term_slug><wp:term_parent><?php echo $t->parent ? $terms[$t->parent]->slug : ''; ?></wp:term_parent><?php wxr_term_name( $t ); ?><?php wxr_term_description( $t ); ?></wp:term> | |
<?php endforeach; ?> | |
<?php if ( 'all' == $args['content'] ) wxr_nav_menu_terms(); ?> | |
<?php do_action( 'rss2_head' ); ?> | |
<?php if ( $post_ids ) { | |
global $wp_query; | |
$wp_query->in_the_loop = true; // Fake being in the loop. | |
// fetch 20 posts at a time rather than loading the entire table into memory | |
while ( $next_posts = array_splice( $post_ids, 0, 20 ) ) { | |
$where = 'WHERE ID IN (' . join( ',', $next_posts ) . ')'; | |
$posts = $wpdb->get_results( "SELECT * FROM {$wpdb->posts} $where" ); | |
// Begin Loop | |
foreach ( $posts as $post ) { | |
$progress->tick(); | |
setup_postdata( $post ); | |
$is_sticky = is_sticky( $post->ID ) ? 1 : 0; | |
?> | |
<item> | |
<title><?php echo apply_filters( 'the_title_rss', $post->post_title ); ?></title> | |
<link><?php the_permalink_rss() ?></link> | |
<pubDate><?php echo mysql2date( 'D, d M Y H:i:s +0000', get_post_time( 'Y-m-d H:i:s', true ), false ); ?></pubDate> | |
<dc:creator><?php echo get_the_author_meta( 'login' ); ?></dc:creator> | |
<guid isPermaLink="false"><?php esc_url( the_guid() ); ?></guid> | |
<description></description> | |
<content:encoded><?php echo wxr_cdata( apply_filters( 'the_content_export', $post->post_content ) ); ?></content:encoded> | |
<excerpt:encoded><?php echo wxr_cdata( apply_filters( 'the_excerpt_export', $post->post_excerpt ) ); ?></excerpt:encoded> | |
<wp:post_id><?php echo $post->ID; ?></wp:post_id> | |
<wp:post_date><?php echo $post->post_date; ?></wp:post_date> | |
<wp:post_date_gmt><?php echo $post->post_date_gmt; ?></wp:post_date_gmt> | |
<wp:comment_status><?php echo $post->comment_status; ?></wp:comment_status> | |
<wp:ping_status><?php echo $post->ping_status; ?></wp:ping_status> | |
<wp:post_name><?php echo $post->post_name; ?></wp:post_name> | |
<wp:status><?php echo $post->post_status; ?></wp:status> | |
<wp:post_parent><?php echo $post->post_parent; ?></wp:post_parent> | |
<wp:menu_order><?php echo $post->menu_order; ?></wp:menu_order> | |
<wp:post_type><?php echo $post->post_type; ?></wp:post_type> | |
<wp:post_password><?php echo $post->post_password; ?></wp:post_password> | |
<wp:is_sticky><?php echo $is_sticky; ?></wp:is_sticky> | |
<?php if ( $post->post_type == 'attachment' ) : ?> | |
<wp:attachment_url><?php echo wp_get_attachment_url( $post->ID ); ?></wp:attachment_url> | |
<?php endif; ?> | |
<?php wxr_post_taxonomy(); ?> | |
<?php $postmeta = $wpdb->get_results( $wpdb->prepare( "SELECT * FROM $wpdb->postmeta WHERE post_id = %d", $post->ID ) ); | |
foreach ( $postmeta as $meta ) : if ( $meta->meta_key != '_edit_lock' ) : ?> | |
<wp:postmeta> | |
<wp:meta_key><?php echo $meta->meta_key; ?></wp:meta_key> | |
<wp:meta_value><?php echo wxr_cdata( $meta->meta_value ); ?></wp:meta_value> | |
</wp:postmeta> | |
<?php endif; endforeach; ?> | |
<?php if ( false === $args['skip_comments'] ): ?> | |
<?php $comments = $wpdb->get_results( $wpdb->prepare( "SELECT * FROM $wpdb->comments WHERE comment_post_ID = %d AND comment_approved <> 'spam'", $post->ID ) ); | |
foreach ( $comments as $c ) : ?> | |
<wp:comment> | |
<wp:comment_id><?php echo $c->comment_ID; ?></wp:comment_id> | |
<wp:comment_author><?php echo wxr_cdata( $c->comment_author ); ?></wp:comment_author> | |
<wp:comment_author_email><?php echo $c->comment_author_email; ?></wp:comment_author_email> | |
<wp:comment_author_url><?php echo esc_url_raw( $c->comment_author_url ); ?></wp:comment_author_url> | |
<wp:comment_author_IP><?php echo $c->comment_author_IP; ?></wp:comment_author_IP> | |
<wp:comment_date><?php echo $c->comment_date; ?></wp:comment_date> | |
<wp:comment_date_gmt><?php echo $c->comment_date_gmt; ?></wp:comment_date_gmt> | |
<wp:comment_content><?php echo wxr_cdata( $c->comment_content ) ?></wp:comment_content> | |
<wp:comment_approved><?php echo $c->comment_approved; ?></wp:comment_approved> | |
<wp:comment_type><?php echo $c->comment_type; ?></wp:comment_type> | |
<wp:comment_parent><?php echo $c->comment_parent; ?></wp:comment_parent> | |
<wp:comment_user_id><?php echo $c->user_id; ?></wp:comment_user_id> | |
<?php $c_meta = $wpdb->get_results( $wpdb->prepare( "SELECT * FROM $wpdb->commentmeta WHERE comment_id = %d", $c->comment_ID ) ); | |
foreach ( $c_meta as $meta ) : ?> | |
<wp:commentmeta> | |
<wp:meta_key><?php echo $meta->meta_key; ?></wp:meta_key> | |
<wp:meta_value><?php echo wxr_cdata( $meta->meta_value ); ?></wp:meta_value> | |
</wp:commentmeta> | |
<?php endforeach; ?> | |
</wp:comment> | |
<?php endforeach; ?> | |
<?php endif; ?> | |
</item> | |
<?php | |
} | |
} | |
} ?> | |
</channel> | |
</rss> | |
<?php | |
$result = ob_get_clean(); | |
$full_path = $this->wxr_path . $file_name_base . '.wxr'; | |
if ( !file_exists( $full_path ) || is_writeable( $full_path ) ) { | |
WP_CLI::line( 'Writing to ' . $full_path ); | |
file_put_contents( $full_path, $result ); | |
} | |
} | |
/** | |
* Implement progress bar | |
*/ | |
private function progress_bar( $title, $total, $interval = 100 ) { | |
return new \cli\progress\Bar( $title, $total, $interval ); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment