PluginProbe
BetterDocs – AI Documentation, Knowledge Base, MCP Server, Docs, Wikis, FAQ & Chatbot / 4.5.0
BetterDocs – AI Documentation, Knowledge Base, MCP Server, Docs, Wikis, FAQ & Chatbot v4.5.0
4.9.1 4.9.0 4.8.2 4.8.1 4.8.0 4.7.0 4.6.2 4.6.1 4.6.0 4.5.6 4.5.5 4.5.4 4.5.3 4.5.2 4.5.1 4.5.0 4.4.1 4.4.0 3.3.4 3.4.0 3.4.1 3.4.2 3.5.0 3.5.1 3.5.2 All 199 releases
betterdocs / includes / Admin / XMLExporter.php

XMLExporter.php in BetterDocs – AI Documentation, Knowledge Base, MCP Server, Docs, Wikis, FAQ & Chatbot 4.5.0, at includes/Admin/XMLExporter.php

671 lines 23.2 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 namespace WPDeveloper\BetterDocs\Admin;
3
4 use WPDeveloper\BetterDocs\Admin\ExportDefaults;
5 use WPDeveloper\BetterDocs\Admin\WPExporter;
6
7 use WP_Post;
8 use WP_Term;
9 use wpdb;
10
11
12 if ( ! defined( 'ABSPATH' ) ) {
13 exit; // Exit if accessed directly.
14 }
15
16 /*
17 * Originally made by WordPress.
18 *
19 * What changed (by Elementor):
20 * Remove echos.
21 * Fix indents.
22 * Add methods
23 * indent.
24 * wxr_categories_list.
25 * wxr_tags_list.
26 * wxr_terms_list.
27 * wxr_posts_list.
28 *
29 * What changed (by Templately)
30 * Added post__in capabilities for query.
31 * nav_menu_item from terms
32 * Some indent, and data type fixes
33 * query_args added as default args
34 */
35
36 #[\AllowDynamicProperties]
37 class XMLExporter {
38 const WXR_VERSION = '1.2';
39
40 /**
41 * @var array
42 */
43 private $args;
44
45 /**
46 * @var wpdb
47 */
48 private $wpdb;
49
50 private $terms;
51
52 private $nav_menu_terms;
53
54 private $wpexporter;
55
56 public function __construct( array $args = [] ) {
57 global $wpdb;
58
59 $this->args = wp_parse_args($args, ExportDefaults::get_default_args());
60
61 $this->wpexporter = new WPExporter($this->args);
62
63 $this->wpdb = $wpdb;
64 }
65
66 public function run(): array {
67 // Handle glossaries export (as taxonomy)
68 if ('glossaries' === $this->args['content']) {
69 return $this->handle_glossaries_export();
70 }
71
72 return [
73 'success' => true,
74 'data' => [
75 'filename' => 'betterdocs.' . date('Y-m-d') . '.xml',
76 'filetype' => 'text/xml',
77 'download' => $this->get_xml_export($this->wpexporter->exporter_ids()),
78 ]
79 ];
80 }
81
82 public function handle_glossaries_export(): array {
83 $filename = 'betterdocs.' . date( 'Y-m-d' ) . '.xml';
84 return [
85 'success' => true,
86 'data' => [
87 'filename' => $filename,
88 'filetype' => 'text/xml',
89 'download' => $this->get_xml_export( $this->wpexporter->get_glossary_term_ids() ),
90 ]
91 ];
92 }
93
94 /**
95 * Return tabulation characters, by `$columns`.
96 *
97 * @param int $columns
98 *
99 * @return string
100 */
101 private function indent( int $columns = 1 ): string {
102
103 $output = str_repeat( "\t", $columns );
104
105 return (string) $output;
106 }
107
108 /**
109 * Return wrapped given string in XML CDATA tag.
110 *
111 * @param string $str String to wrap in XML CDATA tag.
112 *
113 * @return string
114 */
115 private function wxr_cdata( $str ): string {
116 $str = (string) $str;
117
118 if ( ! seems_utf8( $str ) ) {
119 $str = utf8_encode( $str );
120 }
121
122 $str = '<![CDATA[' . str_replace( ']]>', ']]]]><![CDATA[>', $str ) . ']]>';
123
124 return $str;
125 }
126
127 /**
128 * Return the URL of the site.
129 *
130 * @return string Site URL.
131 */
132 private function wxr_site_url(): string {
133 if ( is_multisite() ) {
134 // Multisite: the base URL.
135 return network_home_url();
136 } else {
137 // WordPress (single site): the blog URL.
138 return get_bloginfo_rss( 'url' );
139 }
140 }
141
142 /**
143 * Return a cat_name XML tag from a given category object.
144 *
145 * @param WP_Term $category Category Object
146 *
147 * @return string
148 */
149 private function wxr_cat_name( $category ): string {
150 if ( empty( $category->name ) ) {
151 return '';
152 }
153
154 return $this->indent( 3 ) . '<wp:cat_name>' . $this->wxr_cdata( $category->name ) . '</wp:cat_name>' . PHP_EOL;
155 }
156
157 /**
158 * Return a category_description XML tag from a given category object.
159 *
160 * @param WP_Term $category Category Object
161 *
162 * @return string
163 */
164 private function wxr_category_description( $category ): string {
165 if ( empty( $category->description ) ) {
166 return '';
167 }
168
169 return $this->indent( 3 ) . '<wp:category_description>' . $this->wxr_cdata( $category->description ) . "</wp:category_description>\n";
170 }
171
172 /**
173 * Return a tag_name XML tag from a given tag object.
174 *
175 * @param WP_Term $tag Tag Object
176 *
177 * @return string
178 */
179 private function wxr_tag_name( $tag ): string {
180 if ( empty( $tag->name ) ) {
181 return '';
182 }
183
184 return $this->indent( 3 ) . '<wp:tag_name>' . $this->wxr_cdata( $tag->name ) . '</wp:tag_name>' . PHP_EOL;
185 }
186
187 /**
188 * Return a tag_description XML tag from a given tag object.
189 *
190 * @param WP_Term $tag Tag Object
191 *
192 * @return string
193 */
194 private function wxr_tag_description( $tag ): string {
195 if ( empty( $tag->description ) ) {
196 return '';
197 }
198
199 return $this->indent( 3 ) . '<wp:tag_description>' . $this->wxr_cdata( $tag->description ) . '</wp:tag_description>' . PHP_EOL;
200 }
201
202 /**
203 * Return a term_name XML tag from a given term object.
204 *
205 * @param WP_Term $term Term Object
206 *
207 * @return string
208 */
209 private function wxr_term_name( $term ): string {
210 if ( empty( $term->name ) ) {
211 return '';
212 }
213
214 return $this->indent( 3 ) . '<wp:term_name>' . $this->wxr_cdata( $term->name ) . '</wp:term_name>' . PHP_EOL;
215 }
216
217 /**
218 * Return a term_description XML tag from a given term object.
219 *
220 * @param WP_Term $term Term Object
221 *
222 * @return string
223 */
224 private function wxr_term_description( $term ): string {
225 if ( empty( $term->description ) ) {
226 return '';
227 }
228
229 return $this->indent( 3 ) . '<wp:term_description>' . $this->wxr_cdata( $term->description ) . '</wp:term_description>' . PHP_EOL;
230 }
231
232 /**
233 * Return term meta XML tags for a given term object.
234 *
235 * @param WP_Term $term Term object.
236 *
237 * @return string
238 */
239 private function wxr_term_meta( $term ): string {
240 $result = '';
241 $termmeta = $this->wpdb->get_results( $this->wpdb->prepare( "SELECT * FROM {$this->wpdb->termmeta} WHERE term_id = %d", $term->term_id ) );// phpcs:ignore
242
243 foreach ( $termmeta as $meta ) {
244 /**
245 * Filters whether to selectively skip term meta used for WXR exports.
246 *
247 * Returning a truthy value from the filter will skip the current meta
248 * object from being exported.
249 *
250 * @param bool $skip Whether to skip the current piece of term meta. Default false.
251 * @param string $meta_key Current meta key.
252 * @param object $meta Current meta object.
253 *
254 * @since 4.6.0
255 *
256 */
257 if ( ! apply_filters( 'wxr_export_skip_termmeta', false, $meta->meta_key, $meta ) ) {
258 $result .= sprintf( $this->indent( 3 ) . "<wp:termmeta>\n\t\t\t<wp:meta_key>%s</wp:meta_key>\n\t\t\t<wp:meta_value>%s</wp:meta_value>\n\t\t</wp:termmeta>\n", $this->wxr_cdata( $meta->meta_key ), $this->wxr_cdata( $meta->meta_value ) );
259 }
260 }
261
262 return $result;
263 }
264
265 /**
266 * Return list of authors with posts.
267 *
268 * @param int[] $post_ids Optional. Array of post IDs to filter the query by.
269 *
270 * @return string
271 */
272 private function wxr_authors_list( array $post_ids = null ): string {
273 $result = '';
274
275 if ( ! empty( $post_ids ) ) {
276 $post_ids = array_map( 'absint', $post_ids );
277 $and = 'AND ID IN ( ' . implode( ', ', $post_ids ) . ')';
278 } else {
279 $and = '';
280 }
281
282 $authors = [];
283 $results = $this->wpdb->get_results( "SELECT DISTINCT post_author FROM {$this->wpdb->posts} WHERE post_status != 'auto-draft' $and" );// phpcs:ignore
284 foreach ( (array) $results as $r ) {
285 $authors[] = get_userdata( $r->post_author );
286 }
287
288 $authors = array_filter( $authors );
289
290 foreach ( $authors as $author ) {
291 $result .= $this->indent( 2 ) . '<wp:author>' . PHP_EOL;
292
293 $result .= $this->indent( 3 ) . '<wp:author_id>' . (int) $author->ID . '</wp:author_id>' . PHP_EOL;
294 $result .= $this->indent( 3 ) . '<wp:author_login>' . $this->wxr_cdata( $author->user_login ) . '</wp:author_login>' . PHP_EOL;
295 $result .= $this->indent( 3 ) . '<wp:author_email>' . $this->wxr_cdata( $author->user_email ) . '</wp:author_email>' . PHP_EOL;
296 $result .= $this->indent( 3 ) . '<wp:author_display_name>' . $this->wxr_cdata( $author->display_name ) . '</wp:author_display_name>' . PHP_EOL;
297 $result .= $this->indent( 3 ) . '<wp:author_first_name>' . $this->wxr_cdata( $author->first_name ) . '</wp:author_first_name>' . PHP_EOL;
298 $result .= $this->indent( 3 ) . '<wp:author_last_name>' . $this->wxr_cdata( $author->last_name ) . '</wp:author_last_name>' . PHP_EOL;
299
300 $result .= $this->indent( 2 ) . '</wp:author>' . PHP_EOL;
301 }
302
303 return $result;
304 }
305
306 /**
307 * Return list of categories.
308 *
309 * @param array $cats
310 *
311 * @return string
312 */
313 private function wxr_categories_list( array $cats ): string {
314 $result = '';
315
316 foreach ( $cats as $c ) {
317 $result .= $this->indent( 2 ) . '<wp:category>' . PHP_EOL;
318
319 $result .= $this->indent( 3 ) . '<wp:term_id>' . (int) $c->term_id . '</wp:term_id>' . PHP_EOL;
320 $result .= $this->indent( 3 ) . '<wp:category_nicename>' . $this->wxr_cdata( $c->slug ) . '</wp:category_nicename>' . PHP_EOL;
321 $result .= $this->indent( 3 ) . '<wp:category_parent>' . $this->wxr_cdata( $c->parent ? $cats[ $c->parent ]->slug : '' ) . '</wp:category_parent>' . PHP_EOL;
322 $result .= $this->wxr_cat_name( $c ) . $this->wxr_category_description( $c ) . $this->wxr_term_meta( $c );
323
324 $result .= $this->indent( 2 ) . '</wp:category>' . PHP_EOL;
325 }
326
327 return $result;
328 }
329
330 /**
331 * Return list of tags.
332 *
333 * @param array $tags
334 *
335 * @return string
336 */
337 private function wxr_tags_list( array $tags ): string {
338 $result = '';
339
340 foreach ( $tags as $t ) {
341 $result .= $this->indent( 2 ) . '<wp:tag>' . PHP_EOL;
342
343 $result .= $this->indent( 3 ) . '<wp:term_id>' . (int) $t->term_id . '</wp:term_id>' . PHP_EOL;
344 $result .= $this->indent( 3 ) . '<wp:tag_slug>' . $this->wxr_cdata( $t->slug ) . '</wp:tag_slug>' . PHP_EOL;
345 $result .= $this->wxr_tag_name( $t ) . $this->wxr_tag_description( $t ) . $this->wxr_term_meta( $t );
346
347 $result .= $this->indent( 2 ) . '</wp:tag>' . PHP_EOL;
348 }
349
350 return $result;
351 }
352
353 public function get_parent_terms_slug( $terms, $term_id ) {
354 $key = array_search( $term_id, array_column( $terms, 'term_id' ));
355
356 if ( $key !== false ) {
357 return $terms[$key]->slug;
358 }
359
360 return null;
361 }
362
363 /**
364 * Return list of terms.
365 *
366 * @param array $terms
367 *
368 * @return string
369 */
370 private function wxr_terms_list( array $terms ): string {
371 $result = '';
372 foreach ( $terms as $key => $t ) {
373 $result .= $this->indent( 2 ) . '<wp:term>' . PHP_EOL;
374
375 $result .= $this->indent( 3 ) . '<wp:term_id>' . $this->wxr_cdata( $t->term_id ) . '</wp:term_id>' . PHP_EOL;
376 $result .= $this->indent( 3 ) . '<wp:term_taxonomy>' . $this->wxr_cdata( $t->taxonomy ) . '</wp:term_taxonomy>' . PHP_EOL;
377 $result .= $this->indent( 3 ) . '<wp:term_slug>' . $this->wxr_cdata( $t->slug ) . '</wp:term_slug>' . PHP_EOL;
378 if ( $t->parent ) {
379 $result .= $this->indent( 3 ) . '<wp:term_parent>' . $this->wxr_cdata( $this->get_parent_terms_slug( $terms, $t->parent ) ) . '</wp:term_parent>' . PHP_EOL;
380 }
381 $result .= $this->wxr_term_name( $t ) . $this->wxr_term_description( $t ) . $this->wxr_term_meta( $t );
382
383 $result .= $this->indent( 2 ) . '</wp:term>' . PHP_EOL;
384 }
385
386 return $result;
387 }
388
389 // public function get_terms( array $post_ids ) {
390 // // Get the object taxonomies
391 // $taxonomies = get_object_taxonomies( $this->args['content'] );
392
393 // if ( isset( $this->args['selected_docs'] ) && ! empty ( $this->args['selected_docs'] ) && $this->args['selected_docs'][0] == 'all' ) {
394 // $terms = get_terms( [
395 // 'taxonomy' => $taxonomies,
396 // 'hide_empty' => false,
397 // ] );
398 // } else if( $this->args['content'] == 'glossaries' ) {
399 // $terms = get_terms([
400 // 'taxonomy' => 'glossaries',
401 // 'include' => $post_ids,
402 // 'hide_empty' => false,
403 // ]);
404 // } else {
405 // $terms = wp_get_object_terms( $post_ids, $taxonomies);
406 // }
407
408 // usort( $terms, array( $this, 'compare_terms_by_meta' ) );
409
410 // return $terms;
411 // }
412
413 /**
414 * Return list of posts, by requested `$post_ids`.
415 *
416 * @param array $post_ids
417 *
418 * @return string
419 */
420 private function wxr_posts_list( array $post_ids ): string {
421 $result = '';
422
423 if ( $post_ids ) {
424 global $wp_query;
425
426 // Fake being in the loop.
427 $wp_query->in_the_loop = true;
428
429 // Fetch 20 posts at a time rather than loading the entire table into memory.
430 while ( $next_posts = array_splice( $post_ids, 0, 20 ) ) {
431 $where = 'WHERE ID IN (' . implode( ',', $next_posts ) . ')';
432 $posts = $this->wpdb->get_results( "SELECT * FROM {$this->wpdb->posts} $where" );// phpcs:ignore
433
434 // Begin Loop.
435 foreach ( $posts as $post ) {
436 setup_postdata( $post );
437
438 $title = apply_filters( 'the_title_rss', $post->post_title );
439
440 /**
441 * Filters the post content used for WXR exports.
442 *
443 * @param string $post_content Content of the current post.
444 *
445 * @since 2.5.0
446 *
447 */
448 $content = $this->wxr_cdata( apply_filters( 'the_content_export', $post->post_content ) );
449
450 /**
451 * Filters the post excerpt used for WXR exports.
452 *
453 * @param string $post_excerpt Excerpt for the current post.
454 *
455 * @since 2.6.0
456 *
457 */
458 $excerpt = $this->wxr_cdata( apply_filters( 'the_excerpt_export', $post->post_excerpt ) );
459
460 $result .= $this->indent( 2 ) . '<item>' . PHP_EOL;
461
462 $result .= $this->indent( 3 ) . '<title>' . $title . '</title>' . PHP_EOL;
463 $result .= $this->indent( 3 ) . '<link>' . esc_url( get_permalink() ) . '</link>' . PHP_EOL;
464 $result .= $this->indent( 3 ) . '<pubDate>' . mysql2date( 'D, d M Y H:i:s +0000', get_post_time( 'Y-m-d H:i:s', true ), false ) . '</pubDate>' . PHP_EOL;
465 $result .= $this->indent( 3 ) . '<dc:creator>' . $this->wxr_cdata( get_the_author_meta( 'login' ) ) . '</dc:creator>' . PHP_EOL;
466 $result .= $this->indent( 3 ) . '<guid isPermaLink="false">' . $this->wxr_cdata( get_the_author_meta( 'login' ) ) . '</guid>' . PHP_EOL;
467 $result .= $this->indent( 3 ) . '<description></description>' . PHP_EOL;
468 $result .= $this->indent( 3 ) . '<content:encoded>' . $content . '</content:encoded>' . PHP_EOL;
469 $result .= $this->indent( 3 ) . '<excerpt:encoded>' . $excerpt . '</excerpt:encoded>' . PHP_EOL;
470 $result .= $this->indent( 3 ) . '<wp:post_id>' . (int) $post->ID . '</wp:post_id>' . PHP_EOL;
471 $result .= $this->indent( 3 ) . '<wp:post_date>' . $this->wxr_cdata( $post->post_date ) . '</wp:post_date>' . PHP_EOL;
472 $result .= $this->indent( 3 ) . '<wp:post_date_gmt>' . $this->wxr_cdata( $post->post_date_gmt ) . '</wp:post_date_gmt>' . PHP_EOL;
473 $result .= $this->indent( 3 ) . '<wp:comment_status>' . $this->wxr_cdata( $post->comment_status ) . '</wp:comment_status>' . PHP_EOL;
474 $result .= $this->indent( 3 ) . '<wp:ping_status>' . $this->wxr_cdata( $post->ping_status ) . '</wp:ping_status>' . PHP_EOL;
475 $result .= $this->indent( 3 ) . '<wp:post_name>' . $this->wxr_cdata( $post->post_name ) . '</wp:post_name>' . PHP_EOL;
476 $result .= $this->indent( 3 ) . '<wp:status>' . $this->wxr_cdata( $post->post_status ) . '</wp:status>' . PHP_EOL;
477 $result .= $this->indent( 3 ) . '<wp:post_parent>' . $this->wxr_cdata( $post->post_parent ) . '</wp:post_parent>' . PHP_EOL;
478 $result .= $this->indent( 3 ) . '<wp:menu_order>' . (int) $post->menu_order . '</wp:menu_order>' . PHP_EOL;
479 $result .= $this->indent( 3 ) . '<wp:post_type>' . $this->wxr_cdata( $post->post_type ) . '</wp:post_type>' . PHP_EOL;
480 $result .= $this->indent( 3 ) . '<wp:post_password>' . $this->wxr_cdata( $post->post_password ) . '</wp:post_password>' . PHP_EOL;
481 $result .= $this->indent( 3 ) . '<wp:is_sticky>' . ( is_sticky( $post->ID ) ? 1 : 0 ) . '</wp:is_sticky>' . PHP_EOL;
482
483 if ( 'attachment' === $post->post_type ) {
484 $result .= $this->indent( 3 ) . '<wp:attachment_url>' . $this->wxr_cdata( wp_get_attachment_url( $post->ID ) ) . '</wp:attachment_url>' . PHP_EOL;
485 }
486
487 $result .= $this->wxr_post_taxonomy( $post );
488
489 $postmeta = $this->wpdb->get_results( $this->wpdb->prepare( "SELECT * FROM {$this->wpdb->postmeta} WHERE post_id = %d", $post->ID ) );// phpcs:ignore
490 foreach ( $postmeta as $meta ) {
491 /**
492 * Filters whether to selectively skip post meta used for WXR exports.
493 *
494 * Returning a truthy value from the filter will skip the current meta
495 * object from being exported.
496 *
497 * @param bool $skip Whether to skip the current post meta. Default false.
498 * @param string $meta_key Current meta key.
499 * @param object $meta Current meta object.
500 *
501 * @since 3.3.0
502 *
503 */
504 if ( apply_filters( 'wxr_export_skip_postmeta', false, $meta->meta_key, $meta ) ) {
505 continue;
506 }
507
508 $result .= $this->indent( 3 ) . '<wp:postmeta>' . PHP_EOL;
509
510 $result .= $this->indent( 4 ) . '<wp:meta_key>' . $this->wxr_cdata( $meta->meta_key ) . '</wp:meta_key>' . PHP_EOL;
511 $result .= $this->indent( 4 ) . '<wp:meta_value>' . $this->wxr_cdata( $meta->meta_value ) . '</wp:meta_value>' . PHP_EOL;
512
513 $result .= $this->indent( 3 ) . '</wp:postmeta>' . PHP_EOL;
514 }
515
516 $_comments = $this->wpdb->get_results( $this->wpdb->prepare( "SELECT * FROM {$this->wpdb->comments} WHERE comment_post_ID = %d AND comment_approved <> 'spam'", $post->ID ) );// phpcs:ignore
517 $comments = array_map( 'get_comment', $_comments );
518 foreach ( $comments as $c ) {
519
520 $result .= $this->indent( 3 ) . '<wp:comment>' . PHP_EOL;
521
522 $result .= $this->indent( 4 ) . '<wp:comment_id>' . (int) $c->comment_ID . '</wp:comment_id>' . PHP_EOL;
523 $result .= $this->indent( 4 ) . '<wp:comment_author>' . $this->wxr_cdata( $c->comment_author ) . '</wp:comment_author>' . PHP_EOL;
524 $result .= $this->indent( 4 ) . '<wp:comment_author_email>' . $this->wxr_cdata( $c->comment_author_email ) . '</wp:comment_author_email>' . PHP_EOL;
525 $result .= $this->indent( 4 ) . '<wp:comment_author_url>' . $this->wxr_cdata( $c->comment_author_url ) . '</wp:comment_author_url>' . PHP_EOL;
526 $result .= $this->indent( 4 ) . '<wp:comment_author_IP>' . $this->wxr_cdata( $c->comment_author_IP ) . '</wp:comment_author_IP>' . PHP_EOL;
527 $result .= $this->indent( 4 ) . '<wp:comment_date>' . $this->wxr_cdata( $c->comment_date ) . '</wp:comment_date>' . PHP_EOL;
528 $result .= $this->indent( 4 ) . '<wp:comment_date_gmt>' . $this->wxr_cdata( $c->comment_date_gmt ) . '</wp:comment_date_gmt>' . PHP_EOL;
529 $result .= $this->indent( 4 ) . '<wp:comment_content>' . $this->wxr_cdata( $c->comment_content ) . '</wp:comment_content>' . PHP_EOL;
530 $result .= $this->indent( 4 ) . '<wp:comment_approved>' . $this->wxr_cdata( $c->comment_approved ) . '</wp:comment_approved>' . PHP_EOL;
531 $result .= $this->indent( 4 ) . '<wp:comment_type>' . $this->wxr_cdata( $c->comment_type ) . '</wp:comment_type>' . PHP_EOL;
532 $result .= $this->indent( 4 ) . '<wp:comment_parent>' . $this->wxr_cdata( $c->comment_parent ) . '</wp:comment_parent>' . PHP_EOL;
533 $result .= $this->indent( 4 ) . '<wp:comment_user_id>' . (int) $c->user_id . '</wp:comment_user_id>' . PHP_EOL;
534
535 $c_meta = $this->wpdb->get_results( $this->wpdb->prepare( "SELECT * FROM {$this->wpdb->commentmeta} WHERE comment_id = %d", $c->comment_ID ) );// phpcs:ignore
536 foreach ( $c_meta as $meta ) {
537 /**
538 * Filters whether to selectively skip comment meta used for WXR exports.
539 *
540 * Returning a truthy value from the filter will skip the current meta
541 * object from being exported.
542 *
543 * @param bool $skip Whether to skip the current comment meta. Default false.
544 * @param string $meta_key Current meta key.
545 * @param object $meta Current meta object.
546 *
547 * @since 4.0.0
548 *
549 */
550 if ( apply_filters( 'wxr_export_skip_commentmeta', false, $meta->meta_key, $meta ) ) {
551 continue;
552 }
553
554 $result .= $this->indent( 4 ) . '<wp:commentmeta>' . PHP_EOL;
555
556 $result .= $this->indent( 5 ) . '<wp:meta_key>' . $this->wxr_cdata( $meta->meta_key ) . '</wp:meta_key>' . PHP_EOL;
557 $result .= $this->indent( 5 ) . '<wp:meta_value>' . $this->wxr_cdata( $meta->meta_key ) . '</wp:meta_value>' . PHP_EOL;
558
559 $result .= $this->indent( 4 ) . '</wp:commentmeta>' . PHP_EOL;
560 }
561
562 $result .= $this->indent( 3 ) . '</wp:comment>' . PHP_EOL;
563 }
564
565 $result .= $this->indent( 2 ) . '</item>' . PHP_EOL;
566 }
567 }
568 }
569
570 return $result;
571 }
572
573 /**
574 * Return list of taxonomy terms, in XML tag format, associated with a post
575 *
576 * @param object $post
577 *
578 * @return string
579 */
580 private function wxr_post_taxonomy( $post ): string {
581 $result = '';
582
583 $taxonomies = get_object_taxonomies( $post->post_type );
584
585 if ( empty( $taxonomies ) ) {
586 return $result;
587 }
588
589 $terms = wp_get_object_terms( $post->ID, $taxonomies );
590
591 foreach ( (array) $terms as $term ) {
592 $result .= $this->indent( 3 ) . "<category domain=\"{$term->taxonomy}\" nicename=\"{$term->slug}\">" . $this->wxr_cdata( $term->name ) . '</category>' . PHP_EOL;
593 }
594
595 return $result;
596 }
597
598 /**
599 * Get the XML export.
600 *
601 * @param array $post_ids
602 *
603 * @return string
604 */
605 private function get_xml_export( array $post_ids ): string {
606 $charset = get_bloginfo( 'charset' );
607 $generator = get_the_generator( 'export' );
608 $wxr_version = self::WXR_VERSION;
609 $wxr_site_url = $this->wxr_site_url();
610 $rss_info_name = get_bloginfo_rss( 'name' );
611 $rss_info_url = get_bloginfo_rss( 'url' );
612 $rss_info_description = get_bloginfo_rss( 'description' );
613 $rss_info_language = get_bloginfo_rss( 'language' );
614 $pub_date = gmdate( 'D, d M Y H:i:s +0000' );
615
616 $dynamic = $this->wxr_authors_list( $post_ids );
617
618 ob_start();
619 /** This action is documented in wp-includes/feed-rss2.php */
620 do_action( 'rss2_head' );
621 $rss2_head = ob_get_clean();
622
623 $dynamic .= $rss2_head;
624
625 $dynamic .= $this->wxr_terms_list( $this->wpexporter->get_terms( $post_ids ) );
626 $dynamic .= $this->wxr_posts_list( $post_ids );
627
628 $result = <<<EOT
629 <?xml version="1.0" encoding="$charset" ?>
630 <!-- This is a WordPress eXtended RSS file generated by WordPress as an export of your site. -->
631 <!-- It contains information about your site's posts, pages, comments, categories, and other content. -->
632 <!-- You may use this file to transfer that content from one site to another. -->
633 <!-- This file is not intended to serve as a complete backup of your site. -->
634
635 <!-- To import this information into a WordPress site follow these steps: -->
636 <!-- 1. Log in to that site as an administrator. -->
637 <!-- 2. Go to Tools: Import in the WordPress admin panel. -->
638 <!-- 3. Install the "WordPress" importer from the list. -->
639 <!-- 4. Activate & Run Importer. -->
640 <!-- 5. Upload this file using the form provided on that page. -->
641 <!-- 6. You will first be asked to map the authors in this export file to users -->
642 <!-- on the site. For each author, you may choose to map to an -->
643 <!-- existing user on the site or to create a new user. -->
644 <!-- 7. WordPress will then import each of the posts, pages, comments, categories, etc. -->
645 <!-- contained in this file into your site. -->
646 $generator
647 <rss version="2.0"
648 xmlns:excerpt="http://wordpress.org/export/$wxr_version/excerpt/"
649 xmlns:content="http://purl.org/rss/1.0/modules/content/"
650 xmlns:wfw="http://wellformedweb.org/CommentAPI/"
651 xmlns:dc="http://purl.org/dc/elements/1.1/"
652 xmlns:wp="http://wordpress.org/export/$wxr_version/"
653 >
654 <channel>
655 <title>$rss_info_name</title>
656 <link>$rss_info_url</link>
657 <description>$rss_info_description</description>
658 <pubDate>$pub_date</pubDate>
659 <language>$rss_info_language</language>
660 <wp:wxr_version>$wxr_version</wp:wxr_version>
661 <wp:base_site_url>$wxr_site_url</wp:base_site_url>
662 <wp:base_blog_url>$rss_info_url</wp:base_blog_url>
663 $dynamic
664 </channel>
665 </rss>
666 EOT;
667
668 return $result;
669 }
670 }
671