info['ID'] = 'WPEXP';
$this->info['name'] = __( 'XML export', 'backwpup' );
$this->info['description'] = __( 'WordPress XML export', 'backwpup' );
$this->info['URI'] = __( 'https://backwpup.com', 'backwpup' );
$this->info['author'] = 'WP Media';
$this->info['authorURI'] = 'https://wp-media.me';
$this->info['version'] = BackWPup::get_plugin_data( 'Version' );
}
/**
* Whether the job type creates a file.
*
* @return bool
*/
public function creates_file() {
return true;
}
/**
* Returns default options for the job type.
*
* @return array
*/
public function option_defaults() {
return [
'wpexportcontent' => 'all',
'wpexportfilecompression' => '',
'wpexportfile' => sanitize_text_field( get_bloginfo( 'name' ) ) . '.wordpress.%Y-%m-%d',
];
}
/**
* Renders the job type edit tab.
*
* @param int|array $jobid Job ID or list of job IDs.
*/
public function edit_tab( $jobid ) {
?>
steps_data[ $job_object->step_working ]['SAVE_STEP_TRY'] !== $job_object->steps_data[ $job_object->step_working ]['STEP_TRY'] ) {
$job_object->log(
sprintf(
/* translators: %d: attempt number. */
__( '%d. Trying to create a WordPress export to XML file …', 'backwpup' ),
$job_object->steps_data[ $job_object->step_working ]['STEP_TRY']
)
);
$job_object->steps_data[ $job_object->step_working ]['wpexportfile'] = BackWPup::get_plugin_data( 'TEMP' ) . $job_object->generate_filename( $job_object->job['wpexportfile'], 'xml', true );
$job_object->steps_data[ $job_object->step_working ]['substep'] = 'header';
$job_object->steps_data[ $job_object->step_working ]['post_ids'] = [];
$job_object->substeps_todo = 10;
$job_object->substeps_done = 0;
}
add_filter( 'backwpup_wxr_export_skip_postmeta', [ $this, 'wxr_filter_postmeta' ], 10, 2 );
if ( 'header' === $job_object->steps_data[ $job_object->step_working ]['substep'] ) {
$post_status = 'auto-draft';
$post_ids = [];
$cache_group = 'backwpup_wpexport';
if ( 'all' !== $job_object->job['wpexportcontent'] && post_type_exists( $job_object->job['wpexportcontent'] ) ) {
$ptype = get_post_type_object( $job_object->job['wpexportcontent'] );
if ( ! $ptype->can_export ) {
/* translators: %s: post type slug. */
$job_object->log( sprintf( __( 'WP Export: Post type ā%sā does not allow export.', 'backwpup' ), $job_object->job['wpexportcontent'] ), E_USER_ERROR );
return false;
}
$post_ids_key = 'post_ids_' . $job_object->job['wpexportcontent'] . '_' . $post_status;
$post_ids = wp_cache_get( $post_ids_key, $cache_group );
if ( false === $post_ids ) {
$post_ids = $wpdb->get_col( // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery -- No WP API for raw export selection.
$wpdb->prepare(
"SELECT ID FROM {$wpdb->posts} WHERE {$wpdb->posts}.post_type = %s AND {$wpdb->posts}.post_status != %s",
$job_object->job['wpexportcontent'],
$post_status
)
);
wp_cache_set( $post_ids_key, $post_ids, $cache_group, MINUTE_IN_SECONDS );
}
} else {
$post_types = array_values( get_post_types( [ 'can_export' => true ] ) );
$placeholders = implode( ',', array_fill( 0, count( $post_types ), '%s' ) );
$post_ids_key = 'post_ids_' . md5( implode( ',', $post_types ) . '|' . $post_status );
$post_ids = wp_cache_get( $post_ids_key, $cache_group );
if ( false === $post_ids ) {
$post_ids = $wpdb->get_col( // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery -- No WP API for raw export selection.
$wpdb->prepare(
// phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared -- Dynamic IN clause placeholders.
"SELECT ID FROM {$wpdb->posts} WHERE {$wpdb->posts}.post_type IN ({$placeholders}) AND {$wpdb->posts}.post_status != %s",
array_merge( $post_types, [ $post_status ] )
)
);
wp_cache_set( $post_ids_key, $post_ids, $cache_group, MINUTE_IN_SECONDS );
}
$job_object->job['wpexportcontent'] = 'all';
}
// Grab a snapshot of post IDs, just in case it changes during the export.
$job_object->steps_data[ $job_object->step_working ]['post_ids'] = $post_ids;
$job_object->substeps_todo = $job_object->substeps_todo + count( $job_object->steps_data[ $job_object->step_working ]['post_ids'] );
$header = '\n";
$header .= "\n";
$header .= "\n";
$header .= "\n";
$header .= "\n\n";
$header .= "\n";
$header .= "\n";
$header .= "\n";
$header .= "\n";
$header .= "\n";
$header .= "\n";
$header .= "\n";
$header .= "\n";
$header .= "\n";
$header .= "\n";
$header .= "\n\n";
$header .= '\n";
$header .= "\n";
$header .= "\n";
$header .= "\t" . get_bloginfo_rss( 'name' ) . "\n";
$header .= "\t" . get_bloginfo_rss( 'url' ) . "\n";
$header .= "\t" . get_bloginfo_rss( 'description' ) . "\n";
$header .= "\t" . gmdate( 'D, d M Y H:i:s +0000', time() ) . "\n";
$header .= "\t" . get_bloginfo_rss( 'language' ) . "\n";
$header .= "\t" . $wxr_version . "\n";
$header .= "\t" . $this->wxr_site_url() . "\n";
$header .= "\t" . get_bloginfo_rss( 'url' ) . "\n";
// phpcs:ignore WordPress.WP.AlternativeFunctions.file_system_operations_file_put_contents
$written = file_put_contents( $job_object->steps_data[ $job_object->step_working ]['wpexportfile'], $header, FILE_APPEND );
if ( false === $written ) {
$job_object->log( __( 'WP Export file could not written.', 'backwpup' ), E_USER_ERROR );
return false;
}
unset( $header );
$job_object->steps_data[ $job_object->step_working ]['substep'] = 'authors';
++$job_object->substeps_done;
$job_object->update_working_data();
$job_object->do_restart_time();
}
if ( 'authors' === $job_object->steps_data[ $job_object->step_working ]['substep'] ) {
$written = file_put_contents( $job_object->steps_data[ $job_object->step_working ]['wpexportfile'], $this->wxr_authors_list(), FILE_APPEND ); // phpcs:ignore WordPress.WP.AlternativeFunctions.file_system_operations_file_put_contents
if ( false === $written ) {
$job_object->log( __( 'WP Export file could not written.', 'backwpup' ), E_USER_ERROR );
return false;
}
$job_object->steps_data[ $job_object->step_working ]['substep'] = 'cats';
++$job_object->substeps_done;
$job_object->update_working_data();
$job_object->do_restart_time();
}
if ( 'cats' === $job_object->steps_data[ $job_object->step_working ]['substep'] ) {
if ( 'all' === $job_object->job['wpexportcontent'] ) {
$cats = [];
$categories = (array) get_categories( [ 'get' => 'all' ] );
// Put categories in order with no child going before its parent.
while ( ! empty( $categories ) ) {
$cat = array_shift( $categories );
if ( 0 === (int) $cat->parent || isset( $cats[ $cat->parent ] ) ) {
$cats[ $cat->term_id ] = $cat;
} else {
$categories[] = $cat;
}
}
$cats_xml = '';
foreach ( $cats as $c ) {
$parent_slug = $c->parent ? $cats[ $c->parent ]->slug : '';
$cats_xml .= "\t" . $c->term_id . '' . $c->slug . '' . $parent_slug . '' . $this->wxr_cat_name( $c ) . $this->wxr_category_description( $c ) . "\n";
}
$written = file_put_contents( $job_object->steps_data[ $job_object->step_working ]['wpexportfile'], $cats_xml, FILE_APPEND ); // phpcs:ignore WordPress.WP.AlternativeFunctions.file_system_operations_file_put_contents
if ( false === $written ) {
$job_object->log( __( 'WP Export file could not written.', 'backwpup' ), E_USER_ERROR );
return false;
}
unset( $cats_xml );
}
$job_object->steps_data[ $job_object->step_working ]['substep'] = 'tags';
++$job_object->substeps_done;
$job_object->update_working_data();
$job_object->do_restart_time();
}
if ( 'tags' === $job_object->steps_data[ $job_object->step_working ]['substep'] ) {
if ( 'all' === $job_object->job['wpexportcontent'] ) {
$tags = (array) get_tags( [ 'get' => 'all' ] );
$tags_xml = '';
foreach ( $tags as $t ) {
$tags_xml .= "\t" . $t->term_id . '' . $t->slug . '' . $this->wxr_tag_name( $t ) . $this->wxr_tag_description( $t ) . "\n";
}
$written = file_put_contents( $job_object->steps_data[ $job_object->step_working ]['wpexportfile'], $tags_xml, FILE_APPEND ); // phpcs:ignore WordPress.WP.AlternativeFunctions.file_system_operations_file_put_contents
if ( false === $written ) {
$job_object->log( __( 'WP Export file could not written.', 'backwpup' ), E_USER_ERROR );
return false;
}
unset( $tags_xml );
}
$job_object->steps_data[ $job_object->step_working ]['substep'] = 'terms';
++$job_object->substeps_done;
$job_object->update_working_data();
$job_object->do_restart_time();
}
if ( 'terms' === $job_object->steps_data[ $job_object->step_working ]['substep'] ) {
if ( 'all' === $job_object->job['wpexportcontent'] ) {
$terms = [];
$custom_taxonomies = get_taxonomies( [ '_builtin' => false ] );
$custom_terms = (array) get_terms(
[
'taxonomy' => $custom_taxonomies,
'hide_empty' => false,
]
);
// Put terms in order with no child going before its parent.
while ( ! empty( $custom_terms ) ) {
$t = array_shift( $custom_terms );
if ( 0 === (int) $t->parent || isset( $terms[ $t->parent ] ) ) {
$terms[ $t->term_id ] = $t;
} else {
$custom_terms[] = $t;
}
}
$terms_xml = '';
foreach ( $terms as $t ) {
$parent_slug = $t->parent ? $terms[ $t->parent ]->slug : '';
$terms_xml .= "\t" . $t->term_id . '' . $t->taxonomy . '' . $t->slug . '' . $parent_slug . '' . $this->wxr_term_name( $t ) . $this->wxr_term_description( $t ) . "\n";
}
$written = file_put_contents( $job_object->steps_data[ $job_object->step_working ]['wpexportfile'], $terms_xml, FILE_APPEND ); // phpcs:ignore WordPress.WP.AlternativeFunctions.file_system_operations_file_put_contents
if ( false === $written ) {
$job_object->log( __( 'WP Export file could not written.', 'backwpup' ), E_USER_ERROR );
return false;
}
unset( $terms_xml );
}
$job_object->steps_data[ $job_object->step_working ]['substep'] = 'menus';
++$job_object->substeps_done;
$job_object->update_working_data();
$job_object->do_restart_time();
}
if ( 'menus' === $job_object->steps_data[ $job_object->step_working ]['substep'] ) {
$menu_xml = '';
if ( 'all' === $job_object->job['wpexportcontent'] ) {
$menu_xml .= $this->wxr_nav_menu_terms();
}
$menu_xml .= "\thttp://wordpress.org/?v=" . get_bloginfo_rss( 'version' ) . "\n";
$written = file_put_contents( $job_object->steps_data[ $job_object->step_working ]['wpexportfile'], $menu_xml, FILE_APPEND ); // phpcs:ignore WordPress.WP.AlternativeFunctions.file_system_operations_file_put_contents
if ( false === $written ) {
$job_object->log( __( 'WP Export file could not written.', 'backwpup' ), E_USER_ERROR );
return false;
}
unset( $menu_xml );
$job_object->steps_data[ $job_object->step_working ]['substep'] = 'posts';
++$job_object->substeps_done;
$job_object->update_working_data();
$job_object->do_restart_time();
}
if ( 'posts' === $job_object->steps_data[ $job_object->step_working ]['substep'] ) {
if ( ! empty( $job_object->steps_data[ $job_object->step_working ]['post_ids'] ) ) {
$cache_group = 'backwpup_wpexport';
$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 ( ! empty( $job_object->steps_data[ $job_object->step_working ]['post_ids'] ) ) {
$next_posts = array_splice( $job_object->steps_data[ $job_object->step_working ]['post_ids'], 0, 20 );
$next_posts = array_map( 'intval', $next_posts );
$placeholders = implode( ',', array_fill( 0, count( $next_posts ), '%d' ) );
$posts_key = 'post_chunk_' . md5( implode( ',', $next_posts ) );
$posts = wp_cache_get( $posts_key, $cache_group );
if ( false === $posts ) {
$posts = $wpdb->get_results( // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery -- No WP API for raw export selection.
$wpdb->prepare(
// phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared, WordPress.DB.PreparedSQLPlaceholders.UnfinishedPrepare -- Dynamic IN clause placeholders.
"SELECT * FROM {$wpdb->posts} WHERE ID IN ({$placeholders})",
$next_posts
)
);
wp_cache_set( $posts_key, $posts, $cache_group, MINUTE_IN_SECONDS );
}
$wxr_post = '';
// Begin loop.
/* @var WP_Post $post_item */
foreach ( $posts as $post_item ) {
setup_postdata( $post_item );
$is_sticky = is_sticky( $post_item->ID ) ? 1 : 0;
$wxr_post .= "\t- \n";
$wxr_post .= "\t\t" . wpm_apply_filters_typed( 'string', 'the_title_rss', $post_item->post_title ) . "\n";
$wxr_post .= "\t\t" . esc_url( wpm_apply_filters_typed( 'string', 'the_permalink_rss', get_permalink( $post_item ) ) ) . "\n";
$wxr_post .= "\t\t" . mysql2date( 'D, d M Y H:i:s +0000', get_post_time( 'Y-m-d H:i:s', true, $post_item ), false ) . "\n";
$wxr_post .= "\t\t" . $this->wxr_cdata( get_the_author_meta( 'login', $post_item->post_author ) ) . "\n";
$wxr_post .= "\t\t" . esc_url( get_the_guid( $post_item->ID ) ) . "\n";
$wxr_post .= "\t\t\n";
$wxr_post .= "\t\t" . $this->wxr_cdata( wpm_apply_filters_typed( 'string', 'the_content_export', $post_item->post_content ) ) . "\n";
$wxr_post .= "\t\t" . $this->wxr_cdata( wpm_apply_filters_typed( 'string', 'the_excerpt_export', $post_item->post_excerpt ) ) . "\n";
$wxr_post .= "\t\t" . $post_item->ID . "\n";
$wxr_post .= "\t\t" . $post_item->post_date . "\n";
$wxr_post .= "\t\t" . $post_item->post_date_gmt . "\n";
$wxr_post .= "\t\t" . $post_item->comment_status . "\n";
$wxr_post .= "\t\t" . $post_item->ping_status . "\n";
$wxr_post .= "\t\t" . $post_item->post_name . "\n";
$wxr_post .= "\t\t" . $post_item->post_status . "\n";
$wxr_post .= "\t\t" . $post_item->post_parent . "\n";
$wxr_post .= "\t\t" . $post_item->menu_order . "\n";
$wxr_post .= "\t\t" . $post_item->post_type . "\n";
$wxr_post .= "\t\t" . $post_item->post_password . "\n";
$wxr_post .= "\t\t" . $is_sticky . "\n";
if ( 'attachment' === $post_item->post_type ) {
$wxr_post .= "\t\t" . wp_get_attachment_url( $post_item->ID ) . "\n";
}
$wxr_post .= $this->wxr_post_taxonomy();
$postmeta_key = 'postmeta_' . $post_item->ID;
$postmeta = wp_cache_get( $postmeta_key, $cache_group );
if ( false === $postmeta ) {
$postmeta = $wpdb->get_results( $wpdb->prepare( "SELECT * FROM {$wpdb->postmeta} WHERE post_id = %d", $post_item->ID ) ); // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery -- No WP API for raw postmeta export.
wp_cache_set( $postmeta_key, $postmeta, $cache_group, MINUTE_IN_SECONDS );
}
foreach ( $postmeta as $meta ) {
if ( wpm_apply_filters_typed( 'boolean', 'backwpup_wxr_export_skip_postmeta', false, $meta->meta_key, $meta ) ) {
continue;
}
$wxr_post .= "\t\t\n\t\t\t" . $meta->meta_key . "\n\t\t\t" . $this->wxr_cdata( $meta->meta_value ) . "\n\t\t\n";
}
$comments_key = 'comments_' . $post_item->ID;
$comments = wp_cache_get( $comments_key, $cache_group );
if ( false === $comments ) {
$comments = $wpdb->get_results( $wpdb->prepare( "SELECT * FROM {$wpdb->comments} WHERE comment_post_ID = %d AND comment_approved <> 'spam'", $post_item->ID ) ); // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery -- No WP API for raw comment export.
wp_cache_set( $comments_key, $comments, $cache_group, MINUTE_IN_SECONDS );
}
foreach ( $comments as $c ) {
$wxr_post .= "\t\t\n";
$wxr_post .= "\t\t\t" . $c->comment_ID . "\n";
$wxr_post .= "\t\t\t" . $this->wxr_cdata( $c->comment_author ) . "\n";
$wxr_post .= "\t\t\t" . $c->comment_author_email . "\n";
$wxr_post .= "\t\t\t" . esc_url_raw( $c->comment_author_url ) . "\n";
$wxr_post .= "\t\t\t" . $c->comment_author_IP . "\n";
$wxr_post .= "\t\t\t" . $c->comment_date . "\n";
$wxr_post .= "\t\t\t" . $c->comment_date_gmt . "\n";
$wxr_post .= "\t\t\t" . $this->wxr_cdata( $c->comment_content ) . "\n";
$wxr_post .= "\t\t\t" . $c->comment_approved . "\n";
$wxr_post .= "\t\t\t" . $c->comment_type . "\n";
$wxr_post .= "\t\t\t" . $c->comment_parent . "\n";
$wxr_post .= "\t\t\t" . $c->user_id . "\n";
$commentmeta_key = 'commentmeta_' . $c->comment_ID;
$c_meta = wp_cache_get( $commentmeta_key, $cache_group );
if ( false === $c_meta ) {
$c_meta = $wpdb->get_results( $wpdb->prepare( "SELECT * FROM {$wpdb->commentmeta} WHERE comment_id = %d", $c->comment_ID ) ); // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery -- No WP API for raw commentmeta export.
wp_cache_set( $commentmeta_key, $c_meta, $cache_group, MINUTE_IN_SECONDS );
}
foreach ( $c_meta as $meta ) {
$wxr_post .= "\t\t\t\n\t\t\t\t" . $meta->meta_key . "\n\t\t\t\t" . $this->wxr_cdata( $meta->meta_value ) . "\n\t\t\t\n";
}
$wxr_post .= "\t\t\n";
}
$wxr_post .= "\t
\n";
++$job_object->substeps_done;
}
wp_reset_postdata();
$written = file_put_contents( $job_object->steps_data[ $job_object->step_working ]['wpexportfile'], $wxr_post, FILE_APPEND ); // phpcs:ignore WordPress.WP.AlternativeFunctions.file_system_operations_file_put_contents
if ( false === $written ) {
$job_object->log( __( 'WP Export file could not written.', 'backwpup' ), E_USER_ERROR );
return false;
}
$job_object->do_restart_time();
}
}
$written = file_put_contents( $job_object->steps_data[ $job_object->step_working ]['wpexportfile'], "\n", FILE_APPEND ); // phpcs:ignore WordPress.WP.AlternativeFunctions.file_system_operations_file_put_contents
if ( false === $written ) {
$job_object->log( __( 'WP Export file could not written.', 'backwpup' ), E_USER_ERROR );
return false;
}
$job_object->steps_data[ $job_object->step_working ]['substep'] = 'check';
++$job_object->substeps_done;
$job_object->update_working_data();
$job_object->do_restart_time();
}
remove_filter( 'backwpup_wxr_export_skip_postmeta', [ $this, 'wxr_filter_postmeta' ], 10 );
if ( 'check' === $job_object->steps_data[ $job_object->step_working ]['substep'] ) {
if ( class_exists( \DOMDocument::class ) ) {
$job_object->log( __( 'Check WP Export file …', 'backwpup' ) );
$job_object->need_free_memory( filesize( $job_object->steps_data[ $job_object->step_working ]['wpexportfile'] ) * 2 );
try {
$validator = new WxrValidator( $job_object->steps_data[ $job_object->step_working ]['wpexportfile'] );
$validator->validateWxr();
$job_object->log( __( 'WP Export file is a valid WXR file.', 'backwpup' ) );
} catch ( InvalidXmlException $e ) {
$errors = $e->getErrors();
foreach ( $errors as $error ) {
switch ( $error->level ) {
case LIBXML_ERR_WARNING:
$job_object->log(
E_USER_WARNING,
sprintf(
// translators: 1: XML error code. 2: XML error message.
__( 'XML WARNING (%1$s): %2$s', 'backwpup' ),
$error->code,
trim( $error->message )
),
$job_object->steps_data[ $job_object->step_working ]['wpexportfile'],
$error->line
);
break;
case LIBXML_ERR_ERROR:
$job_object->log(
E_USER_WARNING,
sprintf(
// translators: 1: XML error code. 2: XML error message.
__( 'XML RECOVERABLE (%1$s): %2$s', 'backwpup' ),
$error->code,
trim( $error->message )
),
$job_object->steps_data[ $job_object->step_working ]['wpexportfile'],
$error->line
);
break;
case LIBXML_ERR_FATAL:
$job_object->log(
E_USER_WARNING,
sprintf(
// translators: 1: XML error code. 2: XML error message.
__( 'XML ERROR (%1$s): %2$s', 'backwpup' ),
$error->code,
trim( $error->message )
),
$job_object->steps_data[ $job_object->step_working ]['wpexportfile'],
$error->line
);
break;
}
}
} catch ( InvalidWxrFileException $e ) {
$job_object->log( $e->getMessage(), E_USER_ERROR );
}
} else {
$job_object->log( __( 'WP Export file can not be checked, because no XML extension is loaded, to ensure the file verification.', 'backwpup' ) );
}
$job_object->steps_data[ $job_object->step_working ]['substep'] = 'compress';
++$job_object->substeps_done;
$job_object->update_working_data();
$job_object->do_restart_time();
}
// Compress file.
if ( 'compress' === $job_object->steps_data[ $job_object->step_working ]['substep'] ) {
if ( ! empty( $job_object->job['wpexportfilecompression'] ) ) {
$job_object->log( __( 'Compressing file …', 'backwpup' ) );
try {
$compress = new BackWPup_Create_Archive( $job_object->steps_data[ $job_object->step_working ]['wpexportfile'] . $job_object->job['wpexportfilecompression'] );
if ( $compress->add_file( $job_object->steps_data[ $job_object->step_working ]['wpexportfile'] ) ) {
unset( $compress );
wp_delete_file( $job_object->steps_data[ $job_object->step_working ]['wpexportfile'] );
$job_object->steps_data[ $job_object->step_working ]['wpexportfile'] .= $job_object->job['wpexportfilecompression'];
$job_object->log( __( 'Compressing done.', 'backwpup' ) );
}
} catch ( Exception $e ) {
$job_object->log( $e->getMessage(), E_USER_ERROR, $e->getFile(), $e->getLine() );
return false;
}
}
$job_object->steps_data[ $job_object->step_working ]['substep'] = 'addfile';
++$job_object->substeps_done;
$job_object->update_working_data();
$job_object->do_restart_time();
}
if ( 'addfile' === $job_object->steps_data[ $job_object->step_working ]['substep'] ) {
// Add XML file to backup files.
if ( is_readable( $job_object->steps_data[ $job_object->step_working ]['wpexportfile'] ) ) {
$job_object->additional_files_to_backup[] = $job_object->steps_data[ $job_object->step_working ]['wpexportfile'];
$filesize = filesize( $job_object->steps_data[ $job_object->step_working ]['wpexportfile'] );
/* translators: 1: XML export filename, 2: XML export file size. */
$job_object->log( sprintf( __( 'Added XML export "%1$s" with %2$s to backup file list.', 'backwpup' ), basename( (string) $job_object->steps_data[ $job_object->step_working ]['wpexportfile'] ), size_format( $filesize, 2 ) ) );
}
++$job_object->substeps_done;
$job_object->update_working_data();
}
return true;
}
/**
* Wrap given string in XML CDATA tag.
*
* @since WordPress 2.1.0
*
* @param string $str String to wrap in XML CDATA tag.
*
* @return string
*/
private function wxr_cdata( $str ) {
$str = (string) $str;
// Use wp_is_valid_utf8() if available (WP 6.9+), otherwise fall back to seems_utf8().
if ( function_exists( 'wp_is_valid_utf8' ) ) {
$is_valid_utf8 = wp_is_valid_utf8( $str );
} else {
$is_valid_utf8 = seems_utf8( $str ); // phpcs:ignore WordPress.WP.DeprecatedFunctions.seems_utf8Found
}
if ( ! $is_valid_utf8 ) {
$str = utf8_encode( $str );
}
// Not allowed UTF-8 chars in XML.
$str = preg_replace( '/[^\x{0009}\x{000a}\x{000d}\x{0020}-\x{D7FF}\x{E000}-\x{FFFD}]+/u', '', $str );
// $str = ent2ncr( esc_html( $str ) );
return '', ']]]]>', $str ) . ']]>';
}
/**
* Return the URL of the site.
*
* @since WordPress 2.5.0
*
* @return string Site URL.
*/
private function wxr_site_url() {
// MS: the base URL.
if ( is_multisite() ) {
return network_home_url();
}
// WP: the blog URL.
return get_bloginfo_rss( 'url' );
}
/**
* Output a cat_name XML tag from a given category object.
*
* @since WordPress 2.1.0
*
* @param object $category Category object.
*
* @return string
*/
private function wxr_cat_name( $category ) {
if ( empty( $category->name ) ) {
return '';
}
return '' . $this->wxr_cdata( $category->name ) . '';
}
/**
* Output a category_description XML tag from a given category object.
*
* @since WordPress 2.1.0
*
* @param object $category Category object.
*
* @return string
*/
private function wxr_category_description( $category ) {
if ( empty( $category->description ) ) {
return '';
}
return '' . $this->wxr_cdata( $category->description ) . '';
}
/**
* Output a tag_name XML tag from a given tag object.
*
* @since WordPress 2.3.0
*
* @param object $tag Tag object.
*
* @return string
*/
private function wxr_tag_name( $tag ) {
if ( empty( $tag->name ) ) {
return '';
}
return '' . $this->wxr_cdata( $tag->name ) . '';
}
/**
* Output a tag_description XML tag from a given tag object.
*
* @since WordPress 2.3.0
*
* @param object $tag Tag object.
*
* @return string
*/
private function wxr_tag_description( $tag ) {
if ( empty( $tag->description ) ) {
return '';
}
return '' . $this->wxr_cdata( $tag->description ) . '';
}
/**
* Output a term_name XML tag from a given term object.
*
* @since WordPress 2.9.0
*
* @param object $term Term object.
*
* @return string
*/
private function wxr_term_name( $term ) {
if ( empty( $term->name ) ) {
return '';
}
return '' . $this->wxr_cdata( $term->name ) . '';
}
/**
* Output a term_description XML tag from a given term object.
*
* @since WordPress 2.9.0
*
* @param object $term Term object.
*
* @return string
*/
private function wxr_term_description( $term ) {
if ( empty( $term->description ) ) {
return '';
}
return '' . $this->wxr_cdata( $term->description ) . '';
}
/**
* Output list of authors with posts.
*
* @since WordPress 3.1.0
*
* @return string
*/
private function wxr_authors_list() {
global $wpdb;
$authors = [];
$cache_group = 'backwpup_wpexport';
$authors_key = 'authors_' . DB_NAME;
$results = wp_cache_get( $authors_key, $cache_group );
if ( false === $results ) {
$results = $wpdb->get_results( // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery -- No WP API for raw author export.
$wpdb->prepare( "SELECT DISTINCT post_author FROM {$wpdb->posts} WHERE post_status != %s", 'auto-draft' )
);
wp_cache_set( $authors_key, $results, $cache_group, MINUTE_IN_SECONDS );
}
foreach ( (array) $results as $result ) {
$authors[] = get_userdata( $result->post_author );
}
$authors = array_filter( $authors );
$wxr_authors = '';
foreach ( $authors as $author ) {
$wxr_authors .= "\t";
$wxr_authors .= '' . $author->ID . '';
$wxr_authors .= '' . $author->user_login . '';
$wxr_authors .= '' . $author->user_email . '';
$wxr_authors .= '' . $this->wxr_cdata( $author->display_name ) . '';
$wxr_authors .= '' . $this->wxr_cdata( $author->user_firstname ) . '';
$wxr_authors .= '' . $this->wxr_cdata( $author->user_lastname ) . '';
$wxr_authors .= "\n";
}
return $wxr_authors;
}
/**
* Ouput all navigation menu terms.
*
* @since WordPress 3.1.0
*/
private function wxr_nav_menu_terms() {
$nav_menus = wp_get_nav_menus();
if ( empty( $nav_menus ) || ! is_array( $nav_menus ) ) {
return '';
}
$wxr_nav_meuns = '';
foreach ( $nav_menus as $menu ) {
$wxr_nav_meuns .= "\t{$menu->term_id}nav_menu{$menu->slug}";
$wxr_nav_meuns .= $this->wxr_term_name( $menu );
$wxr_nav_meuns .= "\n";
}
return $wxr_nav_meuns;
}
/**
* Output list of taxonomy terms, in XML tag format, associated with a post.
*
* @since WordPress 2.3.0
*/
private function wxr_post_taxonomy() {
$post = get_post();
if ( ! $post instanceof WP_Post ) {
return '';
}
$taxonomies = get_object_taxonomies( $post->post_type );
if ( empty( $taxonomies ) ) {
return '';
}
$terms = wp_get_object_terms( $post->ID, $taxonomies );
$wxr_post_tags = '';
foreach ( (array) $terms as $term ) {
$wxr_post_tags .= "\t\ttaxonomy}\" nicename=\"{$term->slug}\">" . $this->wxr_cdata( $term->name ) . "\n";
}
return $wxr_post_tags;
}
/**
* Filter postmeta keys that should be skipped during WXR export.
*
* @param bool $return_me Whether to skip the meta key.
* @param string $meta_key Meta key name.
*
* @return bool
*/
public function wxr_filter_postmeta( $return_me, $meta_key ) {
if ( '_edit_lock' === $meta_key ) {
$return_me = true;
}
return $return_me;
}
}