14 * @since 2.5.0 |
14 * @since 2.5.0 |
15 */ |
15 */ |
16 define( 'WXR_VERSION', '1.2' ); |
16 define( 'WXR_VERSION', '1.2' ); |
17 |
17 |
18 /** |
18 /** |
19 * Generates the WXR export file for download |
19 * Generates the WXR export file for download. |
20 * |
20 * |
21 * @since 2.1.0 |
21 * @since 2.1.0 |
22 * |
22 * |
23 * @param array $args Filters defining what should be included in the export |
23 * @param array $args Filters defining what should be included in the export. |
24 */ |
24 */ |
25 function export_wp( $args = array() ) { |
25 function export_wp( $args = array() ) { |
26 global $wpdb, $post; |
26 global $wpdb, $post; |
27 |
27 |
28 $defaults = array( 'content' => 'all', 'author' => false, 'category' => false, |
28 $defaults = array( 'content' => 'all', 'author' => false, 'category' => false, |
29 'start_date' => false, 'end_date' => false, 'status' => false, |
29 'start_date' => false, 'end_date' => false, 'status' => false, |
30 ); |
30 ); |
31 $args = wp_parse_args( $args, $defaults ); |
31 $args = wp_parse_args( $args, $defaults ); |
32 |
32 |
33 do_action( 'export_wp' ); |
33 /** |
|
34 * Fires at the beginning of an export, before any headers are sent. |
|
35 * |
|
36 * @since 2.3.0 |
|
37 * |
|
38 * @param array $args An array of export arguments. |
|
39 */ |
|
40 do_action( 'export_wp', $args ); |
34 |
41 |
35 $sitename = sanitize_key( get_bloginfo( 'name' ) ); |
42 $sitename = sanitize_key( get_bloginfo( 'name' ) ); |
36 if ( ! empty($sitename) ) $sitename .= '.'; |
43 if ( ! empty($sitename) ) $sitename .= '.'; |
37 $filename = $sitename . 'wordpress.' . date( 'Y-m-d' ) . '.xml'; |
44 $filename = $sitename . 'wordpress.' . date( 'Y-m-d' ) . '.xml'; |
38 |
45 |
74 |
81 |
75 if ( $args['end_date'] ) |
82 if ( $args['end_date'] ) |
76 $where .= $wpdb->prepare( " AND {$wpdb->posts}.post_date < %s", date( 'Y-m-d', strtotime('+1 month', strtotime($args['end_date'])) ) ); |
83 $where .= $wpdb->prepare( " AND {$wpdb->posts}.post_date < %s", date( 'Y-m-d', strtotime('+1 month', strtotime($args['end_date'])) ) ); |
77 } |
84 } |
78 |
85 |
79 // grab a snapshot of post IDs, just in case it changes during the export |
86 // Grab a snapshot of post IDs, just in case it changes during the export. |
80 $post_ids = $wpdb->get_col( "SELECT ID FROM {$wpdb->posts} $join WHERE $where" ); |
87 $post_ids = $wpdb->get_col( "SELECT ID FROM {$wpdb->posts} $join WHERE $where" ); |
81 |
88 |
82 // get the requested terms ready, empty unless posts filtered by category or all content |
89 /* |
|
90 * Get the requested terms ready, empty unless posts filtered by category |
|
91 * or all content. |
|
92 */ |
83 $cats = $tags = $terms = array(); |
93 $cats = $tags = $terms = array(); |
84 if ( isset( $term ) && $term ) { |
94 if ( isset( $term ) && $term ) { |
85 $cat = get_term( $term['term_id'], 'category' ); |
95 $cat = get_term( $term['term_id'], 'category' ); |
86 $cats = array( $cat->term_id => $cat ); |
96 $cats = array( $cat->term_id => $cat ); |
87 unset( $term, $cat ); |
97 unset( $term, $cat ); |
88 } else if ( 'all' == $args['content'] ) { |
98 } elseif ( 'all' == $args['content'] ) { |
89 $categories = (array) get_categories( array( 'get' => 'all' ) ); |
99 $categories = (array) get_categories( array( 'get' => 'all' ) ); |
90 $tags = (array) get_tags( array( 'get' => 'all' ) ); |
100 $tags = (array) get_tags( array( 'get' => 'all' ) ); |
91 |
101 |
92 $custom_taxonomies = get_taxonomies( array( '_builtin' => false ) ); |
102 $custom_taxonomies = get_taxonomies( array( '_builtin' => false ) ); |
93 $custom_terms = (array) get_terms( $custom_taxonomies, array( 'get' => 'all' ) ); |
103 $custom_terms = (array) get_terms( $custom_taxonomies, array( 'get' => 'all' ) ); |
94 |
104 |
95 // put categories in order with no child going before its parent |
105 // Put categories in order with no child going before its parent. |
96 while ( $cat = array_shift( $categories ) ) { |
106 while ( $cat = array_shift( $categories ) ) { |
97 if ( $cat->parent == 0 || isset( $cats[$cat->parent] ) ) |
107 if ( $cat->parent == 0 || isset( $cats[$cat->parent] ) ) |
98 $cats[$cat->term_id] = $cat; |
108 $cats[$cat->term_id] = $cat; |
99 else |
109 else |
100 $categories[] = $cat; |
110 $categories[] = $cat; |
101 } |
111 } |
102 |
112 |
103 // put terms in order with no child going before its parent |
113 // Put terms in order with no child going before its parent. |
104 while ( $t = array_shift( $custom_terms ) ) { |
114 while ( $t = array_shift( $custom_terms ) ) { |
105 if ( $t->parent == 0 || isset( $terms[$t->parent] ) ) |
115 if ( $t->parent == 0 || isset( $terms[$t->parent] ) ) |
106 $terms[$t->term_id] = $t; |
116 $terms[$t->term_id] = $t; |
107 else |
117 else |
108 $custom_terms[] = $t; |
118 $custom_terms[] = $t; |
231 |
241 |
232 /** |
242 /** |
233 * Output list of authors with posts |
243 * Output list of authors with posts |
234 * |
244 * |
235 * @since 3.1.0 |
245 * @since 3.1.0 |
236 */ |
246 * |
237 function wxr_authors_list() { |
247 * @param array $post_ids Array of post IDs to filter the query by. Optional. |
|
248 */ |
|
249 function wxr_authors_list( array $post_ids = null ) { |
238 global $wpdb; |
250 global $wpdb; |
239 |
251 |
|
252 if ( !empty( $post_ids ) ) { |
|
253 $post_ids = array_map( 'absint', $post_ids ); |
|
254 $and = 'AND ID IN ( ' . implode( ', ', $post_ids ) . ')'; |
|
255 } else { |
|
256 $and = ''; |
|
257 } |
|
258 |
240 $authors = array(); |
259 $authors = array(); |
241 $results = $wpdb->get_results( "SELECT DISTINCT post_author FROM $wpdb->posts WHERE post_status != 'auto-draft'" ); |
260 $results = $wpdb->get_results( "SELECT DISTINCT post_author FROM $wpdb->posts WHERE post_status != 'auto-draft' $and" ); |
242 foreach ( (array) $results as $result ) |
261 foreach ( (array) $results as $result ) |
243 $authors[] = get_userdata( $result->post_author ); |
262 $authors[] = get_userdata( $result->post_author ); |
244 |
263 |
245 $authors = array_filter( $authors ); |
264 $authors = array_filter( $authors ); |
246 |
265 |
335 <language><?php bloginfo_rss( 'language' ); ?></language> |
354 <language><?php bloginfo_rss( 'language' ); ?></language> |
336 <wp:wxr_version><?php echo WXR_VERSION; ?></wp:wxr_version> |
355 <wp:wxr_version><?php echo WXR_VERSION; ?></wp:wxr_version> |
337 <wp:base_site_url><?php echo wxr_site_url(); ?></wp:base_site_url> |
356 <wp:base_site_url><?php echo wxr_site_url(); ?></wp:base_site_url> |
338 <wp:base_blog_url><?php bloginfo_rss( 'url' ); ?></wp:base_blog_url> |
357 <wp:base_blog_url><?php bloginfo_rss( 'url' ); ?></wp:base_blog_url> |
339 |
358 |
340 <?php wxr_authors_list(); ?> |
359 <?php wxr_authors_list( $post_ids ); ?> |
341 |
360 |
342 <?php foreach ( $cats as $c ) : ?> |
361 <?php foreach ( $cats as $c ) : ?> |
343 <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> |
362 <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> |
344 <?php endforeach; ?> |
363 <?php endforeach; ?> |
345 <?php foreach ( $tags as $t ) : ?> |
364 <?php foreach ( $tags as $t ) : ?> |
348 <?php foreach ( $terms as $t ) : ?> |
367 <?php foreach ( $terms as $t ) : ?> |
349 <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> |
368 <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> |
350 <?php endforeach; ?> |
369 <?php endforeach; ?> |
351 <?php if ( 'all' == $args['content'] ) wxr_nav_menu_terms(); ?> |
370 <?php if ( 'all' == $args['content'] ) wxr_nav_menu_terms(); ?> |
352 |
371 |
353 <?php do_action( 'rss2_head' ); ?> |
372 <?php |
|
373 /** This action is documented in wp-includes/feed-rss2.php */ |
|
374 do_action( 'rss2_head' ); |
|
375 ?> |
354 |
376 |
355 <?php if ( $post_ids ) { |
377 <?php if ( $post_ids ) { |
356 global $wp_query; |
378 global $wp_query; |
357 $wp_query->in_the_loop = true; // Fake being in the loop. |
379 |
358 |
380 // Fake being in the loop. |
359 // fetch 20 posts at a time rather than loading the entire table into memory |
381 $wp_query->in_the_loop = true; |
|
382 |
|
383 // Fetch 20 posts at a time rather than loading the entire table into memory. |
360 while ( $next_posts = array_splice( $post_ids, 0, 20 ) ) { |
384 while ( $next_posts = array_splice( $post_ids, 0, 20 ) ) { |
361 $where = 'WHERE ID IN (' . join( ',', $next_posts ) . ')'; |
385 $where = 'WHERE ID IN (' . join( ',', $next_posts ) . ')'; |
362 $posts = $wpdb->get_results( "SELECT * FROM {$wpdb->posts} $where" ); |
386 $posts = $wpdb->get_results( "SELECT * FROM {$wpdb->posts} $where" ); |
363 |
387 |
364 // Begin Loop |
388 // Begin Loop. |
365 foreach ( $posts as $post ) { |
389 foreach ( $posts as $post ) { |
366 setup_postdata( $post ); |
390 setup_postdata( $post ); |
367 $is_sticky = is_sticky( $post->ID ) ? 1 : 0; |
391 $is_sticky = is_sticky( $post->ID ) ? 1 : 0; |
368 ?> |
392 ?> |
369 <item> |
393 <item> |
370 <?php /** This filter is documented in wp-includes/feed.php */ ?> |
394 <title><?php |
371 <title><?php echo apply_filters( 'the_title_rss', $post->post_title ); ?></title> |
395 /** This filter is documented in wp-includes/feed.php */ |
|
396 echo apply_filters( 'the_title_rss', $post->post_title ); |
|
397 ?></title> |
372 <link><?php the_permalink_rss() ?></link> |
398 <link><?php the_permalink_rss() ?></link> |
373 <pubDate><?php echo mysql2date( 'D, d M Y H:i:s +0000', get_post_time( 'Y-m-d H:i:s', true ), false ); ?></pubDate> |
399 <pubDate><?php echo mysql2date( 'D, d M Y H:i:s +0000', get_post_time( 'Y-m-d H:i:s', true ), false ); ?></pubDate> |
374 <dc:creator><?php echo wxr_cdata( get_the_author_meta( 'login' ) ); ?></dc:creator> |
400 <dc:creator><?php echo wxr_cdata( get_the_author_meta( 'login' ) ); ?></dc:creator> |
375 <guid isPermaLink="false"><?php the_guid(); ?></guid> |
401 <guid isPermaLink="false"><?php the_guid(); ?></guid> |
376 <description></description> |
402 <description></description> |
377 <content:encoded><?php echo wxr_cdata( apply_filters( 'the_content_export', $post->post_content ) ); ?></content:encoded> |
403 <content:encoded><?php |
378 <excerpt:encoded><?php echo wxr_cdata( apply_filters( 'the_excerpt_export', $post->post_excerpt ) ); ?></excerpt:encoded> |
404 /** |
|
405 * Filter the post content used for WXR exports. |
|
406 * |
|
407 * @since 2.5.0 |
|
408 * |
|
409 * @param string $post_content Content of the current post. |
|
410 */ |
|
411 echo wxr_cdata( apply_filters( 'the_content_export', $post->post_content ) ); |
|
412 ?></content:encoded> |
|
413 <excerpt:encoded><?php |
|
414 /** |
|
415 * Filter the post excerpt used for WXR exports. |
|
416 * |
|
417 * @since 2.6.0 |
|
418 * |
|
419 * @param string $post_excerpt Excerpt for the current post. |
|
420 */ |
|
421 echo wxr_cdata( apply_filters( 'the_excerpt_export', $post->post_excerpt ) ); |
|
422 ?></excerpt:encoded> |
379 <wp:post_id><?php echo $post->ID; ?></wp:post_id> |
423 <wp:post_id><?php echo $post->ID; ?></wp:post_id> |
380 <wp:post_date><?php echo $post->post_date; ?></wp:post_date> |
424 <wp:post_date><?php echo $post->post_date; ?></wp:post_date> |
381 <wp:post_date_gmt><?php echo $post->post_date_gmt; ?></wp:post_date_gmt> |
425 <wp:post_date_gmt><?php echo $post->post_date_gmt; ?></wp:post_date_gmt> |
382 <wp:comment_status><?php echo $post->comment_status; ?></wp:comment_status> |
426 <wp:comment_status><?php echo $post->comment_status; ?></wp:comment_status> |
383 <wp:ping_status><?php echo $post->ping_status; ?></wp:ping_status> |
427 <wp:ping_status><?php echo $post->ping_status; ?></wp:ping_status> |
392 <wp:attachment_url><?php echo wp_get_attachment_url( $post->ID ); ?></wp:attachment_url> |
436 <wp:attachment_url><?php echo wp_get_attachment_url( $post->ID ); ?></wp:attachment_url> |
393 <?php endif; ?> |
437 <?php endif; ?> |
394 <?php wxr_post_taxonomy(); ?> |
438 <?php wxr_post_taxonomy(); ?> |
395 <?php $postmeta = $wpdb->get_results( $wpdb->prepare( "SELECT * FROM $wpdb->postmeta WHERE post_id = %d", $post->ID ) ); |
439 <?php $postmeta = $wpdb->get_results( $wpdb->prepare( "SELECT * FROM $wpdb->postmeta WHERE post_id = %d", $post->ID ) ); |
396 foreach ( $postmeta as $meta ) : |
440 foreach ( $postmeta as $meta ) : |
|
441 /** |
|
442 * Filter whether to selectively skip post meta used for WXR exports. |
|
443 * |
|
444 * Returning a truthy value to the filter will skip the current meta |
|
445 * object from being exported. |
|
446 * |
|
447 * @since 3.3.0 |
|
448 * |
|
449 * @param bool $skip Whether to skip the current post meta. Default false. |
|
450 * @param string $meta_key Current meta key. |
|
451 * @param object $meta Current meta object. |
|
452 */ |
397 if ( apply_filters( 'wxr_export_skip_postmeta', false, $meta->meta_key, $meta ) ) |
453 if ( apply_filters( 'wxr_export_skip_postmeta', false, $meta->meta_key, $meta ) ) |
398 continue; |
454 continue; |
399 ?> |
455 ?> |
400 <wp:postmeta> |
456 <wp:postmeta> |
401 <wp:meta_key><?php echo $meta->meta_key; ?></wp:meta_key> |
457 <wp:meta_key><?php echo $meta->meta_key; ?></wp:meta_key> |
402 <wp:meta_value><?php echo wxr_cdata( $meta->meta_value ); ?></wp:meta_value> |
458 <wp:meta_value><?php echo wxr_cdata( $meta->meta_value ); ?></wp:meta_value> |
403 </wp:postmeta> |
459 </wp:postmeta> |
404 <?php endforeach; ?> |
460 <?php endforeach; |
405 <?php $comments = $wpdb->get_results( $wpdb->prepare( "SELECT * FROM $wpdb->comments WHERE comment_post_ID = %d AND comment_approved <> 'spam'", $post->ID ) ); |
461 |
|
462 $comments = $wpdb->get_results( $wpdb->prepare( "SELECT * FROM $wpdb->comments WHERE comment_post_ID = %d AND comment_approved <> 'spam'", $post->ID ) ); |
406 foreach ( $comments as $c ) : ?> |
463 foreach ( $comments as $c ) : ?> |
407 <wp:comment> |
464 <wp:comment> |
408 <wp:comment_id><?php echo $c->comment_ID; ?></wp:comment_id> |
465 <wp:comment_id><?php echo $c->comment_ID; ?></wp:comment_id> |
409 <wp:comment_author><?php echo wxr_cdata( $c->comment_author ); ?></wp:comment_author> |
466 <wp:comment_author><?php echo wxr_cdata( $c->comment_author ); ?></wp:comment_author> |
410 <wp:comment_author_email><?php echo $c->comment_author_email; ?></wp:comment_author_email> |
467 <wp:comment_author_email><?php echo $c->comment_author_email; ?></wp:comment_author_email> |
416 <wp:comment_approved><?php echo $c->comment_approved; ?></wp:comment_approved> |
473 <wp:comment_approved><?php echo $c->comment_approved; ?></wp:comment_approved> |
417 <wp:comment_type><?php echo $c->comment_type; ?></wp:comment_type> |
474 <wp:comment_type><?php echo $c->comment_type; ?></wp:comment_type> |
418 <wp:comment_parent><?php echo $c->comment_parent; ?></wp:comment_parent> |
475 <wp:comment_parent><?php echo $c->comment_parent; ?></wp:comment_parent> |
419 <wp:comment_user_id><?php echo $c->user_id; ?></wp:comment_user_id> |
476 <wp:comment_user_id><?php echo $c->user_id; ?></wp:comment_user_id> |
420 <?php $c_meta = $wpdb->get_results( $wpdb->prepare( "SELECT * FROM $wpdb->commentmeta WHERE comment_id = %d", $c->comment_ID ) ); |
477 <?php $c_meta = $wpdb->get_results( $wpdb->prepare( "SELECT * FROM $wpdb->commentmeta WHERE comment_id = %d", $c->comment_ID ) ); |
421 foreach ( $c_meta as $meta ) : ?> |
478 foreach ( $c_meta as $meta ) : |
|
479 /** |
|
480 * Filter whether to selectively skip comment meta used for WXR exports. |
|
481 * |
|
482 * Returning a truthy value to the filter will skip the current meta |
|
483 * object from being exported. |
|
484 * |
|
485 * @since 4.0.0 |
|
486 * |
|
487 * @param bool $skip Whether to skip the current comment meta. Default false. |
|
488 * @param string $meta_key Current meta key. |
|
489 * @param object $meta Current meta object. |
|
490 */ |
|
491 if ( apply_filters( 'wxr_export_skip_commentmeta', false, $meta->meta_key, $meta ) ) { |
|
492 continue; |
|
493 } |
|
494 ?> |
422 <wp:commentmeta> |
495 <wp:commentmeta> |
423 <wp:meta_key><?php echo $meta->meta_key; ?></wp:meta_key> |
496 <wp:meta_key><?php echo $meta->meta_key; ?></wp:meta_key> |
424 <wp:meta_value><?php echo wxr_cdata( $meta->meta_value ); ?></wp:meta_value> |
497 <wp:meta_value><?php echo wxr_cdata( $meta->meta_value ); ?></wp:meta_value> |
425 </wp:commentmeta> |
498 </wp:commentmeta> |
426 <?php endforeach; ?> |
499 <?php endforeach; ?> |