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