Diff: STRATO-apps/wordpress_03/app/wp-content/plugins/elementor/includes/db.php

Keine Baseline-Datei – Diff nur gegen leer.
Zur Liste
1 -
1 + <?php
2 + namespace Elementor;
3 +
4 + use Elementor\Core\Base\Document;
5 + use Elementor\Core\DynamicTags\Manager;
6 + use Elementor\TemplateLibrary\Source_Local;
7 +
8 + if ( ! defined( 'ABSPATH' ) ) {
9 + exit; // Exit if accessed directly.
10 + }
11 +
12 + /**
13 + * Elementor database.
14 + *
15 + * Elementor database handler class is responsible for communicating with the
16 + * DB, save and retrieve Elementor data and meta data.
17 + *
18 + * @since 1.0.0
19 + */
20 + class DB {
21 +
22 + /**
23 + * Current DB version of the editor.
24 + */
25 + const DB_VERSION = '0.4';
26 +
27 + /**
28 + * Post publish status.
29 + *
30 + * @deprecated 3.1.0 Use `Document::STATUS_PUBLISH` const instead.
31 + */
32 + const STATUS_PUBLISH = Document::STATUS_PUBLISH;
33 +
34 + /**
35 + * Post draft status.
36 + *
37 + * @deprecated 3.1.0 Use `Document::STATUS_DRAFT` const instead.
38 + */
39 + const STATUS_DRAFT = Document::STATUS_DRAFT;
40 +
41 + /**
42 + * Post private status.
43 + *
44 + * @deprecated 3.1.0 Use `Document::STATUS_PRIVATE` const instead.
45 + */
46 + const STATUS_PRIVATE = Document::STATUS_PRIVATE;
47 +
48 + /**
49 + * Post autosave status.
50 + *
51 + * @deprecated 3.1.0 Use `Document::STATUS_AUTOSAVE` const instead.
52 + */
53 + const STATUS_AUTOSAVE = Document::STATUS_AUTOSAVE;
54 +
55 + /**
56 + * Post pending status.
57 + *
58 + * @deprecated 3.1.0 Use `Document::STATUS_PENDING` const instead.
59 + */
60 + const STATUS_PENDING = Document::STATUS_PENDING;
61 +
62 + /**
63 + * Switched post data.
64 + *
65 + * Holds the switched post data.
66 + *
67 + * @since 1.5.0
68 + * @access protected
69 + *
70 + * @var array Switched post data. Default is an empty array.
71 + */
72 + protected $switched_post_data = [];
73 +
74 + /**
75 + * Switched data.
76 + *
77 + * Holds the switched data.
78 + *
79 + * @since 2.0.0
80 + * @access protected
81 + *
82 + * @var array Switched data. Default is an empty array.
83 + */
84 + protected $switched_data = [];
85 +
86 + /**
87 + * Get builder.
88 + *
89 + * Retrieve editor data from the database.
90 + *
91 + * @since 1.0.0
92 + * @deprecated 3.1.0 Use `Plugin::$instance->documents->get( $post_id )->get_elements_raw_data( null, true )` OR `Plugin::$instance->documents->get_doc_or_auto_save( $post_id )->get_elements_raw_data( null, true )` instead.
93 + * @access public
94 + *
95 + * @param int $post_id Post ID.
96 + * @param string $status Optional. Post status. Default is `publish`.
97 + *
98 + * @return array Editor data.
99 + */
100 + public function get_builder( $post_id, $status = Document::STATUS_PUBLISH ) {
101 + Plugin::$instance->modules_manager
102 + ->get_modules( 'dev-tools' )
103 + ->deprecation
104 + ->deprecated_function(
105 + __METHOD__,
106 + '3.1.0',
107 + '`Plugin::$instance->documents->get( $post_id )->get_elements_raw_data( null, true )` OR `Plugin::$instance->documents->get_doc_or_auto_save( $post_id )->get_elements_raw_data( null, true )`'
108 + );
109 +
110 + if ( Document::STATUS_DRAFT === $status ) {
111 + $document = Plugin::$instance->documents->get_doc_or_auto_save( $post_id );
112 + } else {
113 + $document = Plugin::$instance->documents->get( $post_id );
114 + }
115 +
116 + if ( $document ) {
117 + $editor_data = $document->get_elements_raw_data( null, true );
118 + } else {
119 + $editor_data = [];
120 + }
121 +
122 + return $editor_data;
123 + }
124 +
125 + /**
126 + * Get JSON meta.
127 + *
128 + * Retrieve post meta data, and return the JSON decoded data.
129 + *
130 + * @since 1.0.0
131 + * @access protected
132 + *
133 + * @param int $post_id Post ID.
134 + * @param string $key The meta key to retrieve.
135 + *
136 + * @return array Decoded JSON data from post meta.
137 + */
138 + protected function _get_json_meta( $post_id, $key ) {
139 + Plugin::$instance->modules_manager->get_modules( 'dev-tools' )->deprecation->deprecated_function( __METHOD__, '3.1.0' );
140 +
141 + $meta = get_post_meta( $post_id, $key, true );
142 +
143 + if ( is_string( $meta ) && ! empty( $meta ) ) {
144 + $meta = json_decode( $meta, true );
145 + }
146 +
147 + if ( empty( $meta ) ) {
148 + $meta = [];
149 + }
150 +
151 + return $meta;
152 + }
153 +
154 + /**
155 + * Is using Elementor.
156 + *
157 + * Set whether the page is using Elementor or not.
158 + *
159 + * @since 1.5.0
160 + * @deprecated 3.1.0 Use `Plugin::$instance->documents->get( $post_id )->set_is_build_with_elementor( $is_elementor )` instead.
161 + * @access public
162 + *
163 + * @param int $post_id Post ID.
164 + * @param bool $is_elementor Optional. Whether the page is elementor page.
165 + * Default is true.
166 + */
167 + public function set_is_elementor_page( $post_id, $is_elementor = true ) {
168 + Plugin::$instance->modules_manager
169 + ->get_modules( 'dev-tools' )
170 + ->deprecation
171 + ->deprecated_function(
172 + __METHOD__,
173 + '3.1.0',
174 + 'Plugin::$instance->documents->get( $post_id )->set_is_build_with_elementor( $is_elementor )'
175 + );
176 +
177 + $document = Plugin::$instance->documents->get( $post_id );
178 +
179 + if ( ! $document ) {
180 + return;
181 + }
182 +
183 + $document->set_is_built_with_elementor( $is_elementor );
184 + }
185 +
186 + /**
187 + * Render element plain content.
188 + *
189 + * When saving data in the editor, this method renders recursively the plain
190 + * content containing only the content and the HTML. No CSS data.
191 + *
192 + * @since 2.0.0
193 + * @access private
194 + *
195 + * @param array $element_data Element data.
196 + */
197 + private function render_element_plain_content( $element_data ) {
198 + if ( 'widget' === $element_data['elType'] ) {
199 + /** @var Widget_Base $widget */
200 + $widget = Plugin::$instance->elements_manager->create_element_instance( $element_data );
201 +
202 + if ( $widget ) {
203 + $widget->render_plain_content();
204 + }
205 + }
206 +
207 + if ( ! empty( $element_data['elements'] ) ) {
208 + foreach ( $element_data['elements'] as $element ) {
209 + $this->render_element_plain_content( $element );
210 + }
211 + }
212 + }
213 +
214 + /**
215 + * Save plain text.
216 + *
217 + * Retrieves the raw content, removes all kind of unwanted HTML tags and saves
218 + * the content as the `post_content` field in the database.
219 + *
220 + * @since 1.9.0
221 + * @access public
222 + *
223 + * @param int $post_id Post ID.
224 + */
225 + public function save_plain_text( $post_id ) {
226 + // Switch $dynamic_tags to parsing mode = remove.
227 + $dynamic_tags = Plugin::$instance->dynamic_tags;
228 + $parsing_mode = $dynamic_tags->get_parsing_mode();
229 + $dynamic_tags->set_parsing_mode( Manager::MODE_REMOVE );
230 +
231 + $plain_text = $this->get_plain_text( $post_id );
232 +
233 + wp_update_post(
234 + [
235 + 'ID' => $post_id,
236 + 'post_content' => $plain_text,
237 + ]
238 + );
239 +
240 + // Restore parsing mode.
241 + $dynamic_tags->set_parsing_mode( $parsing_mode );
242 + }
243 +
244 + /**
245 + * Iterate data.
246 + *
247 + * Accept any type of Elementor data and a callback function. The callback
248 + * function runs recursively for each element and his child elements.
249 + *
250 + * @since 1.0.0
251 + * @access public
252 + *
253 + * @param array $data_container Any type of elementor data.
254 + * @param callable $callback A function to iterate data by.
255 + * @param array $args Array of args pointers for passing parameters in & out of the callback.
256 + *
257 + * @return mixed Iterated data.
258 + */
259 + public function iterate_data( $data_container, $callback, $args = [] ) {
260 + if ( isset( $data_container['elType'] ) ) {
261 + if ( ! empty( $data_container['elements'] ) ) {
262 + $data_container['elements'] = $this->iterate_data( $data_container['elements'], $callback, $args );
263 + }
264 +
265 + return call_user_func( $callback, $data_container, $args );
266 + }
267 +
268 + foreach ( $data_container as $element_key => $element_value ) {
269 + $element_data = $this->iterate_data( $data_container[ $element_key ], $callback, $args );
270 +
271 + if ( null === $element_data ) {
272 + continue;
273 + }
274 +
275 + $data_container[ $element_key ] = $element_data;
276 + }
277 +
278 + return $data_container;
279 + }
280 +
281 + public static function iterate_elementor_documents( $callback, $batch_size = 100 ) {
282 + $processed_posts = 0;
283 +
284 + while ( true ) {
285 + $args = wp_parse_args( [
286 + 'post_type' => [ Source_Local::CPT, 'post', 'page' ],
287 + 'post_status' => [ 'publish' ],
288 + 'posts_per_page' => $batch_size,
289 + 'meta_key' => Document::BUILT_WITH_ELEMENTOR_META_KEY,
290 + 'meta_value' => 'builder',
291 + 'offset' => $processed_posts,
292 + 'fields' => 'ids',
293 + ] );
294 +
295 + $query = new \WP_Query( $args );
296 +
297 + if ( empty( $query->posts ) ) {
298 + break;
299 + }
300 +
301 + foreach ( $query->posts as $post_id ) {
302 + $document = Plugin::$instance->documents->get( $post_id );
303 + $elements_data = $document->get_json_meta( Document::ELEMENTOR_DATA_META_KEY );
304 +
305 + $callback( $document, $elements_data );
306 +
307 + $processed_posts++;
308 + }
309 + }
310 + }
311 +
312 + /**
313 + * Safely copy Elementor meta.
314 + *
315 + * Make sure the original page was built with Elementor and the post is not
316 + * auto-save. Only then copy elementor meta from one post to another using
317 + * `copy_elementor_meta()`.
318 + *
319 + * @since 1.9.2
320 + * @access public
321 + *
322 + * @param int $from_post_id Original post ID.
323 + * @param int $to_post_id Target post ID.
324 + */
325 + public function safe_copy_elementor_meta( $from_post_id, $to_post_id ) {
326 + // It's from WP-Admin & not from Elementor.
327 + if ( ! did_action( 'elementor/db/before_save' ) ) {
328 + $from_document = Plugin::$instance->documents->get( $from_post_id );
329 +
330 + if ( ! $from_document || ! $from_document->is_built_with_elementor() ) {
331 + return;
332 + }
333 +
334 + // It's an exited Elementor auto-save.
335 + if ( get_post_meta( $to_post_id, '_elementor_data', true ) ) {
336 + return;
337 + }
338 + }
339 +
340 + $this->copy_elementor_meta( $from_post_id, $to_post_id );
341 + }
342 +
343 + /**
344 + * Copy Elementor meta.
345 + *
346 + * Duplicate the data from one post to another.
347 + *
348 + * Consider using `safe_copy_elementor_meta()` method instead.
349 + *
350 + * @since 1.1.0
351 + * @access public
352 + *
353 + * @param int $from_post_id Original post ID.
354 + * @param int $to_post_id Target post ID.
355 + */
356 + public function copy_elementor_meta( $from_post_id, $to_post_id ) {
357 + $from_post_meta = get_post_meta( $from_post_id );
358 + $core_meta = [
359 + '_wp_page_template',
360 + '_thumbnail_id',
361 + ];
362 +
363 + foreach ( $from_post_meta as $meta_key => $values ) {
364 + // Copy only meta with the `_elementor` prefix.
365 + if ( 0 === strpos( $meta_key, '_elementor' ) || in_array( $meta_key, $core_meta, true ) ) {
366 + $value = $values[0];
367 +
368 + // The elementor JSON needs slashes before saving.
369 + if ( '_elementor_data' === $meta_key ) {
370 + $value = wp_slash( $value );
371 + } else {
372 + $value = maybe_unserialize( $value );
373 + }
374 +
375 + // Don't use `update_post_meta` that can't handle `revision` post type.
376 + update_metadata( 'post', $to_post_id, $meta_key, $value );
377 + }
378 + }
379 + }
380 +
381 + /**
382 + * Is built with Elementor.
383 + *
384 + * Check whether the post was built with Elementor.
385 + *
386 + * @since 1.0.10
387 + * @deprecated 3.2.0 Use `Plugin::$instance->documents->get( $post_id )->is_built_with_elementor()` instead.
388 + * @access public
389 + *
390 + * @param int $post_id Post ID.
391 + *
392 + * @return bool Whether the post was built with Elementor.
393 + */
394 + public function is_built_with_elementor( $post_id ) {
395 + Plugin::$instance->modules_manager
396 + ->get_modules( 'dev-tools' )
397 + ->deprecation
398 + ->deprecated_function(
399 + __METHOD__,
400 + '3.2.0',
401 + 'Plugin::$instance->documents->get( $post_id )->is_built_with_elementor()'
402 + );
403 +
404 + $document = Plugin::$instance->documents->get( $post_id );
405 +
406 + if ( ! $document ) {
407 + return false;
408 + }
409 +
410 + return $document->is_built_with_elementor();
411 + }
412 +
413 + /**
414 + * Switch to post.
415 + *
416 + * Change the global WordPress post to the requested post.
417 + *
418 + * @since 1.5.0
419 + * @access public
420 + *
421 + * @param int $post_id Post ID to switch to.
422 + */
423 + public function switch_to_post( $post_id ) {
424 + $post_id = absint( $post_id );
425 + // If is already switched, or is the same post, return.
426 + if ( get_the_ID() === $post_id ) {
427 + $this->switched_post_data[] = false;
428 + return;
429 + }
430 +
431 + $this->switched_post_data[] = [
432 + 'switched_id' => $post_id,
433 + 'original_id' => get_the_ID(), // Note, it can be false if the global isn't set.
434 + ];
435 +
436 + $GLOBALS['post'] = get_post( $post_id ); // phpcs:ignore WordPress.WP.GlobalVariablesOverride.Prohibited
437 +
438 + setup_postdata( $GLOBALS['post'] );
439 + }
440 +
441 + /**
442 + * Restore current post.
443 + *
444 + * Rollback to the previous global post, rolling back from `DB::switch_to_post()`.
445 + *
446 + * @since 1.5.0
447 + * @access public
448 + */
449 + public function restore_current_post() {
450 + $data = array_pop( $this->switched_post_data );
451 +
452 + // If not switched, return.
453 + if ( ! $data ) {
454 + return;
455 + }
456 +
457 + // It was switched from an empty global post, restore this state and unset the global post.
458 + if ( false === $data['original_id'] ) {
459 + unset( $GLOBALS['post'] );
460 + return;
461 + }
462 +
463 + $GLOBALS['post'] = get_post( $data['original_id'] ); // phpcs:ignore WordPress.WP.GlobalVariablesOverride.Prohibited
464 +
465 + setup_postdata( $GLOBALS['post'] );
466 + }
467 +
468 +
469 + /**
470 + * Switch to query.
471 + *
472 + * Change the WordPress query to a new query with the requested
473 + * query variables.
474 + *
475 + * @since 2.0.0
476 + * @access public
477 + *
478 + * @param array $query_vars New query variables.
479 + * @param bool $force_global_post
480 + */
481 + public function switch_to_query( $query_vars, $force_global_post = false ) {
482 + global $wp_query;
483 + $current_query_vars = $wp_query->query;
484 +
485 + // If is already switched, or is the same query, return.
486 + if ( $current_query_vars === $query_vars ) {
487 + $this->switched_data[] = false;
488 + return;
489 + }
490 +
491 + $new_query = new \WP_Query( $query_vars );
492 +
493 + $switched_data = [
494 + 'switched' => $new_query,
495 + 'original' => $wp_query,
496 + ];
497 +
498 + if ( ! empty( $GLOBALS['post'] ) ) {
499 + $switched_data['post'] = $GLOBALS['post'];
500 + }
501 +
502 + $this->switched_data[] = $switched_data;
503 +
504 + $wp_query = $new_query; // phpcs:ignore WordPress.WP.GlobalVariablesOverride.Prohibited
505 +
506 + // Ensure the global post is set only if needed.
507 + unset( $GLOBALS['post'] );
508 +
509 + if ( isset( $new_query->posts[0] ) ) {
510 + if ( $force_global_post || $new_query->is_singular() ) {
511 + $GLOBALS['post'] = $new_query->posts[0]; // phpcs:ignore WordPress.WP.GlobalVariablesOverride.Prohibited
512 + setup_postdata( $GLOBALS['post'] );
513 + }
514 + }
515 +
516 + if ( $new_query->is_author() ) {
517 + $GLOBALS['authordata'] = get_userdata( $new_query->get( 'author' ) ); // phpcs:ignore WordPress.WP.GlobalVariablesOverride.Prohibited
518 + }
519 + }
520 +
521 + /**
522 + * Restore current query.
523 + *
524 + * Rollback to the previous query, rolling back from `DB::switch_to_query()`.
525 + *
526 + * @since 2.0.0
527 + * @access public
528 + */
529 + public function restore_current_query() {
530 + $data = array_pop( $this->switched_data );
531 +
532 + // If not switched, return.
533 + if ( ! $data ) {
534 + return;
535 + }
536 +
537 + global $wp_query;
538 +
539 + $wp_query = $data['original']; // phpcs:ignore WordPress.WP.GlobalVariablesOverride.Prohibited
540 +
541 + // Ensure the global post/authordata is set only if needed.
542 + unset( $GLOBALS['post'] );
543 + unset( $GLOBALS['authordata'] );
544 +
545 + if ( ! empty( $data['post'] ) ) {
546 + $GLOBALS['post'] = $data['post']; // phpcs:ignore WordPress.WP.GlobalVariablesOverride.Prohibited
547 + setup_postdata( $GLOBALS['post'] );
548 + }
549 +
550 + if ( $wp_query->is_author() ) {
551 + $GLOBALS['authordata'] = get_userdata( $wp_query->get( 'author' ) ); // phpcs:ignore WordPress.WP.GlobalVariablesOverride.Prohibited
552 + }
553 + }
554 +
555 + /**
556 + * Get plain text.
557 + *
558 + * Retrieve the post plain text.
559 + *
560 + * @since 1.9.0
561 + * @access public
562 + *
563 + * @param int $post_id Post ID.
564 + *
565 + * @return string Post plain text.
566 + */
567 + public function get_plain_text( $post_id ) {
568 + $document = Plugin::$instance->documents->get( $post_id );
569 + $data = $document ? $document->get_elements_data() : [];
570 +
571 + return $this->get_plain_text_from_data( $data );
572 + }
573 +
574 + /**
575 + * Get plain text from data.
576 + *
577 + * Retrieve the post plain text from any given Elementor data.
578 + *
579 + * @since 1.9.2
580 + * @access public
581 + *
582 + * @param array $data Post ID.
583 + *
584 + * @return string Post plain text.
585 + */
586 + public function get_plain_text_from_data( $data ) {
587 + ob_start();
588 + if ( $data ) {
589 + foreach ( $data as $element_data ) {
590 + $this->render_element_plain_content( $element_data );
591 + }
592 + }
593 +
594 + $plain_text = ob_get_clean();
595 +
596 + // Remove unnecessary tags.
597 + $plain_text = preg_replace( '/<\/?div[^>]*\>/i', '', $plain_text );
598 + $plain_text = preg_replace( '/<\/?span[^>]*\>/i', '', $plain_text );
599 + $plain_text = preg_replace( '#<script(.*?)>(.*?)</script>#is', '', $plain_text );
600 + $plain_text = preg_replace( '/<i [^>]*><\\/i[^>]*>/', '', $plain_text );
601 + $plain_text = preg_replace( '/ class=".*?"/', '', $plain_text );
602 +
603 + // Remove empty lines.
604 + $plain_text = preg_replace( '/(^[\r\n]*|[\r\n]+)[\s\t]*[\r\n]+/', "\n", $plain_text );
605 +
606 + $plain_text = trim( $plain_text );
607 +
608 + return $plain_text;
609 + }
610 + }
611 +