PluginProbe
Elementor Website Builder – more than just a page builder / 3.8.0-beta1
Elementor Website Builder – more than just a page builder v3.8.0-beta1
4.3.0-beta2 4.3.0-beta1 4.2.4 4.2.3 4.2.2 4.2.1 4.2.0 4.1.5 4.2.0-beta2 4.2.0-dev2 4.2.0-beta1 4.1.4 4.1.3 4.1.2 4.1.1 4.1.0 4.1.0-beta3 4.1.0-dev3 4.0.9 4.1.0-beta2 4.1.0-dev2 4.0.8 4.1.0-beta1 4.1.0-dev1 4.0.7 All 451 releases
elementor / app / modules / import-export / module.php

module.php in Elementor Website Builder – more than just a page builder 3.8.0-beta1, at app/modules/import-export/module.php

668 lines 20.9 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 namespace Elementor\App\Modules\ImportExport;
3
4 use Elementor\App\Modules\ImportExport\Processes\Export;
5 use Elementor\App\Modules\ImportExport\Processes\Import;
6 use Elementor\App\Modules\ImportExport\Processes\Revert;
7 use Elementor\Core\Base\Module as BaseModule;
8 use Elementor\Core\Common\Modules\Ajax\Module as Ajax;
9 use Elementor\Core\Files\Uploads_Manager;
10 use Elementor\Modules\System_Info\Reporters\Server;
11 use Elementor\Plugin;
12 use Elementor\Tools;
13 use Elementor\Utils as ElementorUtils;
14 use Elementor\App\Modules\ImportExport\Utils as ImportExportUtils;
15
16 if ( ! defined( 'ABSPATH' ) ) {
17 exit; // Exit if accessed directly
18 }
19
20 /**
21 * Import Export Module
22 *
23 * Responsible for initializing Elementor App functionality
24 */
25 class Module extends BaseModule {
26 const FORMAT_VERSION = '2.0';
27
28 const EXPORT_TRIGGER_KEY = 'elementor_export_kit';
29
30 const UPLOAD_TRIGGER_KEY = 'elementor_upload_kit';
31
32 const IMPORT_TRIGGER_KEY = 'elementor_import_kit';
33
34 const REFERRER_KIT_LIBRARY = 'kit-library';
35
36 const REFERRER_LOCAL = 'local';
37
38 const PERMISSIONS_ERROR_KEY = 'plugin-installation-permissions-error';
39
40 const NO_WRITE_PERMISSIONS_KEY = 'no-write-permissions';
41
42 const OPTION_KEY_ELEMENTOR_IMPORT_SESSIONS = 'elementor_import_sessions';
43
44 const OPTION_KEY_ELEMENTOR_REVERT_SESSIONS = 'elementor_revert_sessions';
45
46 const META_KEY_ELEMENTOR_IMPORT_SESSION_ID = '_elementor_import_session_id';
47
48 const META_KEY_ELEMENTOR_EDIT_MODE = '_elementor_edit_mode';
49
50
51 /**
52 * Assigning the export process to a property, so we can use the process from outside the class.
53 *
54 * @var Export
55 */
56 public $export;
57
58 /**
59 * Assigning the import process to a property, so we can use the process from outside the class.
60 *
61 * @var Import
62 */
63 public $import;
64
65 /**
66 * Assigning the revert process to a property, so we can use the process from outside the class.
67 *
68 * @var Revert
69 */
70 public $revert;
71
72 /**
73 * Get name.
74 *
75 * @access public
76 *
77 * @return string
78 */
79 public function get_name() {
80 return 'import-export';
81 }
82
83 public function __construct() {
84 $this->register_actions();
85
86 if ( ElementorUtils::is_wp_cli() ) {
87 \WP_CLI::add_command( 'elementor kit', WP_CLI::class );
88 }
89
90 ( new Usage() )->register();
91 }
92
93 public function get_init_settings() {
94 if ( ! Plugin::$instance->app->is_current() ) {
95 return [];
96 }
97
98 return $this->get_config_data();
99 }
100
101 /**
102 * Register the import/export tab in elementor tools.
103 */
104 public function register_settings_tab( Tools $tools ) {
105 $tools->add_tab( 'import-export-kit', [
106 'label' => esc_html__( 'Import / Export Kit', 'elementor' ),
107 'sections' => [
108 'intro' => [
109 'label' => esc_html__( 'Template Kits', 'elementor' ),
110 'callback' => function() {
111 $this->render_import_export_tab_content();
112 },
113 'fields' => [],
114 ],
115 ],
116 ] );
117 }
118
119 /**
120 * Render the import/export tab content.
121 */
122 private function render_import_export_tab_content() {
123 $intro_text_link = sprintf( '<a href="https://go.elementor.com/wp-dash-import-export-general/" target="_blank">%s</a>', esc_html__( 'Learn more', 'elementor' ) );
124
125 $intro_text = sprintf(
126 /* translators: 1: New line break, 2: Learn More link. */
127 __( 'Design sites faster with a template kit that contains some or all components of a complete site, like templates, content & site settings.%1$sYou can import a kit and apply it to your site, or export the elements from this site to be used anywhere else. %2$s', 'elementor' ),
128 '<br>',
129 $intro_text_link
130 );
131
132 $content_data = [
133 'export' => [
134 'title' => esc_html__( 'Export a Template Kit', 'elementor' ),
135 'button' => [
136 'url' => Plugin::$instance->app->get_base_url() . '#/export',
137 'text' => esc_html__( 'Start Export', 'elementor' ),
138 ],
139 'description' => esc_html__( 'Bundle your whole site - or just some of its elements - to be used for another website.', 'elementor' ),
140 'link' => [
141 'url' => 'https://go.elementor.com/wp-dash-import-export-export-flow/',
142 'text' => esc_html__( 'Learn More', 'elementor' ),
143 ],
144 ],
145 'import' => [
146 'title' => esc_html__( 'Import a Template Kit', 'elementor' ),
147 'button' => [
148 'url' => Plugin::$instance->app->get_base_url() . '#/import',
149 'text' => esc_html__( 'Start Import', 'elementor' ),
150 ],
151 'description' => esc_html__( 'Apply the design and settings of another site to this one.', 'elementor' ),
152 'link' => [
153 'url' => 'https://go.elementor.com/wp-dash-import-export-import-flow/',
154 'text' => esc_html__( 'Learn More', 'elementor' ),
155 ],
156 ],
157 ];
158
159 $this->revert = new Revert();
160 $last_imported_kit = $this->revert->get_last_import_session();
161 $penultimate_imported_kit = $this->revert->get_penultimate_import_session();
162
163 $user_date_format = get_option( 'date_format' );
164 $user_time_format = get_option( 'time_format' );
165 $date_format = $user_date_format . ' ' . $user_time_format;
166
167 $should_show_revert_section = $this->should_show_revert_section( $last_imported_kit );
168
169 if ( $should_show_revert_section ) {
170 if ( ! empty( $penultimate_imported_kit ) ) {
171 $revert_text = sprintf(
172 esc_html__( 'Remove all the content and site settings that came with "%1$s" on %2$s %3$s and revert to the site setting that came with "%4$s" on %5$s.', 'elementor' ),
173 ! empty( $last_imported_kit['kit_name'] ) ? $last_imported_kit['kit_name'] : esc_html__( 'imported kit', 'elementor' ),
174 gmdate( $date_format, $last_imported_kit['start_timestamp'] ),
175 '<br>',
176 ! empty( $penultimate_imported_kit['kit_name'] ) ? $penultimate_imported_kit['kit_name'] : esc_html__( 'imported kit', 'elementor' ),
177 gmdate( $date_format, $penultimate_imported_kit['start_timestamp'] )
178 );
179 } else {
180 $revert_text = sprintf(
181 esc_html__( 'Remove all the content and site settings that came with "%1$s" on %2$s.%3$s Your original site settings will be restored.', 'elementor' ),
182 ! empty( $last_imported_kit['kit_name'] ) ? $last_imported_kit['kit_name'] : esc_html__( 'imported kit', 'elementor' ),
183 gmdate( $date_format, $last_imported_kit['start_timestamp'] ),
184 '<br>'
185 );
186 }
187 }
188 ?>
189
190 <div class="tab-import-export-kit__content">
191 <p class="tab-import-export-kit__info"><?php ElementorUtils::print_unescaped_internal_string( $intro_text ); ?></p>
192
193 <div class="tab-import-export-kit__wrapper">
194 <?php foreach ( $content_data as $data ) { ?>
195 <div class="tab-import-export-kit__container">
196 <div class="tab-import-export-kit__box">
197 <h2><?php ElementorUtils::print_unescaped_internal_string( $data['title'] ); ?></h2>
198 <a href="<?php ElementorUtils::print_unescaped_internal_string( $data['button']['url'] ); ?>" class="elementor-button elementor-button-success">
199 <?php ElementorUtils::print_unescaped_internal_string( $data['button']['text'] ); ?>
200 </a>
201 </div>
202 <p><?php ElementorUtils::print_unescaped_internal_string( $data['description'] ); ?></p>
203 <a href="<?php ElementorUtils::print_unescaped_internal_string( $data['link']['url'] ); ?>" target="_blank"><?php ElementorUtils::print_unescaped_internal_string( $data['link']['text'] ); ?></a>
204 </div>
205 <?php } ?>
206 </div>
207
208 <?php
209 if ( $should_show_revert_section ) {
210 $link_attributes = [
211 'href' => wp_nonce_url( admin_url( 'admin-post.php?action=elementor_revert_kit' ), 'elementor_revert_kit' ),
212 'id' => 'elementor-import-export__revert_kit',
213 'class' => 'button',
214 ];
215 ?>
216 <div class="tab-import-export-kit__revert">
217 <h2>
218 <?php ElementorUtils::print_unescaped_internal_string( esc_html__( 'Remove the most recent Kit', 'elementor' ) ); ?>
219 </h2>
220 <p class="tab-import-export-kit__info">
221 <?php ElementorUtils::print_unescaped_internal_string( $revert_text ); ?>
222 </p>
223 <a <?php ElementorUtils::print_html_attributes( $link_attributes ); ?> >
224 <?php ElementorUtils::print_unescaped_internal_string( esc_html__( 'Remove Kit', 'elementor' ) ); ?>
225 </a>
226 </div>
227 <?php } ?>
228 </div>
229 <?php
230 }
231
232 /**
233 * Upload a kit zip file and get the kit data.
234 *
235 * Assigning the Import process to the 'import' property,
236 * so it will be available to use in different places such as: WP_Cli, Pro, etc.
237 *
238 * @param string $file Path to the file.
239 * @param string $referrer Referrer of the file 'local' or 'kit-library'.
240 * @return array
241 * @throws \Exception
242 */
243 public function upload_kit( $file, $referrer ) {
244 $this->ensure_writing_permissions();
245
246 $this->import = new Import( $file, [ 'referrer' => $referrer ] );
247
248 return [
249 'session' => $this->import->get_session_id(),
250 'manifest' => $this->import->get_manifest(),
251 'conflicts' => $this->import->get_settings_conflicts(),
252 ];
253 }
254
255 /**
256 * Import a kit by session_id.
257 * Upload and import a kit by kit zip file.
258 *
259 * Assigning the Import process to the 'import' property,
260 * so it will be available to use in different places such as: WP_Cli, Pro, etc.
261 *
262 * @param string $path Path to the file or session_id.
263 * @param array $settings Settings the import use to determine which content to import.
264 * (e.g: include, selected_plugins, selected_cpt, selected_override_conditions, etc.)
265 * @return array
266 * @throws \Exception
267 */
268 public function import_kit( $path, $settings ) {
269 $this->ensure_writing_permissions();
270
271 $this->import = new Import( $path, $settings );
272 $this->import->register_default_runners();
273
274 do_action( 'elementor/import-export/import-kit', $this->import );
275
276 return $this->import->run();
277 }
278
279 /**
280 * Export a kit.
281 *
282 * Assigning the Export process to the 'export' property,
283 * so it will be available to use in different places such as: WP_Cli, Pro, etc.
284 *
285 * @param array $settings Settings the export use to determine which content to export.
286 * (e.g: include, kit_info, selected_plugins, selected_cpt, etc.)
287 * @return array
288 * @throws \Exception
289 */
290 public function export_kit( $settings ) {
291 $this->ensure_writing_permissions();
292
293 $this->export = new Export( $settings );
294 $this->export->register_default_runners();
295
296 do_action( 'elementor/import-export/export-kit', $this->export );
297
298 return $this->export->run();
299 }
300
301 /**
302 * Handle revert kit ajax request.
303 */
304 public function revert_last_imported_kit() {
305 $this->revert = new Revert();
306 $this->revert->register_default_runners();
307
308 do_action( 'elementor/import-export/revert-kit', $this->revert );
309
310 $this->revert->run();
311 }
312
313
314 /**
315 * Handle revert last imported kit ajax request.
316 */
317 public function handle_revert_last_imported_kit() {
318 check_admin_referer( 'elementor_revert_kit' );
319
320 $this->revert_last_imported_kit();
321
322 wp_safe_redirect( admin_url( 'admin.php?page=' . Tools::PAGE_ID . '#tab-import-export-kit' ) );
323 die;
324 }
325
326 /**
327 * Register appropriate actions.
328 */
329 private function register_actions() {
330 add_action( 'admin_init', function() {
331 if ( wp_doing_ajax() &&
332 isset( $_POST['action'] ) &&
333 isset( $_POST['_nonce'] ) &&
334 wp_verify_nonce( $_POST['_nonce'], Ajax::NONCE_KEY ) &&
335 current_user_can( 'manage_options' )
336 ) {
337 $this->maybe_handle_ajax();
338 }
339 } );
340
341 add_action( 'admin_post_elementor_revert_kit', [ $this, 'handle_revert_last_imported_kit' ] );
342
343 add_action( 'admin_enqueue_scripts', [ $this, 'enqueue_scripts' ] );
344
345 $page_id = Tools::PAGE_ID;
346
347 add_action( "elementor/admin/after_create_settings/{$page_id}", [ $this, 'register_settings_tab' ] );
348 }
349
350 private function ensure_writing_permissions() {
351 $server = new Server();
352
353 $paths_to_check = [
354 Server::KEY_PATH_WP_CONTENT_DIR => $server->get_system_path( Server::KEY_PATH_WP_CONTENT_DIR ),
355 Server::KEY_PATH_UPLOADS_DIR => $server->get_system_path( Server::KEY_PATH_UPLOADS_DIR ),
356 Server::KEY_PATH_ELEMENTOR_UPLOADS_DIR => $server->get_system_path( Server::KEY_PATH_ELEMENTOR_UPLOADS_DIR ),
357 ];
358
359 $permissions = $server->get_paths_permissions( $paths_to_check );
360
361 foreach ( $permissions as $permission ) {
362 if ( ! $permission['write'] ) {
363 throw new \Error( self::NO_WRITE_PERMISSIONS_KEY );
364 }
365 }
366 }
367
368 /**
369 * Enqueue admin scripts
370 */
371 public function enqueue_scripts() {
372 wp_enqueue_script(
373 'elementor-import-export-admin',
374 $this->get_js_assets_url( 'import-export-admin' ),
375 [ 'elementor-common' ],
376 ELEMENTOR_VERSION,
377 true
378 );
379 }
380
381 /**
382 * Assign each ajax action to a method.
383 */
384 private function maybe_handle_ajax() {
385 // phpcs:ignore WordPress.Security.NonceVerification.Missing
386 switch ( $_POST['action'] ) {
387 case static::EXPORT_TRIGGER_KEY:
388 $this->handle_export_kit();
389 break;
390
391 case static::UPLOAD_TRIGGER_KEY:
392 $this->handle_upload_kit();
393 break;
394
395 case static::IMPORT_TRIGGER_KEY:
396 $this->handle_import_kit();
397 break;
398
399 default:
400 break;
401 }
402 }
403
404 /**
405 * Handle upload kit ajax request.
406 */
407 private function handle_upload_kit() {
408 // PHPCS - Already validated in caller function.
409 if ( ! empty( $_POST['e_import_file'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification.Missing
410 if (
411 ! isset( $_POST['e_kit_library_nonce'] ) ||
412 ! wp_verify_nonce( $_POST['e_kit_library_nonce'], 'kit-library-import' )
413 ) {
414 throw new \Error( esc_html__( 'Invalid kit library nonce', 'elementor' ) );
415 }
416
417 $file_url = $_POST['e_import_file'];
418
419 if ( ! filter_var( $file_url, FILTER_VALIDATE_URL ) || 0 !== strpos( $file_url, 'http' ) ) {
420 throw new \Error( esc_html__( 'Invalid URL', 'elementor' ) );
421 }
422
423 $remote_zip_request = wp_remote_get( $file_url );
424
425 if ( is_wp_error( $remote_zip_request ) ) {
426 throw new \Error( $remote_zip_request->get_error_message() );
427 }
428
429 if ( 200 !== $remote_zip_request['response']['code'] ) {
430 throw new \Error( $remote_zip_request['response']['message'] );
431 }
432
433 $file_name = Plugin::$instance->uploads_manager->create_temp_file( $remote_zip_request['body'], 'kit.zip' );
434 $referrer = static::REFERRER_KIT_LIBRARY;
435 } else {
436 // PHPCS - Already validated in caller function.
437 $file_name = $_FILES['e_import_file']['tmp_name']; // phpcs:ignore WordPress.Security.NonceVerification.Missing
438 $referrer = static::REFERRER_LOCAL;
439 }
440
441 $uploaded_kit = $this->upload_kit( $file_name, $referrer );
442 $session_dir = $uploaded_kit['session'];
443 $manifest = $uploaded_kit['manifest'];
444 $conflicts = $uploaded_kit['conflicts'];
445
446 if ( ! empty( $file_url ) ) {
447 Plugin::$instance->uploads_manager->remove_file_or_dir( dirname( $file_name ) );
448 }
449
450 if ( isset( $manifest['plugins'] ) && ! current_user_can( 'install_plugins' ) ) {
451 throw new \Error( static::PERMISSIONS_ERROR_KEY );
452 }
453
454 $result = [
455 'session' => $session_dir,
456 'manifest' => $manifest,
457 ];
458
459 if ( ! empty( $conflicts ) ) {
460 $result['conflicts'] = $conflicts;
461 } else {
462 // Moved into the IE process \Elementor\App\Modules\ImportExport\Processes\Import::get_default_settings_conflicts
463 // TODO: remove in 3.10.0
464 $result = apply_filters( 'elementor/import/stage_1/result', $result );
465 }
466
467 wp_send_json_success( $result );
468 }
469
470 /**
471 * Handle import kit ajax request.
472 */
473 private function handle_import_kit() {
474 // PHPCS - Already validated in caller function
475 $settings = json_decode( stripslashes( $_POST['data'] ), true ); // phpcs:ignore WordPress.Security.NonceVerification.Missing
476 $tmp_folder_id = $settings['session'];
477
478 $import = $this->import_kit( $tmp_folder_id, $settings );
479
480 wp_send_json_success( $import );
481 }
482
483 /**
484 * Handle export kit ajax request.
485 */
486 private function handle_export_kit() {
487 // PHPCS - Already validated in caller function
488 $settings = json_decode( stripslashes( $_POST['data'] ), true ); // phpcs:ignore WordPress.Security.NonceVerification.Missing
489 $export = $this->export_kit( $settings );
490
491 $file_name = $export['file_name'];
492 $file = ElementorUtils::file_get_contents( $file_name );
493
494 if ( ! $file ) {
495 throw new \Error( esc_html__( 'Could not read the exported file', 'elementor' ) );
496 }
497
498 Plugin::$instance->uploads_manager->remove_file_or_dir( dirname( $file_name ) );
499
500 $result = [
501 'manifest' => $export['manifest'],
502 'file' => base64_encode( $file ),
503 ];
504
505 wp_send_json_success( $result );
506 }
507
508 /**
509 * Get config data that will be exposed to the frontend.
510 */
511 private function get_config_data() {
512 $export_nonce = wp_create_nonce( 'elementor_export' );
513 $export_url = add_query_arg( [ '_nonce' => $export_nonce ], Plugin::$instance->app->get_base_url() );
514
515 return [
516 'exportURL' => $export_url,
517 'summaryTitles' => $this->get_summary_titles(),
518 'builtinWpPostTypes' => ImportExportUtils::get_builtin_wp_post_types(),
519 'elementorPostTypes' => ImportExportUtils::get_elementor_post_types(),
520 'isUnfilteredFilesEnabled' => Uploads_Manager::are_unfiltered_uploads_enabled(),
521 'elementorHomePageUrl' => $this->get_elementor_home_page_url(),
522 'recentlyEditedElementorPageUrl' => $this->get_recently_edited_elementor_page_url(),
523 ];
524 }
525
526 /**
527 * Get labels of Elementor document types, Elementor Post types, WordPress Post types and Custom Post types.
528 */
529 private function get_summary_titles() {
530 $summary_titles = [];
531
532 $document_types = Plugin::$instance->documents->get_document_types();
533
534 foreach ( $document_types as $name => $document_type ) {
535 $summary_titles['templates'][ $name ] = [
536 'single' => $document_type::get_title(),
537 'plural' => $document_type::get_plural_title(),
538 ];
539 }
540
541 $elementor_post_types = ImportExportUtils::get_elementor_post_types();
542 $wp_builtin_post_types = ImportExportUtils::get_builtin_wp_post_types();
543 $post_types = array_merge( $elementor_post_types, $wp_builtin_post_types );
544
545 foreach ( $post_types as $post_type ) {
546 $post_type_object = get_post_type_object( $post_type );
547
548 $summary_titles['content'][ $post_type ] = [
549 'single' => $post_type_object->labels->singular_name,
550 'plural' => $post_type_object->label,
551 ];
552 }
553
554 $custom_post_types = ImportExportUtils::get_registered_cpt_names();
555 if ( ! empty( $custom_post_types ) ) {
556 foreach ( $custom_post_types as $custom_post_type ) {
557
558 $custom_post_types_object = get_post_type_object( $custom_post_type );
559 // CPT data appears in two arrays:
560 // 1. content object: in order to show the export summary when completed in getLabel function
561 $summary_titles['content'][ $custom_post_type ] = [
562 'single' => $custom_post_types_object->labels->singular_name,
563 'plural' => $custom_post_types_object->label,
564 ];
565
566 // 2. customPostTypes object: in order to actually export the data
567 $summary_titles['content']['customPostTypes'][ $custom_post_type ] = [
568 'single' => $custom_post_types_object->labels->singular_name,
569 'plural' => $custom_post_types_object->label,
570 ];
571 }
572 }
573
574 $active_kit = Plugin::$instance->kits_manager->get_active_kit();
575
576 foreach ( $active_kit->get_tabs() as $key => $tab ) {
577 $summary_titles['site-settings'][ $key ] = $tab->get_title();
578 }
579
580 return $summary_titles;
581 }
582
583 public function should_show_revert_section( $last_imported_kit ) {
584 if ( empty( $last_imported_kit ) ) {
585 return false;
586 }
587
588 // TODO: BC - remove in the future
589 // The 'templates' runner was in core and moved to the Pro plugin. (Part of it still exits in the Core for BC)
590 // The runner that is in the core version is missing the revert functionality,
591 // therefore we shouldn't display the revert section if the import process done with the core version.
592 $is_import_templates_ran = isset( $last_imported_kit['runners']['templates'] );
593 if ( $this->has_pro() && $is_import_templates_ran ) {
594 $has_imported_templates = ! empty( $last_imported_kit['runners']['templates'] );
595
596 return $has_imported_templates;
597 }
598
599 return true;
600 }
601
602 public function has_pro(): bool {
603 return ElementorUtils::has_pro();
604 }
605
606 private function get_elementor_editor_home_page_url() {
607 if ( 'page' !== get_option( 'show_on_front' ) ) {
608 return '';
609 }
610
611 $frontpage_id = get_option( 'page_on_front' );
612
613 return $this->get_elementor_editor_page_url( $frontpage_id );
614 }
615
616 private function get_elementor_home_page_url() {
617 if ( 'page' !== get_option( 'show_on_front' ) ) {
618 return '';
619 }
620
621 $frontpage_id = get_option( 'page_on_front' );
622
623 return $this->get_elementor_page_url( $frontpage_id );
624 }
625
626 private function get_recently_edited_elementor_page_url() {
627 $query = ElementorUtils::get_recently_edited_posts_query( [ 'posts_per_page' => 1 ] );
628
629 if ( ! isset( $query->post ) ) {
630 return '';
631 }
632
633 return $this->get_elementor_page_url( $query->post->ID );
634 }
635
636 private function get_recently_edited_elementor_editor_page_url() {
637 $query = ElementorUtils::get_recently_edited_posts_query( [ 'posts_per_page' => 1 ] );
638
639 if ( ! isset( $query->post ) ) {
640 return '';
641 }
642
643 return $this->get_elementor_editor_page_url( $query->post->ID );
644 }
645
646 private function get_elementor_document( $page_id ) {
647 $document = Plugin::$instance->documents->get( $page_id );
648
649 if ( ! $document || ! $document->is_built_with_elementor() ) {
650 return false;
651 }
652
653 return $document;
654 }
655
656 private function get_elementor_page_url( $page_id ) {
657 $document = $this->get_elementor_document( $page_id );
658
659 return $document ? $document->get_preview_url() : '';
660 }
661
662 private function get_elementor_editor_page_url( $page_id ) {
663 $document = $this->get_elementor_document( $page_id );
664
665 return $document ? $document->get_edit_url() : '';
666 }
667 }
668