PageRenderTime 44ms CodeModel.GetById 13ms RepoModel.GetById 0ms app.codeStats 0ms

/src/php/wp-cli/commands/internals/export.php

https://github.com/ericmann/wp-cli
PHP | 541 lines | 439 code | 71 blank | 31 comment | 82 complexity | aa33cf368e3c930d4144304724c07c81 MD5 | raw file
Possible License(s): MIT
  1. <?php
  2. WP_CLI::add_command( 'export', new Export_Command );
  3. /**
  4. * Implement export command
  5. *
  6. * @package wp-cli
  7. * @subpackage commands/internals
  8. */
  9. class Export_Command extends WP_CLI_Command {
  10. /**
  11. * Initialize the array of arguments that will be eventually be passed to export_wp
  12. * @var array
  13. */
  14. public $export_args = array();
  15. /**
  16. * Export posts to a WXR file.
  17. *
  18. * @synopsis [--dir=<dir>] [--start_date=<date>] [--end_date=<date>] [--post_type=<ptype>] [--post_status=<status>] [--post__in=<pids>] [--author=<login>] [--category=<cat>] [--skip_comments] [--file_item_count=<count>]
  19. */
  20. public function __invoke( $_, $assoc_args ) {
  21. $defaults = array(
  22. 'dir' => NULL,
  23. 'start_date' => NULL,
  24. 'end_date' => NULL,
  25. 'post_type' => NULL,
  26. 'author' => NULL,
  27. 'category' => NULL,
  28. 'post_status' => NULL,
  29. 'post__in' => NULL,
  30. 'skip_comments' => NULL,
  31. 'file_item_count' => 1000,
  32. );
  33. $args = wp_parse_args( $assoc_args, $defaults );
  34. $has_errors = false;
  35. foreach ( $args as $key => $value ) {
  36. if ( is_callable( array( $this, 'check_' . $key ) ) ) {
  37. $result = call_user_func( array( $this, 'check_' . $key ), $value );
  38. if ( false === $result )
  39. $has_errors = true;
  40. }
  41. }
  42. if ( $has_errors ) {
  43. exit(1);
  44. }
  45. $this->wxr_path = trailingslashit( $this->export_args['dir'] );
  46. unset( $this->export_args['dir'] );
  47. WP_CLI::line( 'Starting export process...' );
  48. WP_CLI::line();
  49. $this->export_wp( $this->export_args );
  50. }
  51. private function check_dir( $path ) {
  52. if ( empty( $path ) ) {
  53. $this->export_args['dir'] = getcwd();
  54. return true;
  55. }
  56. if ( !is_dir( $path ) ) {
  57. WP_CLI::error( sprintf( "The directory %s does not exist", $path ) );
  58. }
  59. $this->export_args['dir'] = $path;
  60. return true;
  61. }
  62. private function check_start_date( $date ) {
  63. if ( is_null( $date ) )
  64. return true;
  65. $time = strtotime( $date );
  66. if ( !empty( $date ) && !$time ) {
  67. WP_CLI::warning( sprintf( "The start_date %s is invalid", $date ) );
  68. return false;
  69. }
  70. $this->export_args['start_date'] = date( 'Y-m-d', $time );
  71. return true;
  72. }
  73. private function check_end_date( $date ) {
  74. if ( is_null( $date ) )
  75. return true;
  76. $time = strtotime( $date );
  77. if ( !empty( $date ) && !$time ) {
  78. WP_CLI::warning( sprintf( "The end_date %s is invalid", $date ) );
  79. return false;
  80. }
  81. $this->export_args['end_date'] = date( 'Y-m-d', $time );
  82. return true;
  83. }
  84. private function check_post_type( $post_type ) {
  85. if ( is_null( $post_type ) )
  86. return true;
  87. $post_types = get_post_types();
  88. if ( !in_array( $post_type, $post_types ) ) {
  89. 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 ) ) );
  90. return false;
  91. }
  92. $this->export_args['post_type'] = $post_type;
  93. return true;
  94. }
  95. private function check_post__in( $post__in ) {
  96. if ( is_null( $post__in ) )
  97. return true;
  98. $post__in = array_unique( array_map( 'intval', explode( ',', $post__in ) ) );
  99. if ( empty( $post__in ) ) {
  100. WP_CLI::warning( "post__in should be comma-separated post IDs" );
  101. return false;
  102. }
  103. $this->export_args['post__in'] = implode( ',', $post__in );
  104. return true;
  105. }
  106. private function check_author( $author ) {
  107. if ( is_null( $author ) )
  108. return true;
  109. $authors = get_users_of_blog();
  110. if ( empty( $authors ) || is_wp_error( $authors ) ) {
  111. WP_CLI::warning( sprintf( "Could not find any authors in this blog" ) );
  112. return false;
  113. }
  114. $hit = false;
  115. foreach( $authors as $user ) {
  116. if ( $hit )
  117. break;
  118. if ( (int) $author == $user->ID || $author == $user->user_login )
  119. $hit = $user->ID;
  120. }
  121. if ( false === $hit ) {
  122. $authors_nice = array();
  123. foreach( $authors as $_author )
  124. $authors_nice[] = sprintf( '%s (%s)', $_author->user_login, $_author->display_name );
  125. WP_CLI::warning( sprintf( 'Could not find a matching author for %s. The following authors exist: %s', $author, implode( ", ", $authors_nice ) ) );
  126. return false;
  127. }
  128. $this->export_args['author'] = $hit;
  129. return true;
  130. }
  131. private function check_category( $category ) {
  132. if ( is_null( $category ) )
  133. return true;
  134. $term = category_exists( $category );
  135. if ( empty( $term ) || is_wp_error( $term ) ) {
  136. WP_CLI::warning( sprintf( 'Could not find a category matching %s', $category ) );
  137. return false;
  138. }
  139. $this->export_args['category'] = $category;
  140. return true;
  141. }
  142. private function check_post_status( $status ) {
  143. if ( is_null( $status ) )
  144. return true;
  145. $stati = get_post_statuses();
  146. if ( empty( $stati ) || is_wp_error( $stati ) ) {
  147. WP_CLI::warning( 'Could not find any post stati' );
  148. return false;
  149. }
  150. if ( !isset( $stati[$status] ) ) {
  151. 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 ) ) ) );
  152. return false;
  153. }
  154. $this->export_args['status'] = $status;
  155. return true;
  156. }
  157. private function check_skip_comments( $skip ) {
  158. if ( is_null( $skip ) )
  159. return true;
  160. if ( (int) $skip <> 0 && (int) $skip <> 1 ) {
  161. WP_CLI::warning( 'skip_comments needs to be 0 (no) or 1 (yes)' );
  162. return false;
  163. }
  164. $this->export_args['skip_comments'] = $skip;
  165. return true;
  166. }
  167. private function check_file_item_count( $file_item_count ) {
  168. if ( ! is_numeric( $file_item_count ) ) {
  169. WP_CLI::warning( 'File item count needs to be numeric' );
  170. return false;
  171. }
  172. $this->export_args['file_item_count'] = $file_item_count;
  173. return true;
  174. }
  175. /**
  176. * Workaround to prevent memory leaks from growing variables
  177. */
  178. private function stop_the_insanity() {
  179. global $wpdb, $wp_object_cache;
  180. $wpdb->queries = array(); // or define( 'WP_IMPORTING', true );
  181. if ( !is_object( $wp_object_cache ) )
  182. return;
  183. $wp_object_cache->group_ops = array();
  184. $wp_object_cache->stats = array();
  185. $wp_object_cache->memcache_debug = array();
  186. $wp_object_cache->cache = array();
  187. if ( method_exists( $wp_object_cache, '__remoteset' ) )
  188. $wp_object_cache->__remoteset();
  189. }
  190. private function start_export() {
  191. ob_start();
  192. }
  193. private function end_export() {
  194. ob_end_clean();
  195. }
  196. private function flush_export( $file_path, $append = true ) {
  197. $result = ob_get_clean();
  198. if ( $append )
  199. $append = FILE_APPEND;
  200. file_put_contents( $file_path, $result, $append );
  201. $this->start_export();
  202. }
  203. /**
  204. * Export function as it is defined in the original code of export_wp defined in wp-admin/includes/export.php
  205. */
  206. private function export_wp( $args = array() ) {
  207. require_once ABSPATH . 'wp-admin/includes/export.php';
  208. global $wpdb;
  209. /**
  210. * This is mostly the original code of export_wp defined in wp-admin/includes/export.php
  211. */
  212. $defaults = array( 'post_type' => 'all', 'post__in' => false, 'author' => false, 'category' => false,
  213. 'start_date' => false, 'end_date' => false, 'status' => false, 'skip_comments' => false, 'file_item_count' => 1000,
  214. );
  215. $args = wp_parse_args( $args, $defaults );
  216. WP_CLI::line( "Exporting with export_wp with arguments: " . var_export( $args, true ) );
  217. do_action( 'export_wp' );
  218. $sitename = sanitize_key( get_bloginfo( 'name' ) );
  219. if ( ! empty( $sitename ) )
  220. $sitename .= '.';
  221. $append = array( date( 'Y-m-d' ) );
  222. foreach( array_keys( $args ) as $arg_key ) {
  223. if ( $defaults[$arg_key] <> $args[$arg_key] && 'post__in' != $arg_key )
  224. $append[]= "$arg_key-" . (string) $args[$arg_key];
  225. }
  226. $file_name_base = sanitize_file_name( $sitename . 'wordpress.' . implode( ".", $append ) );
  227. if ( 'all' != $args['post_type'] && post_type_exists( $args['post_type'] ) ) {
  228. $ptype = get_post_type_object( $args['post_type'] );
  229. if ( ! $ptype->can_export )
  230. $args['post_type'] = 'post';
  231. $where = $wpdb->prepare( "{$wpdb->posts}.post_type = %s", $args['post_type'] );
  232. } else {
  233. $post_types = get_post_types( array( 'can_export' => true ) );
  234. $esses = array_fill( 0, count( $post_types ), '%s' );
  235. $where = $wpdb->prepare( "{$wpdb->posts}.post_type IN (" . implode( ',', $esses ) . ')', $post_types );
  236. }
  237. if ( $args['status'] && ( 'post' == $args['post_type'] || 'page' == $args['post_type'] ) )
  238. $where .= $wpdb->prepare( " AND {$wpdb->posts}.post_status = %s", $args['status'] );
  239. else
  240. $where .= " AND {$wpdb->posts}.post_status != 'auto-draft'";
  241. $join = '';
  242. if ( $args['category'] && 'post' == $args['post_type'] ) {
  243. if ( $term = term_exists( $args['category'], 'category' ) ) {
  244. $join = "INNER JOIN {$wpdb->term_relationships} ON ({$wpdb->posts}.ID = {$wpdb->term_relationships}.object_id)";
  245. $where .= $wpdb->prepare( " AND {$wpdb->term_relationships}.term_taxonomy_id = %d", $term['term_taxonomy_id'] );
  246. }
  247. }
  248. if ( $args['author'] )
  249. $where .= $wpdb->prepare( " AND {$wpdb->posts}.post_author = %d", $args['author'] );
  250. if ( $args['start_date'] )
  251. $where .= $wpdb->prepare( " AND {$wpdb->posts}.post_date >= %s", date( 'Y-m-d 00:00:00', strtotime( $args['start_date'] ) ) );
  252. if ( $args['end_date'] )
  253. $where .= $wpdb->prepare( " AND {$wpdb->posts}.post_date <= %s", date( 'Y-m-d 23:59:59', strtotime( $args['end_date'] ) ) );
  254. // grab a snapshot of post IDs, just in case it changes during the export
  255. if ( empty( $args['post__in'] ) )
  256. $all_the_post_ids = $wpdb->get_col( "SELECT ID FROM {$wpdb->posts} $join WHERE $where ORDER BY post_date ASC, post_parent ASC" );
  257. else
  258. $all_the_post_ids = $wpdb->get_col( "SELECT ID FROM {$wpdb->posts} WHERE ID IN ({$args['post__in']}) ORDER BY post_date ASC, post_parent ASC" );
  259. // Make sure we're getting all of the attachments for these posts too
  260. if ( 'all' != $args['post_type'] || ! empty( $args['post__in'] ) ) {
  261. $all_post_ids_with_attachments = array();
  262. while ( $post_ids = array_splice( $all_the_post_ids, 0, 100 ) ) {
  263. $attachment_ids = $wpdb->get_col( "SELECT ID FROM {$wpdb->posts} WHERE post_type = 'attachment' AND post_parent IN (". implode( ",", array_map( 'intval', $post_ids ) ) .")" );
  264. $all_post_ids_with_attachments = array_merge( $all_post_ids_with_attachments, $post_ids, (array)$attachment_ids );
  265. }
  266. $all_the_post_ids = $all_post_ids_with_attachments;
  267. }
  268. // get the requested terms ready, empty unless posts filtered by category or all content
  269. $cats = $tags = $terms = array();
  270. if ( isset( $term ) && $term ) {
  271. $cat = get_term( $term['term_id'], 'category' );
  272. $cats = array( $cat->term_id => $cat );
  273. unset( $term, $cat );
  274. } else if ( 'all' == $args['post_type'] ) {
  275. $categories = (array) get_categories( array( 'get' => 'all' ) );
  276. $tags = (array) get_tags( array( 'get' => 'all' ) );
  277. $custom_taxonomies = get_taxonomies( array( '_builtin' => false ) );
  278. $custom_terms = (array) get_terms( $custom_taxonomies, array( 'get' => 'all' ) );
  279. // put categories in order with no child going before its parent
  280. while ( $cat = array_shift( $categories ) ) {
  281. if ( $cat->parent == 0 || isset( $cats[$cat->parent] ) )
  282. $cats[$cat->term_id] = $cat;
  283. else
  284. $categories[] = $cat;
  285. }
  286. // put terms in order with no child going before its parent
  287. while ( $t = array_shift( $custom_terms ) ) {
  288. if ( $t->parent == 0 || isset( $terms[$t->parent] ) )
  289. $terms[$t->term_id] = $t;
  290. else
  291. $custom_terms[] = $t;
  292. }
  293. unset( $categories, $custom_taxonomies, $custom_terms );
  294. }
  295. // Load the functions available in wp-admin/includes/export.php
  296. ob_start();
  297. export_wp( array( 'content' => 'page', 'start_date' => '1971-01-01', 'end_date' => '1971-01-02' ) );
  298. ob_end_clean();
  299. WP_CLI::line( 'Exporting ' . count( $all_the_post_ids ) . ' items to be broken into ' . ceil( count( $all_the_post_ids ) / $args['file_item_count'] ) . ' files' );
  300. WP_CLI::line( 'Exporting ' . count( $cats ) . ' cateogries' );
  301. WP_CLI::line( 'Exporting ' . count( $tags ) . ' tags' );
  302. WP_CLI::line( 'Exporting ' . count( $terms ) . ' terms' );
  303. WP_CLI::line();
  304. $file_count = 1;
  305. while ( $post_ids = array_splice( $all_the_post_ids, 0, $args['file_item_count'] ) ) {
  306. $full_path = $this->wxr_path . $file_name_base . '.' . str_pad( $file_count, 3, '0', STR_PAD_LEFT ) . '.xml';
  307. // Create the file if it doesn't exist
  308. if ( ! file_exists( $full_path ) ) {
  309. touch( $full_path );
  310. }
  311. if ( ! file_exists( $full_path ) ) {
  312. WP_CLI::error( "Failed to create file " . $full_path );
  313. exit;
  314. } else {
  315. WP_CLI::line( 'Writing to file ' . $full_path );
  316. }
  317. $progress = new \cli\progress\Bar( 'Exporting', count( $post_ids ) );
  318. $this->start_export();
  319. echo '<?xml version="1.0" encoding="' . get_bloginfo( 'charset' ) . "\" ?>\n";
  320. ?>
  321. <!-- This is a WordPress eXtended RSS file generated by WordPress as an export of your site. -->
  322. <!-- It contains information about your site's posts, pages, comments, categories, and other content. -->
  323. <!-- You may use this file to transfer that content from one site to another. -->
  324. <!-- This file is not intended to serve as a complete backup of your site. -->
  325. <!-- To import this information into a WordPress site follow these steps: -->
  326. <!-- 1. Log in to that site as an administrator. -->
  327. <!-- 2. Go to Tools: Import in the WordPress admin panel. -->
  328. <!-- 3. Install the "WordPress" importer from the list. -->
  329. <!-- 4. Activate & Run Importer. -->
  330. <!-- 5. Upload this file using the form provided on that page. -->
  331. <!-- 6. You will first be asked to map the authors in this export file to users -->
  332. <!-- on the site. For each author, you may choose to map to an -->
  333. <!-- existing user on the site or to create a new user. -->
  334. <!-- 7. WordPress will then import each of the posts, pages, comments, categories, etc. -->
  335. <!-- contained in this file into your site. -->
  336. <?php the_generator( 'export' ); ?>
  337. <rss version="2.0"
  338. xmlns:excerpt="http://wordpress.org/export/<?php echo WXR_VERSION; ?>/excerpt/"
  339. xmlns:content="http://purl.org/rss/1.0/modules/content/"
  340. xmlns:wfw="http://wellformedweb.org/CommentAPI/"
  341. xmlns:dc="http://purl.org/dc/elements/1.1/"
  342. xmlns:wp="http://wordpress.org/export/<?php echo WXR_VERSION; ?>/"
  343. >
  344. <channel>
  345. <title><?php bloginfo_rss( 'name' ); ?></title>
  346. <link><?php bloginfo_rss( 'url' ); ?></link>
  347. <description><?php bloginfo_rss( 'description' ); ?></description>
  348. <pubDate><?php echo date( 'D, d M Y H:i:s +0000' ); ?></pubDate>
  349. <language><?php echo get_option( 'rss_language' ); ?></language>
  350. <wp:wxr_version><?php echo WXR_VERSION; ?></wp:wxr_version>
  351. <wp:base_site_url><?php echo wxr_site_url(); ?></wp:base_site_url>
  352. <wp:base_blog_url><?php bloginfo_rss( 'url' ); ?></wp:base_blog_url>
  353. <?php wxr_authors_list(); ?>
  354. <?php foreach ( $cats as $c ) : ?>
  355. <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>
  356. <?php endforeach; ?>
  357. <?php foreach ( $tags as $t ) : ?>
  358. <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>
  359. <?php endforeach; ?>
  360. <?php foreach ( $terms as $t ) : ?>
  361. <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>
  362. <?php endforeach; ?>
  363. <?php if ( 'all' == $args['post_type'] ) wxr_nav_menu_terms(); ?>
  364. <?php do_action( 'rss2_head' ); ?>
  365. <?php $this->flush_export( $full_path, false ); ?>
  366. <?php if ( $post_ids ) {
  367. global $wp_query, $post;
  368. $wp_query->in_the_loop = true; // Fake being in the loop.
  369. // fetch 20 posts at a time rather than loading the entire table into memory
  370. while ( $next_posts = array_splice( $post_ids, 0, 20 ) ) {
  371. $where = 'WHERE ID IN (' . join( ',', $next_posts ) . ')';
  372. $posts = $wpdb->get_results( "SELECT * FROM {$wpdb->posts} $where" );
  373. // Begin Loop
  374. foreach ( $posts as $post ) {
  375. $progress->tick();
  376. setup_postdata( $post );
  377. $is_sticky = is_sticky( $post->ID ) ? 1 : 0;
  378. ?>
  379. <item>
  380. <title><?php echo apply_filters( 'the_title_rss', $post->post_title ); ?></title>
  381. <link><?php the_permalink_rss() ?></link>
  382. <pubDate><?php echo mysql2date( 'D, d M Y H:i:s +0000', get_post_time( 'Y-m-d H:i:s', true ), false ); ?></pubDate>
  383. <dc:creator><?php echo get_the_author_meta( 'login' ); ?></dc:creator>
  384. <guid isPermaLink="false"><?php esc_url( the_guid() ); ?></guid>
  385. <description></description>
  386. <content:encoded><?php echo wxr_cdata( apply_filters( 'the_content_export', $post->post_content ) ); ?></content:encoded>
  387. <excerpt:encoded><?php echo wxr_cdata( apply_filters( 'the_excerpt_export', $post->post_excerpt ) ); ?></excerpt:encoded>
  388. <wp:post_id><?php echo $post->ID; ?></wp:post_id>
  389. <wp:post_date><?php echo $post->post_date; ?></wp:post_date>
  390. <wp:post_date_gmt><?php echo $post->post_date_gmt; ?></wp:post_date_gmt>
  391. <wp:comment_status><?php echo $post->comment_status; ?></wp:comment_status>
  392. <wp:ping_status><?php echo $post->ping_status; ?></wp:ping_status>
  393. <wp:post_name><?php echo $post->post_name; ?></wp:post_name>
  394. <wp:status><?php echo $post->post_status; ?></wp:status>
  395. <wp:post_parent><?php echo $post->post_parent; ?></wp:post_parent>
  396. <wp:menu_order><?php echo $post->menu_order; ?></wp:menu_order>
  397. <wp:post_type><?php echo $post->post_type; ?></wp:post_type>
  398. <wp:post_password><?php echo $post->post_password; ?></wp:post_password>
  399. <wp:is_sticky><?php echo $is_sticky; ?></wp:is_sticky>
  400. <?php if ( $post->post_type == 'attachment' ) : ?>
  401. <wp:attachment_url><?php echo wp_get_attachment_url( $post->ID ); ?></wp:attachment_url>
  402. <?php endif; ?>
  403. <?php wxr_post_taxonomy(); ?>
  404. <?php $postmeta = $wpdb->get_results( $wpdb->prepare( "SELECT * FROM $wpdb->postmeta WHERE post_id = %d", $post->ID ) );
  405. foreach ( $postmeta as $meta ) :
  406. if ( apply_filters( 'wxr_export_skip_postmeta', false, $meta->meta_key, $meta ) )
  407. continue;
  408. ?>
  409. <wp:postmeta>
  410. <wp:meta_key><?php echo $meta->meta_key; ?></wp:meta_key>
  411. <wp:meta_value><?php echo wxr_cdata( $meta->meta_value ); ?></wp:meta_value>
  412. </wp:postmeta>
  413. <?php endforeach; ?>
  414. <?php if ( false === $args['skip_comments'] ): ?>
  415. <?php $comments = $wpdb->get_results( $wpdb->prepare( "SELECT * FROM $wpdb->comments WHERE comment_post_ID = %d AND comment_approved <> 'spam'", $post->ID ) );
  416. foreach ( $comments as $c ) : ?>
  417. <wp:comment>
  418. <wp:comment_id><?php echo $c->comment_ID; ?></wp:comment_id>
  419. <wp:comment_author><?php echo wxr_cdata( $c->comment_author ); ?></wp:comment_author>
  420. <wp:comment_author_email><?php echo $c->comment_author_email; ?></wp:comment_author_email>
  421. <wp:comment_author_url><?php echo esc_url_raw( $c->comment_author_url ); ?></wp:comment_author_url>
  422. <wp:comment_author_IP><?php echo $c->comment_author_IP; ?></wp:comment_author_IP>
  423. <wp:comment_date><?php echo $c->comment_date; ?></wp:comment_date>
  424. <wp:comment_date_gmt><?php echo $c->comment_date_gmt; ?></wp:comment_date_gmt>
  425. <wp:comment_content><?php echo wxr_cdata( $c->comment_content ) ?></wp:comment_content>
  426. <wp:comment_approved><?php echo $c->comment_approved; ?></wp:comment_approved>
  427. <wp:comment_type><?php echo $c->comment_type; ?></wp:comment_type>
  428. <wp:comment_parent><?php echo $c->comment_parent; ?></wp:comment_parent>
  429. <wp:comment_user_id><?php echo $c->user_id; ?></wp:comment_user_id>
  430. <?php $c_meta = $wpdb->get_results( $wpdb->prepare( "SELECT * FROM $wpdb->commentmeta WHERE comment_id = %d", $c->comment_ID ) );
  431. foreach ( $c_meta as $meta ) : ?>
  432. <wp:commentmeta>
  433. <wp:meta_key><?php echo $meta->meta_key; ?></wp:meta_key>
  434. <wp:meta_value><?php echo wxr_cdata( $meta->meta_value ); ?></wp:meta_value>
  435. </wp:commentmeta>
  436. <?php endforeach; ?>
  437. </wp:comment>
  438. <?php endforeach; ?>
  439. <?php endif; ?>
  440. </item>
  441. <?php
  442. $this->flush_export( $full_path );
  443. }
  444. }
  445. } ?>
  446. </channel>
  447. </rss>
  448. <?php
  449. $this->flush_export( $full_path );
  450. $this->end_export();
  451. $this->stop_the_insanity();
  452. $progress->finish();
  453. $file_count++;
  454. }
  455. WP_CLI::success( "All done with export" );
  456. }
  457. }