PluginProbe
BetterDocs – AI Documentation, Knowledge Base, MCP Server, Docs, Wikis, FAQ & Chatbot / 4.9.3
BetterDocs – AI Documentation, Knowledge Base, MCP Server, Docs, Wikis, FAQ & Chatbot v4.9.3
4.9.3 4.9.2 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 All 201 releases
betterdocs / includes / Admin / Importer / Parsers / WXR_Parser_XML.php

WXR_Parser_XML.php in BetterDocs – AI Documentation, Knowledge Base, MCP Server, Docs, Wikis, FAQ & Chatbot 4.9.3, at includes/Admin/Importer/Parsers/WXR_Parser_XML.php

372 lines 7.6 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\Importer\Parsers;
3
4 use Elementor\Utils;
5 use WP_Error;
6
7 if ( ! defined( 'ABSPATH' ) ) {
8 exit; // Exit if accessed directly.
9 }
10
11 /**
12 * WordPress extended RSS file parser implementations,
13 * Originally made by WordPress part of WordPress/Importer.
14 * https://plugins.trac.wordpress.org/browser/wordpress-importer/trunk/parsers/class-wxr-parser-xml.php
15 *
16 * What was done (by Elementor):
17 * Reformat of the code.
18 * Added PHPDOC.
19 * Changed text domain.
20 * Added clear() method.
21 * Added undeclared class properties.
22 * Changed methods visibility.
23 */
24
25 /**
26 * WXR Parser that makes use of the XML Parser PHP extension.
27 */
28 class WXR_Parser_XML {
29 private static $wp_tags = [
30 'wp:post_id',
31 'wp:post_date',
32 'wp:post_date_gmt',
33 'wp:comment_status',
34 'wp:ping_status',
35 'wp:attachment_url',
36 'wp:status',
37 'wp:post_name',
38 'wp:post_parent',
39 'wp:menu_order',
40 'wp:post_type',
41 'wp:post_password',
42 'wp:is_sticky',
43 'wp:term_id',
44 'wp:category_nicename',
45 'wp:category_parent',
46 'wp:cat_name',
47 'wp:category_description',
48 'wp:tag_slug',
49 'wp:tag_name',
50 'wp:tag_description',
51 'wp:term_taxonomy',
52 'wp:term_parent',
53 'wp:term_name',
54 'wp:term_description',
55 'wp:author_id',
56 'wp:author_login',
57 'wp:author_email',
58 'wp:author_display_name',
59 'wp:author_first_name',
60 'wp:author_last_name',
61 ];
62
63 private static $wp_sub_tags = [
64 'wp:comment_id',
65 'wp:comment_author',
66 'wp:comment_author_email',
67 'wp:comment_author_url',
68 'wp:comment_author_IP',
69 'wp:comment_date',
70 'wp:comment_date_gmt',
71 'wp:comment_content',
72 'wp:comment_approved',
73 'wp:comment_type',
74 'wp:comment_parent',
75 'wp:comment_user_id',
76 ];
77
78 /**
79 * @var string
80 */
81 private $wxr_version;
82
83 /**
84 * @var string
85 */
86 private $cdata;
87
88 /**
89 * @var array
90 */
91 private $data;
92
93 /**
94 * @var array
95 */
96 private $sub_data;
97
98 /**
99 * @var boolean
100 */
101 private $in_post;
102
103 /**
104 * @var boolean
105 */
106 private $in_tag;
107
108 /**
109 * @var boolean
110 */
111 private $in_sub_tag;
112
113 /**
114 * @var array
115 */
116 private $authors;
117
118 /**
119 * @var array
120 */
121 private $posts;
122
123 /**
124 * @var array
125 */
126 private $term;
127
128 /**
129 * @var array
130 */
131 private $category;
132
133 /**
134 * @var array
135 */
136 private $tag;
137
138 /**
139 * @var string
140 */
141 private $base_url;
142
143 /**
144 * @var string
145 */
146 private $base_blog_url;
147
148 /**
149 * @param string $file
150 *
151 * @return array|WP_Error
152 */
153 public function parse( $file ) {
154 $this->clear();
155
156 $xml = xml_parser_create( 'UTF-8' );
157 xml_parser_set_option( $xml, XML_OPTION_SKIP_WHITE, 1 );
158 xml_parser_set_option( $xml, XML_OPTION_CASE_FOLDING, 0 );
159 xml_set_object( $xml, $this );
160
161 xml_set_character_data_handler(
162 $xml,
163 function ( $parser, $cdata ) {
164 $this->cdata( $cdata );
165 }
166 );
167
168 $tag_open_callback = function ( $parse, $tag, $attr ) {
169 $this->tag_open( $tag, $attr );
170 };
171
172 $tag_close_callback = function ( $parser, $tag ) {
173 $this->tag_close( $tag );
174 };
175
176 xml_set_element_handler( $xml, $tag_open_callback, $tag_close_callback );
177
178 if ( ! xml_parse( $xml, Utils::file_get_contents( $file ), true ) ) {
179 $current_line = xml_get_current_line_number( $xml );
180 $current_column = xml_get_current_column_number( $xml );
181 $error_code = xml_get_error_code( $xml );
182 $error_string = xml_error_string( $error_code );
183
184 return new WP_Error(
185 'XML_parse_error',
186 'There was an error when reading this WXR file',
187 [
188 $current_line,
189 $current_column,
190 $error_string,
191 ]
192 );
193 }
194 xml_parser_free( $xml );
195
196 if ( ! preg_match( '/^\d+\.\d+$/', $this->wxr_version ) ) {
197 return new WP_Error( 'WXR_parse_error', esc_html__( 'This does not appear to be a WXR file, missing/invalid WXR version number', 'betterdocs' ) );
198 }
199
200 return array(
201 'authors' => $this->authors,
202 'posts' => $this->posts,
203 'categories' => $this->category,
204 'tags' => $this->tag,
205 'terms' => $this->term,
206 'base_url' => $this->base_url,
207 'base_blog_url' => $this->base_blog_url,
208 'version' => $this->wxr_version,
209 );
210 }
211
212 private function tag_open( $tag, $attr ) {
213 if ( in_array( $tag, self::$wp_tags ) ) {
214 $this->in_tag = substr( $tag, 3 );
215
216 return;
217 }
218
219 if ( in_array( $tag, self::$wp_sub_tags ) ) {
220 $this->in_sub_tag = substr( $tag, 3 );
221
222 return;
223 }
224
225 switch ( $tag ) {
226 case 'category':
227 if ( isset( $attr['domain'], $attr['nicename'] ) ) {
228 $this->sub_data['domain'] = $attr['domain'];
229 $this->sub_data['slug'] = $attr['nicename'];
230 }
231 break;
232 case 'item':
233 $this->in_post = true;
234 // No break !!!.
235 case 'title':
236 if ( $this->in_post ) {
237 $this->in_tag = 'post_title';
238 }
239 break;
240 case 'guid':
241 $this->in_tag = 'guid';
242 break;
243 case 'dc:creator':
244 $this->in_tag = 'post_author';
245 break;
246 case 'content:encoded':
247 $this->in_tag = 'post_content';
248 break;
249 case 'excerpt:encoded':
250 $this->in_tag = 'post_excerpt';
251 break;
252
253 case 'wp:term_slug':
254 $this->in_tag = 'slug';
255 break;
256 case 'wp:meta_key':
257 $this->in_sub_tag = 'key';
258 break;
259 case 'wp:meta_value':
260 $this->in_sub_tag = 'value';
261 break;
262 }
263 }
264
265 private function cdata( $cdata ) {
266 if ( ! trim( $cdata ) ) {
267 return;
268 }
269
270 if ( false !== $this->in_tag || false !== $this->in_sub_tag ) {
271 $this->cdata .= $cdata;
272 } else {
273 $this->cdata .= trim( $cdata );
274 }
275 }
276
277 private function tag_close( $tag ) {
278 switch ( $tag ) {
279 case 'wp:comment':
280 unset( $this->sub_data['key'], $this->sub_data['value'] ); // Remove meta sub_data.
281 if ( ! empty( $this->sub_data ) ) {
282 $this->data['comments'][] = $this->sub_data;
283 }
284 $this->sub_data = [];
285 break;
286 case 'wp:commentmeta':
287 $this->sub_data['commentmeta'][] = [
288 'key' => $this->sub_data['key'],
289 'value' => $this->sub_data['value'],
290 ];
291 break;
292 case 'category':
293 if ( ! empty( $this->sub_data ) ) {
294 $this->sub_data['name'] = $this->cdata;
295 $this->data['terms'][] = $this->sub_data;
296 }
297 $this->sub_data = [];
298 break;
299 case 'wp:postmeta':
300 if ( ! empty( $this->sub_data ) ) {
301 $this->data['postmeta'][] = $this->sub_data;
302 }
303 $this->sub_data = [];
304 break;
305 case 'item':
306 $this->posts[] = $this->data;
307 $this->data = [];
308 break;
309 case 'wp:category':
310 case 'wp:tag':
311 case 'wp:term':
312 $n = substr( $tag, 3 );
313 array_push( $this->$n, $this->data );
314 $this->data = [];
315 break;
316 case 'wp:termmeta':
317 if ( ! empty( $this->sub_data ) ) {
318 $this->data['termmeta'][] = $this->sub_data;
319 }
320 $this->sub_data = [];
321 break;
322 case 'wp:author':
323 if ( ! empty( $this->data['author_login'] ) ) {
324 $this->authors[ $this->data['author_login'] ] = $this->data;
325 }
326 $this->data = [];
327 break;
328 case 'wp:base_site_url':
329 $this->base_url = $this->cdata;
330 if ( ! isset( $this->base_blog_url ) ) {
331 $this->base_blog_url = $this->cdata;
332 }
333 break;
334 case 'wp:base_blog_url':
335 $this->base_blog_url = $this->cdata;
336 break;
337 case 'wp:wxr_version':
338 $this->wxr_version = $this->cdata;
339 break;
340
341 default:
342 if ( $this->in_sub_tag ) {
343 $this->sub_data[ $this->in_sub_tag ] = $this->cdata;
344 $this->in_sub_tag = false;
345 } elseif ( $this->in_tag ) {
346 $this->data[ $this->in_tag ] = $this->cdata;
347 $this->in_tag = false;
348 }
349 }
350
351 $this->cdata = '';
352 }
353
354 private function clear() {
355 $this->wxr_version = '';
356
357 $this->cdata = '';
358 $this->data = [];
359 $this->sub_data = [];
360
361 $this->in_post = false;
362 $this->in_tag = false;
363 $this->in_sub_tag = false;
364
365 $this->authors = [];
366 $this->posts = [];
367 $this->term = [];
368 $this->category = [];
369 $this->tag = [];
370 }
371 }
372