PluginProbe ʕ •ᴥ•ʔ
Royal Addons for Elementor – Addons and Templates Kit for Elementor / 1.7.1064
Royal Addons for Elementor – Addons and Templates Kit for Elementor v1.7.1064
1.7.1064 1.7.1063 1.7.1062 1.7.1061 1.7.1060 1.7.1059 1.7.1058 trunk 1.0.0 1.1.0 1.2 1.3 1.3.1 1.3.2 1.3.21 1.3.22 1.3.23 1.3.24 1.3.25 1.3.26 1.3.27 1.3.28 1.3.29 1.3.30 1.3.31 1.3.32 1.3.33 1.3.34 1.3.35 1.3.36 1.3.37 1.3.38 1.3.39 1.3.40 1.3.41 1.3.42 1.3.43 1.3.44 1.3.45 1.3.46 1.3.47 1.3.48 1.3.49 1.3.50 1.3.51 1.3.52 1.3.53 1.3.54 1.3.55 1.3.56 1.3.57 1.3.58 1.3.59 1.3.60 1.3.61 1.3.62 1.3.63 1.3.64 1.3.65 1.3.66 1.3.67 1.3.68 1.3.69 1.3.70 1.3.71 1.3.72 1.3.73 1.3.74 1.3.75 1.3.76 1.3.77 1.3.78 1.3.79 1.3.80 1.3.81 1.3.82 1.3.83 1.3.84 1.3.85 1.3.86 1.3.87 1.3.88 1.3.89 1.3.90 1.3.91 1.3.92 1.3.93 1.3.94 1.3.95 1.3.96 1.3.97 1.3.971 1.3.972 1.3.973 1.3.974 1.3.975 1.3.976 1.3.977 1.3.978 1.3.979 1.3.980 1.3.981 1.3.982 1.3.983 1.3.984 1.3.985 1.3.986 1.3.987 1.7.1 1.7.1001 1.7.1002 1.7.1003 1.7.1004 1.7.1005 1.7.1006 1.7.1007 1.7.1008 1.7.1009 1.7.1010 1.7.1011 1.7.1012 1.7.1013 1.7.1014 1.7.1015 1.7.1016 1.7.1017 1.7.1018 1.7.1019 1.7.1020 1.7.1021 1.7.1022 1.7.1023 1.7.1024 1.7.1025 1.7.1026 1.7.1027 1.7.1028 1.7.1029 1.7.1030 1.7.1031 1.7.1032 1.7.1033 1.7.1034 1.7.1035 1.7.1036 1.7.1037 1.7.1038 1.7.1039 1.7.1040 1.7.1041 1.7.1042 1.7.1043 1.7.1044 1.7.1045 1.7.1046 1.7.1047 1.7.1048 1.7.1049 1.7.1050 1.7.1051 1.7.1052 1.7.1053 1.7.1054 1.7.1055 1.7.1056 1.7.1057
royal-elementor-addons / admin / import / class-parsers.php
royal-elementor-addons / admin / import Last commit date
class-parsers.php 5 days ago class-wordpress-importer.php 5 days ago
class-parsers.php
1043 lines
1 <?php
2 if ( ! defined( 'ABSPATH' ) ) {
3 exit; // Exit if accessed directly.
4 }
5
6 /**
7 * WordPress eXtended RSS file parser implementations
8 *
9 * @package WordPress
10 * @subpackage Importer
11 */
12
13 /**
14 * WXR Parser that uses regular expressions. Fallback for installs without an XML parser.
15 */
16 class WXR_Parser_Regex {
17 /**
18 * @var bool
19 */
20 private $has_gzip;
21
22 private $authors = [];
23 private $posts = [];
24 private $categories = [];
25 private $tags = [];
26 private $terms = [];
27 private $base_url = '';
28 private $base_blog_url = '';
29
30 /**
31 * @param string $file
32 *
33 * @return array|\WP_Error
34 */
35 public function parse( $file ) {
36 $wxr_version = '';
37 $in_multiline = false;
38
39 $multiline_content = '';
40
41 $multiline_tags = [
42 'item' => [
43 'posts',
44 function ( $post ) {
45 return $this->process_post( $post );
46 },
47 ],
48 'wp:category' => [
49 'categories',
50 function ( $category ) {
51 return $this->process_category( $category );
52 },
53 ],
54 'wp:tag' => [
55 'tags',
56 function ( $tag ) {
57 return $this->process_tag( $tag );
58 },
59 ],
60 'wp:term' => [
61 'terms',
62 function ( $term ) {
63 return $this->process_term( $term );
64 },
65 ],
66 ];
67
68 $fp = $this->fopen( $file, 'r' );
69 if ( $fp ) {
70 while ( ! $this->feof( $fp ) ) {
71 $importline = rtrim( $this->fgets( $fp ) );
72
73 if ( ! $wxr_version && preg_match( '|<wp:wxr_version>(\d+\.\d+)</wp:wxr_version>|', $importline, $version ) ) {
74 $wxr_version = $version[1];
75 }
76
77 if ( false !== strpos( $importline, '<wp:base_site_url>' ) ) {
78 preg_match( '|<wp:base_site_url>(.*?)</wp:base_site_url>|is', $importline, $url );
79 $this->base_url = $url[1];
80 continue;
81 }
82
83 if ( false !== strpos( $importline, '<wp:base_blog_url>' ) ) {
84 preg_match( '|<wp:base_blog_url>(.*?)</wp:base_blog_url>|is', $importline, $blog_url );
85 $this->base_blog_url = $blog_url[1];
86 continue;
87 } else {
88 $this->base_blog_url = $this->base_url;
89 }
90
91 if ( false !== strpos( $importline, '<wp:author>' ) ) {
92 preg_match( '|<wp:author>(.*?)</wp:author>|is', $importline, $author );
93 $a = $this->process_author( $author[1] );
94 $this->authors[ $a['author_login'] ] = $a;
95 continue;
96 }
97
98 foreach ( $multiline_tags as $tag => $handler ) {
99 // Handle multi-line tags on a singular line.
100 if ( preg_match( '|<'. $tag .'>(.*?)</'. $tag .'>|is', $importline, $matches ) ) {
101 $this->{$handler[0]}[] = call_user_func( $handler[1], $matches[1] );
102
103 continue;
104 }
105
106 $pos = strpos( $importline, "<$tag>" );
107
108 if ( false !== $pos ) {
109 // Take note of any content after the opening tag.
110 $multiline_content = trim( substr( $importline, $pos + strlen( $tag ) + 2 ) );
111
112 // We don't want to have this line added to `$is_multiline` below.
113 $importline = '';
114 $in_multiline = $tag;
115
116 continue;
117 }
118
119 $pos = strpos( $importline, "</$tag>" );
120
121 if ( false !== $pos ) {
122 $in_multiline = false;
123 $multiline_content .= trim( substr( $importline, 0, $pos ) );
124
125 $this->{$handler[0]}[] = call_user_func( $handler[1], $multiline_content );
126 }
127 }
128
129 if ( $in_multiline && $importline ) {
130 $multiline_content .= $importline . "\n";
131 }
132 }
133
134 $this->fclose( $fp );
135 }
136
137 if ( ! $wxr_version ) {
138 return new WP_Error( 'WXR_parse_error', esc_html__( 'This does not appear to be a WXR file, missing/invalid WXR version number', 'wpr-addons' ) );
139 }
140
141 return [
142 'authors' => $this->authors,
143 'posts' => $this->posts,
144 'categories' => $this->categories,
145 'tags' => $this->tags,
146 'terms' => $this->terms,
147 'base_url' => $this->base_url,
148 'base_blog_url' => $this->base_blog_url,
149 'version' => $wxr_version,
150 ];
151 }
152
153 private function process_category( $category ) {
154 $term = [
155 'term_id' => $this->get_tag( $category, 'wp:term_id' ),
156 'cat_name' => $this->get_tag( $category, 'wp:cat_name' ),
157 'category_nicename' => $this->get_tag( $category, 'wp:category_nicename' ),
158 'category_parent' => $this->get_tag( $category, 'wp:category_parent' ),
159 'category_description' => $this->get_tag( $category, 'wp:category_description' ),
160 ];
161
162 $term_meta = $this->process_meta( $category, 'wp:termmeta' );
163 if ( ! empty( $term_meta ) ) {
164 $term['termmeta'] = $term_meta;
165 }
166
167 return $term;
168 }
169
170 private function process_tag( $tag ) {
171 $term = [
172 'term_id' => $this->get_tag( $tag, 'wp:term_id' ),
173 'tag_name' => $this->get_tag( $tag, 'wp:tag_name' ),
174 'tag_slug' => $this->get_tag( $tag, 'wp:tag_slug' ),
175 'tag_description' => $this->get_tag( $tag, 'wp:tag_description' ),
176 ];
177
178 $term_meta = $this->process_meta( $tag, 'wp:termmeta' );
179 if ( ! empty( $term_meta ) ) {
180 $term['termmeta'] = $term_meta;
181 }
182
183 return $term;
184 }
185
186 private function process_term( $term ) {
187 $term_data = [
188 'term_id' => $this->get_tag( $term, 'wp:term_id' ),
189 'term_taxonomy' => $this->get_tag( $term, 'wp:term_taxonomy' ),
190 'slug' => $this->get_tag( $term, 'wp:term_slug' ),
191 'term_parent' => $this->get_tag( $term, 'wp:term_parent' ),
192 'term_name' => $this->get_tag( $term, 'wp:term_name' ),
193 'term_description' => $this->get_tag( $term, 'wp:term_description' ),
194 ];
195
196 $term_meta = $this->process_meta( $term, 'wp:termmeta' );
197 if ( ! empty( $term_meta ) ) {
198 $term_data['termmeta'] = $term_meta;
199 }
200
201 return $term_data;
202 }
203
204 private function process_meta( $string, $tag ) {
205 $parsed_meta = [];
206
207 preg_match_all( "|<$tag>(.+?)</$tag>|is", $string, $meta );
208
209 if ( ! isset( $meta[1] ) ) {
210 return $parsed_meta;
211 }
212
213 foreach ( $meta[1] as $m ) {
214 $parsed_meta[] = [
215 'key' => $this->get_tag( $m, 'wp:meta_key' ),
216 'value' => $this->get_tag( $m, 'wp:meta_value' ),
217 ];
218 }
219
220 return $parsed_meta;
221 }
222
223 private function process_author( $a ) {
224 return [
225 'author_id' => $this->get_tag( $a, 'wp:author_id' ),
226 'author_login' => $this->get_tag( $a, 'wp:author_login' ),
227 'author_email' => $this->get_tag( $a, 'wp:author_email' ),
228 'author_display_name' => $this->get_tag( $a, 'wp:author_display_name' ),
229 'author_first_name' => $this->get_tag( $a, 'wp:author_first_name' ),
230 'author_last_name' => $this->get_tag( $a, 'wp:author_last_name' ),
231 ];
232 }
233
234 private function process_post( $post ) {
235 $normalize_tag_callback = function ( $matches ) {
236 return $this->normalize_tag( $matches );
237 };
238
239 $post_id = $this->get_tag( $post, 'wp:post_id' );
240 $post_title = $this->get_tag( $post, 'title' );
241 $post_date = $this->get_tag( $post, 'wp:post_date' );
242 $post_date_gmt = $this->get_tag( $post, 'wp:post_date_gmt' );
243 $comment_status = $this->get_tag( $post, 'wp:comment_status' );
244 $ping_status = $this->get_tag( $post, 'wp:ping_status' );
245 $status = $this->get_tag( $post, 'wp:status' );
246 $post_name = $this->get_tag( $post, 'wp:post_name' );
247 $post_parent = $this->get_tag( $post, 'wp:post_parent' );
248 $menu_order = $this->get_tag( $post, 'wp:menu_order' );
249 $post_type = $this->get_tag( $post, 'wp:post_type' );
250 $post_password = $this->get_tag( $post, 'wp:post_password' );
251 $is_sticky = $this->get_tag( $post, 'wp:is_sticky' );
252 $guid = $this->get_tag( $post, 'guid' );
253 $post_author = $this->get_tag( $post, 'dc:creator' );
254
255 $post_excerpt = $this->get_tag( $post, 'excerpt:encoded' );
256 $post_excerpt = preg_replace_callback( '|<(/?[A-Z]+)|', $normalize_tag_callback, $post_excerpt );
257 $post_excerpt = str_replace( '<br>', '<br />', $post_excerpt );
258 $post_excerpt = str_replace( '<hr>', '<hr />', $post_excerpt );
259
260 $post_content = $this->get_tag( $post, 'content:encoded' );
261 $post_content = preg_replace_callback( '|<(/?[A-Z]+)|', $normalize_tag_callback, $post_content );
262 $post_content = str_replace( '<br>', '<br />', $post_content );
263 $post_content = str_replace( '<hr>', '<hr />', $post_content );
264
265 $postdata = compact( 'post_id', 'post_author', 'post_date', 'post_date_gmt', 'post_content', 'post_excerpt', 'post_title', 'status', 'post_name', 'comment_status', 'ping_status', 'guid', 'post_parent', 'menu_order', 'post_type', 'post_password', 'is_sticky' );
266
267 $attachment_url = $this->get_tag( $post, 'wp:attachment_url' );
268 if ( $attachment_url ) {
269 $postdata['attachment_url'] = $attachment_url;
270 }
271
272 preg_match_all( '|<category domain="([^"]+?)" nicename="([^"]+?)">(.+?)</category>|is', $post, $terms, PREG_SET_ORDER );
273 foreach ( $terms as $t ) {
274 $post_terms[] = [
275 'slug' => $t[2],
276 'domain' => $t[1],
277 'name' => str_replace( [ '<![CDATA[', ']]>' ], '', $t[3] ),
278 ];
279 }
280 if ( ! empty( $post_terms ) ) {
281 $postdata['terms'] = $post_terms;
282 }
283
284 preg_match_all( '|<wp:comment>(.+?)</wp:comment>|is', $post, $comments );
285 $comments = $comments[1];
286 if ( $comments ) {
287 foreach ( $comments as $comment ) {
288 $post_comments[] = [
289 'comment_id' => $this->get_tag( $comment, 'wp:comment_id' ),
290 'comment_author' => $this->get_tag( $comment, 'wp:comment_author' ),
291 'comment_author_email' => $this->get_tag( $comment, 'wp:comment_author_email' ),
292 'comment_author_IP' => $this->get_tag( $comment, 'wp:comment_author_IP' ),
293 'comment_author_url' => $this->get_tag( $comment, 'wp:comment_author_url' ),
294 'comment_date' => $this->get_tag( $comment, 'wp:comment_date' ),
295 'comment_date_gmt' => $this->get_tag( $comment, 'wp:comment_date_gmt' ),
296 'comment_content' => $this->get_tag( $comment, 'wp:comment_content' ),
297 'comment_approved' => $this->get_tag( $comment, 'wp:comment_approved' ),
298 'comment_type' => $this->get_tag( $comment, 'wp:comment_type' ),
299 'comment_parent' => $this->get_tag( $comment, 'wp:comment_parent' ),
300 'comment_user_id' => $this->get_tag( $comment, 'wp:comment_user_id' ),
301 'commentmeta' => $this->process_meta( $comment, 'wp:commentmeta' ),
302 ];
303 }
304 }
305 if ( ! empty( $post_comments ) ) {
306 $postdata['comments'] = $post_comments;
307 }
308
309 $post_meta = $this->process_meta( $post, 'wp:postmeta' );
310 if ( ! empty( $post_meta ) ) {
311 $postdata['postmeta'] = $post_meta;
312 }
313
314 return $postdata;
315 }
316
317 private function get_tag( $string, $tag ) {
318 preg_match( "|<$tag.*?>(.*?)</$tag>|is", $string, $return );
319 if ( isset( $return[1] ) ) {
320 if ( substr( $return[1], 0, 9 ) == '<![CDATA[' ) {
321 if ( strpos( $return[1], ']]]]><![CDATA[>' ) !== false ) {
322 preg_match_all( '|<!\[CDATA\[(.*?)\]\]>|s', $return[1], $matches );
323 $return = '';
324 foreach ( $matches[1] as $match ) {
325 $return .= $match;
326 }
327 } else {
328 $return = preg_replace( '|^<!\[CDATA\[(.*)\]\]>$|s', '$1', $return[1] );
329 }
330 } else {
331 $return = $return[1];
332 }
333 } else {
334 $return = '';
335 }
336
337 return $return;
338 }
339
340 private function normalize_tag( $matches ) {
341 return '<' . strtolower( $matches[1] );
342 }
343
344 private function fopen( $filename, $mode = 'r' ) {
345 if ( $this->has_gzip ) {
346 return gzopen( $filename, $mode );
347 }
348
349 return fopen( $filename, $mode );
350 }
351
352 private function feof( $fp ) {
353 if ( $this->has_gzip ) {
354 return gzeof( $fp );
355 }
356
357 return feof( $fp );
358 }
359
360 private function fgets( $fp, $len = 8192 ) {
361 if ( $this->has_gzip ) {
362 return gzgets( $fp, $len );
363 }
364
365 return fgets( $fp, $len );
366 }
367
368 private function fclose( $fp ) {
369 if ( $this->has_gzip ) {
370 return gzclose( $fp );
371 }
372
373 return fclose( $fp );
374 }
375
376 public function __construct() {
377 $this->has_gzip = is_callable( 'gzopen' );
378 }
379 }
380
381 /**
382 * WordPress eXtended RSS file parser implementations,
383 * Originally made by WordPress part of WordPress/Importer.
384 * https://plugins.trac.wordpress.org/browser/wordpress-importer/trunk/parsers/class-wxr-parser-simplexml.php
385 *
386 * What was done:
387 * Reformat of the code.
388 * Removed variable '$internal_errors'.
389 * Changed text domain.
390 */
391
392 /**
393 * WXR Parser that makes use of the SimpleXML PHP extension.
394 */
395 class WXR_Parser_SimpleXML {
396
397 /**
398 * @param string $file
399 *
400 * @return array|\WP_Error
401 */
402 public function parse( $file ) {
403 $authors = [];
404 $posts = [];
405 $categories = [];
406 $tags = [];
407 $terms = [];
408
409 libxml_use_internal_errors( true );
410
411 $dom = new \DOMDocument();
412 $old_value = null;
413
414 $libxml_disable_entity_loader_exists = function_exists( 'libxml_disable_entity_loader' );
415
416 if ( PHP_VERSION_ID < 80000 && $libxml_disable_entity_loader_exists ) {
417 // Only call libxml_disable_entity_loader() for PHP versions before 8.0
418 $old_value = libxml_disable_entity_loader( true ); // phpcs:ignore Generic.PHP.DeprecatedFunctions.Deprecated
419 }
420
421 $success = $dom->loadXML( file_get_contents( $file ) );
422
423 if ( PHP_VERSION_ID < 80000 && $libxml_disable_entity_loader_exists && ! is_null( $old_value ) ) {
424 libxml_disable_entity_loader( $old_value ); // phpcs:ignore Generic.PHP.DeprecatedFunctions.Deprecated
425 }
426
427 if ( ! $success || isset( $dom->doctype ) ) {
428 return new WP_Error( 'SimpleXML_parse_error', esc_html__( 'There was an error when reading this WXR file', 'wpr-addons' ), libxml_get_errors() );
429 }
430
431 $xml = simplexml_import_dom( $dom );
432 unset( $dom );
433
434 // Halt if loading produces an error.
435 if ( ! $xml ) {
436 return new WP_Error( 'SimpleXML_parse_error', esc_html__( 'There was an error when reading this WXR file', 'wpr-addons' ), libxml_get_errors() );
437 }
438
439 $wxr_version = $xml->xpath( '/rss/channel/wp:wxr_version' );
440 if ( ! $wxr_version ) {
441 return new WP_Error( 'WXR_parse_error', esc_html__( 'This does not appear to be a WXR file, missing/invalid WXR version number', 'wpr-addons' ) );
442 }
443
444 $wxr_version = (string) trim( $wxr_version[0] );
445 // Confirm that we are dealing with the correct file format.
446 if ( ! preg_match( '/^\d+\.\d+$/', $wxr_version ) ) {
447 return new WP_Error( 'WXR_parse_error', esc_html__( 'This does not appear to be a WXR file, missing/invalid WXR version number', 'wpr-addons' ) );
448 }
449
450 $base_url = $xml->xpath( '/rss/channel/wp:base_site_url' );
451 $base_url = (string) trim( isset( $base_url[0] ) ? $base_url[0] : '' );
452
453 $base_blog_url = $xml->xpath( '/rss/channel/wp:base_blog_url' );
454 if ( $base_blog_url ) {
455 $base_blog_url = (string) trim( $base_blog_url[0] );
456 } else {
457 $base_blog_url = $base_url;
458 }
459
460 $page_on_front = $xml->xpath( '/rss/channel/wp:page_on_front' );
461
462 if ( $page_on_front ) {
463 $page_on_front = (int) $page_on_front[0];
464 }
465
466 $namespaces = $xml->getDocNamespaces();
467 if ( ! isset( $namespaces['wp'] ) ) {
468 $namespaces['wp'] = 'http://wordpress.org/export/1.1/';
469 }
470 if ( ! isset( $namespaces['excerpt'] ) ) {
471 $namespaces['excerpt'] = 'http://wordpress.org/export/1.1/excerpt/';
472 }
473
474 // Grab authors.
475 foreach ( $xml->xpath( '/rss/channel/wp:author' ) as $author_arr ) {
476 $a = $author_arr->children( $namespaces['wp'] );
477 $login = (string) $a->author_login;
478 $authors[ $login ] = [
479 'author_id' => (int) $a->author_id,
480 'author_login' => $login,
481 'author_email' => (string) $a->author_email,
482 'author_display_name' => (string) $a->author_display_name,
483 'author_first_name' => (string) $a->author_first_name,
484 'author_last_name' => (string) $a->author_last_name,
485 ];
486 }
487
488 // Grab cats, tags and terms.
489 foreach ( $xml->xpath( '/rss/channel/wp:category' ) as $term_arr ) {
490 $t = $term_arr->children( $namespaces['wp'] );
491 $category = [
492 'term_id' => (int) $t->term_id,
493 'category_nicename' => (string) $t->category_nicename,
494 'category_parent' => (string) $t->category_parent,
495 'cat_name' => (string) $t->cat_name,
496 'category_description' => (string) $t->category_description,
497 ];
498
499 foreach ( $t->termmeta as $meta ) {
500 $category['termmeta'][] = [
501 'key' => (string) $meta->meta_key,
502 'value' => (string) $meta->meta_value,
503 ];
504 }
505
506 $categories[] = $category;
507 }
508
509 foreach ( $xml->xpath( '/rss/channel/wp:tag' ) as $term_arr ) {
510 $t = $term_arr->children( $namespaces['wp'] );
511 $tag = [
512 'term_id' => (int) $t->term_id,
513 'tag_slug' => (string) $t->tag_slug,
514 'tag_name' => (string) $t->tag_name,
515 'tag_description' => (string) $t->tag_description,
516 ];
517
518 foreach ( $t->termmeta as $meta ) {
519 $tag['termmeta'][] = [
520 'key' => (string) $meta->meta_key,
521 'value' => (string) $meta->meta_value,
522 ];
523 }
524
525 $tags[] = $tag;
526 }
527
528 foreach ( $xml->xpath( '/rss/channel/wp:term' ) as $term_arr ) {
529 $t = $term_arr->children( $namespaces['wp'] );
530 $term = [
531 'term_id' => (int) $t->term_id,
532 'term_taxonomy' => (string) $t->term_taxonomy,
533 'slug' => (string) $t->term_slug,
534 'term_parent' => (string) $t->term_parent,
535 'term_name' => (string) $t->term_name,
536 'term_description' => (string) $t->term_description,
537 ];
538
539 foreach ( $t->termmeta as $meta ) {
540 $term['termmeta'][] = [
541 'key' => (string) $meta->meta_key,
542 'value' => (string) $meta->meta_value,
543 ];
544 }
545
546 $terms[] = $term;
547 }
548
549 // Grab posts.
550 foreach ( $xml->channel->item as $item ) {
551 $post = [
552 'post_title' => (string) $item->title,
553 'guid' => (string) $item->guid,
554 ];
555
556 $dc = $item->children( 'http://purl.org/dc/elements/1.1/' );
557 $post['post_author'] = (string) $dc->creator;
558
559 $content = $item->children( 'http://purl.org/rss/1.0/modules/content/' );
560 $excerpt = $item->children( $namespaces['excerpt'] );
561 $post['post_content'] = (string) $content->encoded;
562 $post['post_excerpt'] = (string) $excerpt->encoded;
563
564 $wp = $item->children( $namespaces['wp'] );
565 $post['post_id'] = (int) $wp->post_id;
566 $post['post_date'] = (string) $wp->post_date;
567 $post['post_date_gmt'] = (string) $wp->post_date_gmt;
568 $post['comment_status'] = (string) $wp->comment_status;
569 $post['ping_status'] = (string) $wp->ping_status;
570 $post['post_name'] = (string) $wp->post_name;
571 $post['status'] = (string) $wp->status;
572 $post['post_parent'] = (int) $wp->post_parent;
573 $post['menu_order'] = (int) $wp->menu_order;
574 $post['post_type'] = (string) $wp->post_type;
575 $post['post_password'] = (string) $wp->post_password;
576 $post['is_sticky'] = (int) $wp->is_sticky;
577
578 if ( isset( $wp->attachment_url ) ) {
579 $post['attachment_url'] = (string) $wp->attachment_url;
580 }
581
582 foreach ( $item->category as $c ) {
583 $att = $c->attributes();
584 if ( isset( $att['nicename'] ) ) {
585 $post['terms'][] = [
586 'name' => (string) $c,
587 'slug' => (string) $att['nicename'],
588 'domain' => (string) $att['domain'],
589 ];
590 }
591 }
592
593 foreach ( $wp->postmeta as $meta ) {
594 $post['postmeta'][] = [
595 'key' => (string) $meta->meta_key,
596 'value' => (string) $meta->meta_value,
597 ];
598 }
599
600 foreach ( $wp->comment as $comment ) {
601 $meta = [];
602 if ( isset( $comment->commentmeta ) ) {
603 foreach ( $comment->commentmeta as $m ) {
604 $meta[] = [
605 'key' => (string) $m->meta_key,
606 'value' => (string) $m->meta_value,
607 ];
608 }
609 }
610
611 $post['comments'][] = [
612 'comment_id' => (int) $comment->comment_id,
613 'comment_author' => (string) $comment->comment_author,
614 'comment_author_email' => (string) $comment->comment_author_email,
615 'comment_author_IP' => (string) $comment->comment_author_IP,
616 'comment_author_url' => (string) $comment->comment_author_url,
617 'comment_date' => (string) $comment->comment_date,
618 'comment_date_gmt' => (string) $comment->comment_date_gmt,
619 'comment_content' => (string) $comment->comment_content,
620 'comment_approved' => (string) $comment->comment_approved,
621 'comment_type' => (string) $comment->comment_type,
622 'comment_parent' => (string) $comment->comment_parent,
623 'comment_user_id' => (int) $comment->comment_user_id,
624 'commentmeta' => $meta,
625 ];
626 }
627
628 $posts[] = $post;
629 }
630
631 return [
632 'authors' => $authors,
633 'posts' => $posts,
634 'categories' => $categories,
635 'tags' => $tags,
636 'terms' => $terms,
637 'base_url' => $base_url,
638 'base_blog_url' => $base_blog_url,
639 'page_on_front' => $page_on_front,
640 'version' => $wxr_version,
641 ];
642 }
643 }
644
645
646 /**
647 * WordPress eXtended RSS file parser implementations,
648 * Originally made by WordPress part of WordPress/Importer.
649 * https://plugins.trac.wordpress.org/browser/wordpress-importer/trunk/parsers/class-wxr-parser-xml.php
650 *
651 * What was done:
652 * Reformat of the code.
653 * Added PHPDOC.
654 * Changed text domain.
655 * Added clear() method.
656 * Added undeclared class properties.
657 * Changed methods visibility.
658 */
659
660 /**
661 * WXR Parser that makes use of the XML Parser PHP extension.
662 */
663 class WXR_Parser_XML {
664 private static $wp_tags = [
665 'wp:post_id',
666 'wp:post_date',
667 'wp:post_date_gmt',
668 'wp:comment_status',
669 'wp:ping_status',
670 'wp:attachment_url',
671 'wp:status',
672 'wp:post_name',
673 'wp:post_parent',
674 'wp:menu_order',
675 'wp:post_type',
676 'wp:post_password',
677 'wp:is_sticky',
678 'wp:term_id',
679 'wp:category_nicename',
680 'wp:category_parent',
681 'wp:cat_name',
682 'wp:category_description',
683 'wp:tag_slug',
684 'wp:tag_name',
685 'wp:tag_description',
686 'wp:term_taxonomy',
687 'wp:term_parent',
688 'wp:term_name',
689 'wp:term_description',
690 'wp:author_id',
691 'wp:author_login',
692 'wp:author_email',
693 'wp:author_display_name',
694 'wp:author_first_name',
695 'wp:author_last_name',
696 ];
697
698 private static $wp_sub_tags = [
699 'wp:comment_id',
700 'wp:comment_author',
701 'wp:comment_author_email',
702 'wp:comment_author_url',
703 'wp:comment_author_IP',
704 'wp:comment_date',
705 'wp:comment_date_gmt',
706 'wp:comment_content',
707 'wp:comment_approved',
708 'wp:comment_type',
709 'wp:comment_parent',
710 'wp:comment_user_id',
711 ];
712
713 /**
714 * @var string
715 */
716 private $wxr_version;
717
718 /**
719 * @var string
720 */
721 private $cdata;
722
723 /**
724 * @var array
725 */
726 private $data;
727
728 /**
729 * @var array
730 */
731 private $sub_data;
732
733 /**
734 * @var boolean
735 */
736 private $in_post;
737
738 /**
739 * @var boolean
740 */
741 private $in_tag;
742
743 /**
744 * @var boolean
745 */
746 private $in_sub_tag;
747
748 /**
749 * @var array
750 */
751 private $authors;
752
753 /**
754 * @var array
755 */
756 private $posts;
757
758 /**
759 * @var array
760 */
761 private $term;
762
763 /**
764 * @var array
765 */
766 private $category;
767
768 /**
769 * @var array
770 */
771 private $tag;
772
773 /**
774 * @var string
775 */
776 private $base_url;
777
778 /**
779 * @var string
780 */
781 private $base_blog_url;
782
783 /**
784 * @param string $file
785 *
786 * @return array|WP_Error
787 */
788 public function parse( $file ) {
789 $this->clear();
790
791 $xml = xml_parser_create( 'UTF-8' );
792 xml_parser_set_option( $xml, XML_OPTION_SKIP_WHITE, 1 );
793 xml_parser_set_option( $xml, XML_OPTION_CASE_FOLDING, 0 );
794 xml_set_object( $xml, $this );
795
796 xml_set_character_data_handler( $xml, function ( $parser, $cdata ) {
797 $this->cdata( $cdata );
798 } );
799
800 $tag_open_callback = function ( $parse, $tag, $attr ) {
801 $this->tag_open( $tag, $attr );
802 };
803
804 $tag_close_callback = function ( $parser, $tag ) {
805 $this->tag_close( $tag );
806 };
807
808 xml_set_element_handler( $xml, $tag_open_callback, $tag_close_callback );
809
810 if ( ! xml_parse( $xml, file_get_contents( $file ), true ) ) {
811 $current_line = xml_get_current_line_number( $xml );
812 $current_column = xml_get_current_column_number( $xml );
813 $error_code = xml_get_error_code( $xml );
814 $error_string = xml_error_string( $error_code );
815
816 return new WP_Error( 'XML_parse_error', 'There was an error when reading this WXR file', [
817 $current_line,
818 $current_column,
819 $error_string,
820 ] );
821 }
822 xml_parser_free( $xml );
823
824 if ( ! preg_match( '/^\d+\.\d+$/', $this->wxr_version ) ) {
825 return new WP_Error( 'WXR_parse_error', esc_html__( 'This does not appear to be a WXR file, missing/invalid WXR version number', 'wpr-addons' ) );
826 }
827
828 return array(
829 'authors' => $this->authors,
830 'posts' => $this->posts,
831 'categories' => $this->category,
832 'tags' => $this->tag,
833 'terms' => $this->term,
834 'base_url' => $this->base_url,
835 'base_blog_url' => $this->base_blog_url,
836 'version' => $this->wxr_version,
837 );
838 }
839
840 private function tag_open( $tag, $attr ) {
841 if ( in_array( $tag, self::$wp_tags ) ) {
842 $this->in_tag = substr( $tag, 3 );
843
844 return;
845 }
846
847 if ( in_array( $tag, self::$wp_sub_tags ) ) {
848 $this->in_sub_tag = substr( $tag, 3 );
849
850 return;
851 }
852
853 switch ( $tag ) {
854 case 'category':
855 if ( isset( $attr['domain'], $attr['nicename'] ) ) {
856 $this->sub_data['domain'] = $attr['domain'];
857 $this->sub_data['slug'] = $attr['nicename'];
858 }
859 break;
860 case 'item':
861 $this->in_post = true;
862 // No break !!!.
863 case 'title':
864 if ( $this->in_post ) {
865 $this->in_tag = 'post_title';
866 }
867 break;
868 case 'guid':
869 $this->in_tag = 'guid';
870 break;
871 case 'dc:creator':
872 $this->in_tag = 'post_author';
873 break;
874 case 'content:encoded':
875 $this->in_tag = 'post_content';
876 break;
877 case 'excerpt:encoded':
878 $this->in_tag = 'post_excerpt';
879 break;
880
881 case 'wp:term_slug':
882 $this->in_tag = 'slug';
883 break;
884 case 'wp:meta_key':
885 $this->in_sub_tag = 'key';
886 break;
887 case 'wp:meta_value':
888 $this->in_sub_tag = 'value';
889 break;
890 }
891 }
892
893 private function cdata( $cdata ) {
894 if ( ! trim( $cdata ) ) {
895 return;
896 }
897
898 if ( false !== $this->in_tag || false !== $this->in_sub_tag ) {
899 $this->cdata .= $cdata;
900 } else {
901 $this->cdata .= trim( $cdata );
902 }
903 }
904
905 private function tag_close( $tag ) {
906 switch ( $tag ) {
907 case 'wp:comment':
908 unset( $this->sub_data['key'], $this->sub_data['value'] ); // Remove meta sub_data.
909 if ( ! empty( $this->sub_data ) ) {
910 $this->data['comments'][] = $this->sub_data;
911 }
912 $this->sub_data = [];
913 break;
914 case 'wp:commentmeta':
915 $this->sub_data['commentmeta'][] = [
916 'key' => $this->sub_data['key'],
917 'value' => $this->sub_data['value'],
918 ];
919 break;
920 case 'category':
921 if ( ! empty( $this->sub_data ) ) {
922 $this->sub_data['name'] = $this->cdata;
923 $this->data['terms'][] = $this->sub_data;
924 }
925 $this->sub_data = [];
926 break;
927 case 'wp:postmeta':
928 if ( ! empty( $this->sub_data ) ) {
929 $this->data['postmeta'][] = $this->sub_data;
930 }
931 $this->sub_data = [];
932 break;
933 case 'item':
934 $this->posts[] = $this->data;
935 $this->data = [];
936 break;
937 case 'wp:category':
938 case 'wp:tag':
939 case 'wp:term':
940 $n = substr( $tag, 3 );
941 array_push( $this->$n, $this->data );
942 $this->data = [];
943 break;
944 case 'wp:termmeta':
945 if ( ! empty( $this->sub_data ) ) {
946 $this->data['termmeta'][] = $this->sub_data;
947 }
948 $this->sub_data = [];
949 break;
950 case 'wp:author':
951 if ( ! empty( $this->data['author_login'] ) ) {
952 $this->authors[ $this->data['author_login'] ] = $this->data;
953 }
954 $this->data = [];
955 break;
956 case 'wp:base_site_url':
957 $this->base_url = $this->cdata;
958 if ( ! isset( $this->base_blog_url ) ) {
959 $this->base_blog_url = $this->cdata;
960 }
961 break;
962 case 'wp:base_blog_url':
963 $this->base_blog_url = $this->cdata;
964 break;
965 case 'wp:wxr_version':
966 $this->wxr_version = $this->cdata;
967 break;
968
969 default:
970 if ( $this->in_sub_tag ) {
971 $this->sub_data[ $this->in_sub_tag ] = $this->cdata;
972 $this->in_sub_tag = false;
973 } elseif ( $this->in_tag ) {
974 $this->data[ $this->in_tag ] = $this->cdata;
975 $this->in_tag = false;
976 }
977 }
978
979 $this->cdata = '';
980 }
981
982 private function clear() {
983 $this->wxr_version = '';
984
985 $this->cdata = '';
986 $this->data = [];
987 $this->sub_data = [];
988
989 $this->in_post = false;
990 $this->in_tag = false;
991 $this->in_sub_tag = false;
992
993 $this->authors = [];
994 $this->posts = [];
995 $this->term = [];
996 $this->category = [];
997 $this->tag = [];
998 }
999 }
1000
1001
1002 /**
1003 * WordPress eXtended RSS file parser implementations,
1004 * Originally made by WordPress part of WordPress/Importer.
1005 * https://plugins.trac.wordpress.org/browser/wordpress-importer/trunk/parsers/class-wxr-parser.php
1006 *
1007 * What was done:
1008 * Reformat of the code.
1009 * Changed text domain.
1010 */
1011
1012 /**
1013 * WordPress Importer class for managing parsing of WXR files.
1014 */
1015 class WXR_Parser {
1016
1017 public function parse( $file ) {
1018 // Attempt to use proper XML parsers first.
1019 if ( extension_loaded( 'simplexml' ) ) {
1020 $parser = new WXR_Parser_SimpleXML();
1021 $result = $parser->parse( $file );
1022
1023 // If SimpleXML succeeds or this is an invalid WXR file then return the results.
1024 if ( ! is_wp_error( $result ) || 'SimpleXML_parse_error' != $result->get_error_code() ) {
1025 return $result;
1026 }
1027 } elseif ( extension_loaded( 'xml' ) ) {
1028 $parser = new WXR_Parser_XML();
1029 $result = $parser->parse( $file );
1030
1031 // If XMLParser succeeds or this is an invalid WXR file then return the results.
1032 if ( ! is_wp_error( $result ) || 'XML_parse_error' != $result->get_error_code() ) {
1033 return $result;
1034 }
1035 }
1036
1037 // Use regular expressions if nothing else available or this is bad XML.
1038 $parser = new WXR_Parser_Regex();
1039
1040 return $parser->parse( $file );
1041 }
1042 }
1043