PluginProbe
Elementor Website Builder – more than just a page builder / 3.10.0-dev1
Elementor Website Builder – more than just a page builder v3.10.0-dev1
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
← All changes | app/modules/import-export/processes/import.php +51 -301 4.2.03.10.0-dev1 View file →
@@ -6,9 +6,8 @@
6 6 use Elementor\App\Modules\ImportExport\Compatibility\Envato;
7 7 use Elementor\App\Modules\ImportExport\Compatibility\Kit_Library;
8 8 use Elementor\App\Modules\ImportExport\Utils;
9 9 use Elementor\Core\Base\Document;
10 -use Elementor\Core\Kits\Documents\Kit;
11 10 use Elementor\Plugin;
12 11
13 12 use Elementor\App\Modules\ImportExport\Runners\Import\Elementor_Content;
14 13 use Elementor\App\Modules\ImportExport\Runners\Import\Import_Runner_Base;
@@ -21,11 +20,11 @@
21 20
22 21 class Import {
23 22 const MANIFEST_ERROR_KEY = 'manifest-error';
24 23
25 - const ZIP_FILE_ERROR_KEY = 'invalid-zip-file';
24 + const SESSION_DOES_NOT_EXITS_ERROR = 'session-does-not-exits-error';
26 25
27 - const ZIP_ARCHIVE_ERROR_KEY = 'zip-archive-module-missing';
26 + const ZIP_FILE_ERROR_KEY = 'zip-file-error';
28 27
29 28 /**
30 29 * @var Import_Runner_Base[]
31 30 */
@@ -39,15 +38,8 @@
39 38 */
40 39 private $session_id;
41 40
42 41 /**
43 - * The Kit ID.
44 - *
45 - * @var string
46 - */
47 - private $kit_id;
48 -
49 - /**
50 42 * Adapter for the kit compatibility.
51 43 *
52 44 * @var Base_Adapter[]
53 45 */
@@ -53,13 +45,13 @@
53 45 */
54 46 private $adapters;
55 47
56 48 /**
57 - * Document's data (elements and settings) that was imported during the process.
49 + * Document's elements that imported during the process.
58 50 *
59 - * @var array { [document_id] => { "elements": array , "settings": array } }
51 + * @var array
60 52 */
61 - private $documents_data = [];
53 + private $documents_elements = [];
62 54
63 55 /**
64 56 * Path to the extracted kit files.
65 57 *
@@ -138,105 +130,43 @@
138 130 */
139 131 private $runners_import_metadata = [];
140 132
141 133 /**
142 - * @param string $path session_id | zip_file_path
143 - * @param array $settings Use to determine which content to import.
144 - * (e.g: include, selected_plugins, selected_cpt, selected_override_conditions, etc.)
145 - * @param array|null $old_instance An array of old instance parameters that will be used for creating new instance.
146 - * We are using it for quick creation of the instance when the import process is being split into chunks.
147 - *
148 - * @throws \Exception If the import session does not exist.
134 + * @param $path string session_id | zip_file_path
135 + * @param $settings array Use to determine which content to import.
136 + * (e.g: include, selected_plugins, selected_cpt, selected_override_conditions, etc.)
137 + * @throws \Exception
149 138 */
150 - public function __construct( string $path, array $settings = [], array $old_instance = null ) {
151 - if ( ! empty( $old_instance ) ) {
152 - $this->set_import_object( $old_instance );
139 + public function __construct( string $path, array $settings = [] ) {
140 + if ( is_file( $path ) ) {
141 + $this->extracted_directory_path = $this->extract_zip( $path );
153 142 } else {
154 - if ( is_file( $path ) ) {
155 - $this->extracted_directory_path = $this->extract_zip( $path );
156 - } else {
157 - $elementor_tmp_directory = Plugin::$instance->uploads_manager->get_temp_dir();
158 - $path = $elementor_tmp_directory . basename( $path );
143 + $elementor_tmp_directory = Plugin::$instance->uploads_manager->get_temp_dir();
144 + $path = $elementor_tmp_directory . basename( $path );
159 145
160 - if ( ! is_dir( $path ) ) {
161 - throw new \Exception( 'Couldn’t execute the import process because the import session does not exist.' );
162 - }
163 -
164 - $this->extracted_directory_path = $path . '/';
146 + if ( ! is_dir( $path ) ) {
147 + throw new \Exception( static::SESSION_DOES_NOT_EXITS_ERROR );
165 148 }
166 149
167 - $this->session_id = basename( $this->extracted_directory_path );
168 - $this->kit_id = $settings['id'] ?? '';
169 - $this->settings_referrer = ! empty( $settings['referrer'] ) ? $settings['referrer'] : 'local';
170 - $this->settings_include = ! empty( $settings['include'] ) ? $settings['include'] : null;
171 -
172 - // Using isset and not empty is important since empty array is valid option.
173 - $this->settings_selected_override_conditions = $settings['overrideConditions'] ?? null;
174 - $this->settings_selected_custom_post_types = $settings['selectedCustomPostTypes'] ?? null;
175 - $this->settings_selected_plugins = $settings['plugins'] ?? null;
176 -
177 - $this->manifest = $this->read_manifest_json();
178 - $this->site_settings = $this->read_site_settings_json();
179 -
180 - $this->set_default_settings();
150 + $this->extracted_directory_path = $path . '/';
181 151 }
182 152
183 - add_filter( 'wp_php_error_args', function ( $args, $error ) {
184 - return $this->filter_php_error_args( $args, $error );
185 - }, 10, 2 );
186 - }
153 + $this->session_id = basename( $this->extracted_directory_path );
154 + $this->settings_referrer = ! empty( $settings['referrer'] ) ? $settings['referrer'] : 'local';
155 + $this->settings_include = ! empty( $settings['include'] ) ? $settings['include'] : null;
187 156
188 - /**
189 - * Set the import object parameters.
190 - *
191 - * @param array $instance
192 - * @return void
193 - */
194 - private function set_import_object( array $instance ) {
195 - $this->session_id = $instance['session_id'];
157 + // Using isset and not empty is important since empty array is valid option.
158 + $this->settings_selected_override_conditions = $settings['overrideConditions'] ?? null;
159 + $this->settings_selected_custom_post_types = $settings['selectedCustomPostTypes'] ?? null;
160 + $this->settings_selected_plugins = $settings['plugins'] ?? null;
196 161
197 - $instance_data = $instance['instance_data'];
162 + $this->manifest = $this->read_manifest_json();
163 + $this->site_settings = $this->read_site_settings_json();
198 164
199 - $this->extracted_directory_path = $instance_data['extracted_directory_path'];
200 - $this->runners = $instance_data['runners'];
201 - $this->adapters = $instance_data['adapters'];
202 -
203 - $this->manifest = $instance_data['manifest'];
204 - $this->site_settings = $instance_data['site_settings'];
205 -
206 - $this->settings_include = $instance_data['settings_include'];
207 - $this->settings_referrer = $instance_data['settings_referrer'];
208 - $this->settings_conflicts = $instance_data['settings_conflicts'];
209 - $this->settings_selected_override_conditions = $instance_data['settings_selected_override_conditions'];
210 - $this->settings_selected_custom_post_types = $instance_data['settings_selected_custom_post_types'];
211 - $this->settings_selected_plugins = $instance_data['settings_selected_plugins'];
212 -
213 - $this->documents_data = $instance_data['documents_data'];
214 - $this->imported_data = $instance_data['imported_data'];
215 - $this->runners_import_metadata = $instance_data['runners_import_metadata'];
165 + $this->set_default_settings();
216 166 }
217 167
218 168 /**
219 - * Creating a new instance of the import process by the id of the old import session.
220 - *
221 - * @param string $session_id
222 - *
223 - * @return Import
224 - * @throws \Exception If the import session does not exist.
225 - */
226 - public static function from_session( string $session_id ): Import {
227 - $import_sessions = Utils::get_import_sessions();
228 -
229 - if ( ! $import_sessions || ! isset( $import_sessions[ $session_id ] ) ) {
230 - throw new \Exception( 'Couldn’t execute the import process because the import session does not exist.' );
231 - }
232 -
233 - $import_session = $import_sessions[ $session_id ];
234 -
235 - return new self( $session_id, [], $import_session );
236 - }
237 -
238 - /**
239 169 * Register a runner.
240 170 * Be aware that the runner will be executed in the order of registration, the order is crucial for the import process.
241 171 *
242 172 * @param Import_Runner_Base $runner_instance
@@ -282,14 +212,15 @@
282 212 /**
283 213 * Execute the import process.
284 214 *
285 215 * @return array The imported data output.
286 - *
287 - * @throws \Exception If no import runners have been specified.
216 + * @throws \Exception
288 217 */
289 218 public function run() {
219 + $start_time = current_time( 'timestamp' );
220 +
290 221 if ( empty( $this->runners ) ) {
291 - throw new \Exception( 'Couldn’t execute the import process because no import runners have been specified. Try again by specifying import runners.' );
222 + throw new \Exception( 'Please specify import runners.' );
292 223 }
293 224
294 225 $data = [
295 226 'session_id' => $this->session_id,
@@ -300,11 +231,8 @@
300 231 'extracted_directory_path' => $this->extracted_directory_path,
301 232 'selected_custom_post_types' => $this->settings_selected_custom_post_types,
302 233 ];
303 234
304 - $this->init_import_session();
305 -
306 - remove_filter( 'elementor/document/save/data', [ Plugin::$instance->modules_manager->get_modules( 'content-sanitizer' ), 'sanitize_content' ] );
307 235 add_filter( 'elementor/document/save/data', [ $this, 'prevent_saving_elements_on_post_creation' ], 10, 2 );
308 236
309 237 // Set the Request's state as an Elementor upload request, in order to support unfiltered file uploads.
310 238 Plugin::$instance->uploads_manager->set_elementor_upload_state( true );
@@ -322,9 +250,9 @@
322 250 Plugin::$instance->uploads_manager->set_elementor_upload_state( false );
323 251
324 252 remove_filter( 'elementor/document/save/data', [ $this, 'prevent_saving_elements_on_post_creation' ], 10 );
325 253
326 - $this->finalize_import_session_option();
254 + $this->add_import_session_option( $start_time );
327 255
328 256 $this->save_elements_of_imported_posts();
329 257
330 258 Plugin::$instance->uploads_manager->remove_file_or_dir( $this->extracted_directory_path );
@@ -330,129 +258,8 @@
330 258 Plugin::$instance->uploads_manager->remove_file_or_dir( $this->extracted_directory_path );
331 259 return $this->imported_data;
332 260 }
333 261
334 - /**
335 - * Run specific runner by runner_name
336 - *
337 - * @param string $runner_name
338 - *
339 - * @return array
340 - *
341 - * @throws \Exception If no export runners have been specified.
342 - */
343 - public function run_runner( string $runner_name ): array {
344 - if ( empty( $this->runners ) ) {
345 - throw new \Exception( 'Couldn’t execute the import process because no import runners have been specified. Try again by specifying import runners.' );
346 - }
347 -
348 - $data = [
349 - 'session_id' => $this->session_id,
350 - 'include' => $this->settings_include,
351 - 'manifest' => $this->manifest,
352 - 'site_settings' => $this->site_settings,
353 - 'selected_plugins' => $this->settings_selected_plugins,
354 - 'extracted_directory_path' => $this->extracted_directory_path,
355 - 'selected_custom_post_types' => $this->settings_selected_custom_post_types,
356 - ];
357 -
358 - add_filter( 'elementor/document/save/data', [ $this, 'prevent_saving_elements_on_post_creation' ], 10, 2 );
359 -
360 - // Set the Request's state as an Elementor upload request, in order to support unfiltered file uploads.
361 - Plugin::$instance->uploads_manager->set_elementor_upload_state( true );
362 -
363 - $runner = $this->runners[ $runner_name ];
364 -
365 - if ( empty( $runner ) ) {
366 - throw new \Exception( 'Couldn’t execute the import process because the import runner was not found. Try again by specifying an import runner.' );
367 - }
368 -
369 - if ( $runner->should_import( $data ) ) {
370 - $import = $runner->import( $data, $this->imported_data );
371 - $this->imported_data = array_merge_recursive( $this->imported_data, $import );
372 -
373 - $this->runners_import_metadata[ $runner::get_name() ] = $runner->get_import_session_metadata();
374 - }
375 -
376 - // After the upload complete, set the elementor upload state back to false.
377 - Plugin::$instance->uploads_manager->set_elementor_upload_state( false );
378 -
379 - remove_filter( 'elementor/document/save/data', [ $this, 'prevent_saving_elements_on_post_creation' ], 10 );
380 -
381 - $is_last_runner = key( array_slice( $this->runners, -1, 1, true ) ) === $runner_name;
382 - if ( $is_last_runner ) {
383 - $this->finalize_import_session_option();
384 - $this->save_elements_of_imported_posts();
385 - } else {
386 - $this->update_instance_data_in_import_session_option();
387 - }
388 -
389 - return [
390 - 'status' => 'success',
391 - 'runner' => $runner_name,
392 - ];
393 - }
394 -
395 - /**
396 - * Create and save all the instance data to the import sessions option.
397 - *
398 - * @return void
399 - */
400 - public function init_import_session( $save_instance_data = false ) {
401 - $import_sessions = Utils::get_import_sessions( true );
402 -
403 - $import_sessions[ $this->session_id ] = [
404 - 'session_id' => $this->session_id,
405 - 'kit_title' => $this->manifest['title'] ?? '',
406 - 'kit_name' => $this->manifest['name'] ?? '',
407 - 'kit_thumbnail' => $this->get_kit_thumbnail(),
408 - 'kit_source' => $this->settings_referrer,
409 - 'user_id' => get_current_user_id(),
410 - 'start_timestamp' => current_time( 'timestamp' ),
411 - ];
412 -
413 - if ( $save_instance_data ) {
414 - $import_sessions[ $this->session_id ]['instance_data'] = [
415 - 'extracted_directory_path' => $this->extracted_directory_path,
416 - 'runners' => $this->runners,
417 - 'adapters' => $this->adapters,
418 -
419 - 'manifest' => $this->manifest,
420 - 'site_settings' => $this->site_settings,
421 -
422 - 'settings_include' => $this->settings_include,
423 - 'settings_referrer' => $this->settings_referrer,
424 - 'settings_conflicts' => $this->settings_conflicts,
425 - 'settings_selected_override_conditions' => $this->settings_selected_override_conditions,
426 - 'settings_selected_custom_post_types' => $this->settings_selected_custom_post_types,
427 - 'settings_selected_plugins' => $this->settings_selected_plugins,
428 -
429 - 'documents_data' => $this->documents_data,
430 - 'imported_data' => $this->imported_data,
431 - 'runners_import_metadata' => $this->runners_import_metadata,
432 - ];
433 - }
434 -
435 - update_option( Module::OPTION_KEY_ELEMENTOR_IMPORT_SESSIONS, $import_sessions, false );
436 - }
437 -
438 - /**
439 - * Get the Kit thumbnail, goes to the home page thumbnail if main doesn't exist
440 - *
441 - * @return string
442 - */
443 - private function get_kit_thumbnail(): string {
444 - if ( ! empty( $this->manifest['thumbnail'] ) ) {
445 - return $this->manifest['thumbnail'];
446 - }
447 -
448 - return apply_filters( 'elementor/import/kit_thumbnail', '', $this->kit_id, $this->settings_referrer );
449 - }
450 -
451 - public function get_runners_name(): array {
452 - return array_keys( $this->runners );
453 - }
454 -
455 262 public function get_manifest() {
456 263 return $this->manifest;
457 264 }
458 265
@@ -467,12 +274,8 @@
467 274 public function get_adapters() {
468 275 return $this->adapters;
469 276 }
470 277
471 - public function get_imported_data() {
472 - return $this->imported_data;
473 - }
474 -
475 278 /**
476 279 * Get settings by key.
477 280 * Used for backward compatibility.
478 281 *
@@ -559,9 +362,9 @@
559 362
560 363 /**
561 364 * Prevent saving elements on elementor post creation.
562 365 *
563 - * @param array $data
366 + * @param array $data
564 367 * @param Document $document
565 368 *
566 369 * @return array
567 370 */
@@ -566,18 +369,13 @@
566 369 * @return array
567 370 */
568 371 public function prevent_saving_elements_on_post_creation( array $data, Document $document ) {
569 372 if ( isset( $data['elements'] ) ) {
570 - $this->documents_data[ $document->get_main_id() ] = [ 'elements' => $data['elements'] ];
373 + $this->documents_elements[ $document->get_main_id() ] = $data['elements'];
571 374
572 375 $data['elements'] = [];
573 376 }
574 377
575 - if ( isset( $data['settings'] ) ) {
576 - $this->documents_data[ $document->get_main_id() ]['settings'] = $data['settings'];
577 -
578 - }
579 -
580 378 return $data;
581 379 }
582 380
583 381 /**
@@ -584,19 +382,14 @@
584 382 * Extract the zip file.
585 383 *
586 384 * @param string $zip_path The path to the zip file.
587 385 * @return string The extracted directory path.
588 - * @throws \Error If import process fails, file validation errors occur, or data corruption is detected.
589 386 */
590 387 private function extract_zip( $zip_path ) {
591 388 $extraction_result = Plugin::$instance->uploads_manager->extract_and_validate_zip( $zip_path, [ 'json', 'xml' ] );
592 389
593 390 if ( is_wp_error( $extraction_result ) ) {
594 - if ( isset( $extraction_result->errors['zip_error'] ) ) {
595 - throw new \Error( static::ZIP_ARCHIVE_ERROR_KEY ); // phpcs:ignore WordPress.Security.EscapeOutput.ExceptionNotEscaped
596 - }
597 -
598 - throw new \Error( static::ZIP_FILE_ERROR_KEY ); // phpcs:ignore WordPress.Security.EscapeOutput.ExceptionNotEscaped
391 + throw new \Error( static::ZIP_FILE_ERROR_KEY );
599 392 }
600 393
601 394 return $extraction_result['extraction_directory'];
602 395 }
@@ -604,17 +397,14 @@
604 397 /**
605 398 * Get the manifest file from the extracted directory and adapt it if needed.
606 399 *
607 400 * @return string The manifest file content.
608 - *
609 - * @throws \Error If import validation fails or processing errors occur.
610 401 */
611 402 private function read_manifest_json() {
612 403 $manifest = Utils::read_json_file( $this->extracted_directory_path . 'manifest' );
613 404
614 405 if ( ! $manifest ) {
615 - Plugin::$instance->logger->get_logger()->error( static::MANIFEST_ERROR_KEY );
616 - throw new \Error( static::ZIP_FILE_ERROR_KEY ); // phpcs:ignore WordPress.Security.EscapeOutput.ExceptionNotEscaped
406 + throw new \Error( static::MANIFEST_ERROR_KEY );
617 407 }
618 408
619 409 $this->init_adapters( $manifest );
620 410
@@ -721,9 +511,9 @@
721 511 * Get the data that requires updating/replacement when imported.
722 512 *
723 513 * @return array{post_ids: array, term_ids: array}
724 514 */
725 - private function get_imported_data_replacements(): array {
515 + private function get_imported_data_replacements() : array {
726 516 return [
727 517 'post_ids' => Utils::map_old_new_post_ids( $this->imported_data ),
728 518 'term_ids' => Utils::map_old_new_term_ids( $this->imported_data ),
729 519 ];
@@ -733,67 +523,27 @@
733 523 * Save the prevented elements on elementor post creation elements.
734 524 * Handle the replacement of all the dynamic content of the elements that probably have been changed during the import.
735 525 */
736 526 private function save_elements_of_imported_posts() {
737 - $imported_data_replacements = $this->get_imported_data_replacements();
738 -
739 - foreach ( $this->documents_data as $new_id => $data ) {
527 + foreach ( $this->documents_elements as $new_id => $document_elements ) {
740 528 $document = Plugin::$instance->documents->get( $new_id );
741 -
742 - if ( isset( $data['elements'] ) ) {
743 - $data['elements'] = $document->on_import_update_dynamic_content( $data['elements'], $imported_data_replacements );
744 - }
745 -
746 - if ( isset( $data['settings'] ) ) {
747 -
748 - if ( $document instanceof Kit ) {
749 - // Without post_status certain tabs in the Kit will not save properly.
750 - $data['settings']['post_status'] = get_post_status( $new_id );
751 - }
752 -
753 - $data['settings'] = $document->on_import_update_settings( $data['settings'], $imported_data_replacements );
754 - }
755 -
756 - $document->save( $data );
529 + $updated_elements = $document->on_import_update_dynamic_content( $document_elements, $this->get_imported_data_replacements() );
530 + $document->save( [ 'elements' => $updated_elements ] );
757 531 }
758 532 }
759 533
760 - private function update_instance_data_in_import_session_option() {
761 - $import_sessions = Utils::get_import_sessions();
534 + private function add_import_session_option( $start_time ) {
535 + $import_sessions = get_option( Module::OPTION_KEY_ELEMENTOR_IMPORT_SESSIONS );
762 536
763 - $import_sessions[ $this->session_id ]['instance_data']['documents_data'] = $this->documents_data;
764 - $import_sessions[ $this->session_id ]['instance_data']['imported_data'] = $this->imported_data;
765 - $import_sessions[ $this->session_id ]['instance_data']['runners_import_metadata'] = $this->runners_import_metadata;
537 + $import_sessions[ time() ] = [
538 + 'session_id' => $this->session_id,
539 + 'kit_name' => $this->manifest['name'],
540 + 'kit_source' => $this->settings_referrer,
541 + 'user_id' => get_current_user_id(),
542 + 'start_timestamp' => $start_time,
543 + 'end_timestamp' => current_time( 'timestamp' ),
544 + 'runners' => $this->runners_import_metadata,
545 + ];
766 546
767 547 update_option( Module::OPTION_KEY_ELEMENTOR_IMPORT_SESSIONS, $import_sessions, false );
768 - }
769 -
770 - public function finalize_import_session_option() {
771 - $import_sessions = Utils::get_import_sessions();
772 -
773 - if ( ! isset( $import_sessions[ $this->session_id ] ) ) {
774 - return;
775 - }
776 -
777 - unset( $import_sessions[ $this->session_id ]['instance_data'] );
778 -
779 - $import_sessions[ $this->session_id ]['end_timestamp'] = current_time( 'timestamp' );
780 - $import_sessions[ $this->session_id ]['runners'] = $this->runners_import_metadata;
781 -
782 - update_option( Module::OPTION_KEY_ELEMENTOR_IMPORT_SESSIONS, $import_sessions, false );
783 - }
784 -
785 - /**
786 - * Filter the php error args and return 408 status code if the error is a timeout.
787 - *
788 - * @param array $args
789 - * @param array $error
790 - * @return array
791 - */
792 - private function filter_php_error_args( $args, $error ) {
793 - if ( strpos( $error['message'], 'Maximum execution time' ) !== false ) {
794 - $args['response'] = 408;
795 - }
796 -
797 - return $args;
798 548 }
799 549 }