PluginProbe
Elementor Website Builder – more than just a page builder / 3.32.2
Elementor Website Builder – more than just a page builder v3.32.2
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 | includes/template-library/manager.php +221 -160 4.1.23.32.2 View file →
@@ -2,12 +2,15 @@
2 2 namespace Elementor\TemplateLibrary;
3 3
4 4 use Elementor\Api;
5 5 use Elementor\Core\Common\Modules\Ajax\Module as Ajax;
6 +use Elementor\Core\Isolation\Wordpress_Adapter;
7 +use Elementor\Core\Isolation\Wordpress_Adapter_Interface;
8 +use Elementor\Core\Isolation\Elementor_Adapter;
9 +use Elementor\Core\Isolation\Elementor_Adapter_Interface;
6 10 use Elementor\Core\Settings\Manager as SettingsManager;
7 11 use Elementor\Includes\TemplateLibrary\Data\Controller;
8 12 use Elementor\TemplateLibrary\Classes\Import_Images;
9 -use Elementor\Core\Utils\Template_Library_Import_Export_Utils;
10 13 use Elementor\Plugin;
11 14 use Elementor\User;
12 15 use Elementor\Utils;
13 16
@@ -24,11 +27,8 @@
24 27 * @since 1.0.0
25 28 */
26 29 class Manager {
27 30
28 - const ERROR_TEMPLATE_SOURCE_NOT_FOUND = 'Template source not found.';
29 - const ERROR_TEMPLATE_IDS_MISSING = 'Template IDs are missing.';
30 -
31 31 /**
32 32 * Registered template sources.
33 33 *
34 34 * Holds a list of all the supported sources with their instances.
@@ -50,8 +50,18 @@
50 50 */
51 51 private $_import_images = null; // phpcs:ignore PSR2.Classes.PropertyDeclaration.Underscore
52 52
53 53 /**
54 + * @var Wordpress_Adapter_Interface
55 + */
56 + protected $wordpress_adapter = null;
57 +
58 + /**
59 + * @var Elementor_Adapter_Interface
60 + */
61 + protected $elementor_adapter = null;
62 +
63 + /**
54 64 * Template library manager constructor.
55 65 *
56 66 * Initializing the template library manager by registering default template
57 67 * sources and initializing ajax calls.
@@ -93,8 +103,16 @@
93 103
94 104 return $this->_import_images;
95 105 }
96 106
107 + public function set_wordpress_adapter( Wordpress_Adapter_Interface $wordpress_adapter ) {
108 + $this->wordpress_adapter = $wordpress_adapter;
109 + }
110 +
111 + public function set_elementor_adapter( Elementor_Adapter_Interface $elementor_adapter ): void {
112 + $this->elementor_adapter = $elementor_adapter;
113 + }
114 +
97 115 /**
98 116 * Register template source.
99 117 *
100 118 * Used to register new template sources displayed in the template library.
@@ -282,9 +300,9 @@
282 300 private function save_template_item( array $args ) {
283 301 $source = $this->get_source( $args['source'] );
284 302
285 303 if ( ! $source ) {
286 - return new \WP_Error( 'template_error', self::ERROR_TEMPLATE_SOURCE_NOT_FOUND );
304 + return new \WP_Error( 'template_error', 'Template source not found.' );
287 305 }
288 306
289 307 $args['content'] = json_decode( $args['content'], true );
290 308
@@ -331,9 +349,9 @@
331 349
332 350 $source = $this->get_source( $args['source'] );
333 351
334 352 if ( ! $source ) {
335 - return new \WP_Error( 'template_error', self::ERROR_TEMPLATE_SOURCE_NOT_FOUND );
353 + return new \WP_Error( 'template_error', 'Template source not found.' );
336 354 }
337 355
338 356 if ( $this->is_action_to_same_source( $args ) ) {
339 357 return $source->move_template_to_folder( $args );
@@ -338,16 +356,16 @@
338 356 if ( $this->is_action_to_same_source( $args ) ) {
339 357 return $source->move_template_to_folder( $args );
340 358 }
341 359
342 - $from_source = $this->get_source( $args['from_source'] );
360 + if ( 'local' === $args['from_source'] ) {
361 + $args = $this->format_args_for_single_action_from_local_to_cloud( $args );
362 + }
343 363
344 - if ( ! $from_source ) {
345 - return new \WP_Error( 'template_error', self::ERROR_TEMPLATE_SOURCE_NOT_FOUND );
364 + if ( 'cloud' === $args['from_source'] ) {
365 + $args = $this->format_args_for_single_action_from_cloud_to_local( $args );
346 366 }
347 367
348 - $args = $from_source->format_args_for_single_action( $args );
349 -
350 368 $template_id = $source->save_item( $args );
351 369
352 370 if ( is_wp_error( $template_id ) ) {
353 371 return $template_id;
@@ -365,19 +383,19 @@
365 383
366 384 $source = $this->get_source( $args['source'][0] );
367 385
368 386 if ( ! $source ) {
369 - return new \WP_Error( 'template_error', self::ERROR_TEMPLATE_SOURCE_NOT_FOUND );
387 + return new \WP_Error( 'template_error', 'Template source not found.' );
370 388 }
371 389
372 - $from_source = $this->get_source( $args['from_source'] );
390 + if ( 'local' === $args['from_source'] ) {
391 + $args = $this->format_args_for_single_action_from_local_to_cloud( $args );
392 + }
373 393
374 - if ( ! $from_source ) {
375 - return new \WP_Error( 'template_error', self::ERROR_TEMPLATE_SOURCE_NOT_FOUND );
394 + if ( 'cloud' === $args['from_source'] ) {
395 + $args = $this->format_args_for_single_action_from_cloud_to_local( $args );
376 396 }
377 397
378 - $args = $from_source->format_args_for_single_action( $args );
379 -
380 398 $template_id = $source->save_item( $args );
381 399
382 400 if ( is_wp_error( $template_id ) ) {
383 401 return $template_id;
@@ -389,8 +407,53 @@
389 407 private function is_action_to_same_source( $args ) {
390 408 return $args['source'] === $args['from_source'];
391 409 }
392 410
411 + private function format_args_for_single_action_from_local_to_cloud( $args ) {
412 + if ( ! $this->is_allowed_to_read_template( [
413 + 'source' => $args['from_source'],
414 + 'template_id' => $args['from_template_id'],
415 + ] ) ) {
416 + return new \WP_Error(
417 + 'template_error',
418 + esc_html__( 'You do not have permission to access this template.', 'elementor' )
419 + );
420 + }
421 +
422 + $document = Plugin::$instance->documents->get( $args['from_template_id'] );
423 +
424 + if ( ! $document ) {
425 + return new \WP_Error( 'template_error', 'Document not found.' );
426 + }
427 +
428 + $args['content'] = $document->get_elements_data();
429 +
430 + $page = SettingsManager::get_settings_managers( 'page' )->get_model( $args['from_template_id'] );
431 + $args['page_settings'] = $page->get_data( 'settings' );
432 +
433 + return $args;
434 + }
435 +
436 + private function format_args_for_single_action_from_cloud_to_local( $args ) {
437 + $from_source = $this->get_source( $args['from_source'] );
438 +
439 + if ( ! $from_source ) {
440 + return new \WP_Error( 'template_error', 'Template source not found.' );
441 + }
442 +
443 + $data = $from_source->get_item( $args['from_template_id'] );
444 +
445 + if ( is_wp_error( $data ) || empty( $data['content'] ) ) {
446 + return new \WP_Error( 'template_error', 'Unable to format template args.' );
447 + }
448 +
449 + $decoded_data = json_decode( $data['content'], true );
450 + $args['content'] = $decoded_data['content'];
451 + $args['page_settings'] = $decoded_data['page_settings'];
452 +
453 + return $args;
454 + }
455 +
393 456 /**
394 457 * Update template.
395 458 *
396 459 * Update template on the database.
@@ -412,9 +475,9 @@
412 475
413 476 $source = $this->get_source( $template_data['source'] );
414 477
415 478 if ( ! $source ) {
416 - return new \WP_Error( 'template_error', self::ERROR_TEMPLATE_SOURCE_NOT_FOUND );
479 + return new \WP_Error( 'template_error', 'Template source not found.' );
417 480 }
418 481
419 482 $template_data['content'] = json_decode( $template_data['content'], true );
420 483
@@ -436,9 +499,9 @@
436 499
437 500 $source = $this->get_source( $template_data['source'] );
438 501
439 502 if ( ! $source ) {
440 - return new \WP_Error( 'template_error', self::ERROR_TEMPLATE_SOURCE_NOT_FOUND );
503 + return new \WP_Error( 'template_error', 'Template source not found.' );
441 504 }
442 505
443 506 $update = $source->update_item( $template_data );
444 507
@@ -491,15 +554,9 @@
491 554 if ( is_wp_error( $validate_args ) ) {
492 555 return $validate_args;
493 556 }
494 557
495 - $source = $this->get_source( $args['source'] );
496 -
497 - if ( ! $source ) {
498 - return new \WP_Error( 'template_error', self::ERROR_TEMPLATE_SOURCE_NOT_FOUND );
499 - }
500 -
501 - if ( method_exists( $source, 'is_allowed_to_read_template' ) && ! $source->is_allowed_to_read_template( $args ) ) {
558 + if ( ! $this->is_allowed_to_read_template( $args ) ) {
502 559 return new \WP_Error(
503 560 'template_error',
504 561 esc_html__( 'You do not have permission to access this template.', 'elementor' )
505 562 );
@@ -508,8 +565,14 @@
508 565 if ( isset( $args['edit_mode'] ) ) {
509 566 Plugin::$instance->editor->set_edit_mode( $args['edit_mode'] );
510 567 }
511 568
569 + $source = $this->get_source( $args['source'] );
570 +
571 + if ( ! $source ) {
572 + return new \WP_Error( 'template_error', 'Template source not found.' );
573 + }
574 +
512 575 do_action( 'elementor/template-library/before_get_source_data', $args, $source );
513 576
514 577 $data = $source->get_data( $args );
515 578
@@ -540,9 +603,9 @@
540 603
541 604 $source = $this->get_source( $args['source'] );
542 605
543 606 if ( ! $source ) {
544 - return new \WP_Error( 'template_error', self::ERROR_TEMPLATE_SOURCE_NOT_FOUND );
607 + return new \WP_Error( 'template_error', 'Template source not found.' );
545 608 }
546 609
547 610 return $source->delete_template( $args['template_id'] );
548 611 }
@@ -569,9 +632,9 @@
569 632
570 633 $source = $this->get_source( $args['source'] );
571 634
572 635 if ( ! $source ) {
573 - return new \WP_Error( 'template_error', self::ERROR_TEMPLATE_SOURCE_NOT_FOUND );
636 + return new \WP_Error( 'template_error', 'Template source not found' );
574 637 }
575 638
576 639 return $source->export_template( $args['template_id'] );
577 640 }
@@ -610,15 +673,16 @@
610 673 remove_filter( 'elementor/files/allow-file-type/json', [ $this, 'enable_json_template_upload' ] );
611 674 remove_filter( 'elementor/files/allow_unfiltered_upload', [ $this, 'enable_json_template_upload' ] );
612 675
613 676 if ( is_wp_error( $upload_result ) ) {
677 + Plugin::$instance->uploads_manager->remove_file_or_dir( dirname( $upload_result['tmp_name'] ) );
678 +
614 679 return $upload_result;
615 680 }
616 681
617 682 $source = $this->get_source( $data['source'] ?? 'local' );
618 683
619 - $import_mode = $data['import_mode'] ?? 'match_site';
620 - $import_result = $source->import_template( $upload_result['name'], $upload_result['tmp_name'], $import_mode );
684 + $import_result = $source->import_template( $upload_result['name'], $upload_result['tmp_name'] );
621 685
622 686 // Remove the temporary directory generated for the stream-uploaded file.
623 687 Plugin::$instance->uploads_manager->remove_file_or_dir( dirname( $upload_result['tmp_name'] ) );
624 688
@@ -678,103 +742,11 @@
678 742 }
679 743
680 744 $import_data = $document->get_import_data( [ 'content' => $elements ] );
681 745
682 - $content = $document::on_import_update_dynamic_content(
683 - $import_data['content'],
684 - [ 'post_ids' => [] ]
685 - );
686 -
687 - return Plugin::$instance->db->iterate_data( $content, function( $element_data ) {
688 - unset( $element_data['htmlCache'] );
689 - return $element_data;
690 - } );
746 + return $import_data['content'];
691 747 }
692 748
693 - public function process_global_styles( array $args ) {
694 - $validate_args = $this->ensure_args( [ 'content', 'import_mode' ], $args );
695 -
696 - if ( is_wp_error( $validate_args ) ) {
697 - return $validate_args;
698 - }
699 -
700 - $import_mode = Template_Library_Import_Export_Utils::sanitize_import_mode( $args['import_mode'] );
701 -
702 - $content = $this->get_validated_json_arg( $args, 'content' );
703 - if ( is_wp_error( $content ) ) {
704 - return $content;
705 - }
706 -
707 - $global_classes = $this->get_validated_json_arg( $args, 'global_classes', true );
708 - if ( is_wp_error( $global_classes ) ) {
709 - return $global_classes;
710 - }
711 -
712 - $global_variables = $this->get_validated_json_arg( $args, 'global_variables', true );
713 - if ( is_wp_error( $global_variables ) ) {
714 - return $global_variables;
715 - }
716 -
717 - $data = [
718 - 'global_classes' => $global_classes,
719 - 'global_variables' => $global_variables,
720 - ];
721 -
722 - $result = apply_filters(
723 - 'elementor/template_library/import/process_content',
724 - [ 'content' => $content ],
725 - $import_mode,
726 - $data,
727 - null
728 - );
729 -
730 - $response = [
731 - 'content' => $result['content'],
732 - ];
733 -
734 - if ( ! empty( $result['updated_global_classes'] ) ) {
735 - $response['updated_global_classes'] = $result['updated_global_classes'];
736 - }
737 -
738 - if ( ! empty( $result['updated_global_variables'] ) ) {
739 - $response['updated_global_variables'] = $result['updated_global_variables'];
740 - }
741 -
742 - $classes_to_flatten = $result['classes_to_flatten'] ?? [];
743 - $variables_to_flatten = $result['variables_to_flatten'] ?? [];
744 -
745 - if ( ! empty( $classes_to_flatten ) ) {
746 - $response['flattened_classes_count'] = count( $classes_to_flatten );
747 - }
748 -
749 - if ( ! empty( $variables_to_flatten ) ) {
750 - $response['flattened_variables_count'] = count( $variables_to_flatten );
751 - }
752 -
753 - return $response;
754 - }
755 -
756 - private function get_validated_json_arg( array $args, string $key, bool $is_optional = false ) {
757 - if ( ! array_key_exists( $key, $args ) || null === $args[ $key ] || '' === $args[ $key ] ) {
758 - return $is_optional ? null : new \WP_Error( "invalid_$key", "Invalid $key." );
759 - }
760 -
761 - $value = $args[ $key ];
762 - if ( is_string( $value ) ) {
763 - $decoded = json_decode( $value, true );
764 - if ( JSON_ERROR_NONE !== json_last_error() ) {
765 - return new \WP_Error( "invalid_$key", "Invalid JSON $key." );
766 - }
767 - return $decoded;
768 - }
769 -
770 - if ( ! is_array( $value ) ) {
771 - return new \WP_Error( "invalid_$key", "Invalid $key format." );
772 - }
773 -
774 - return $value;
775 - }
776 -
777 749 public function get_item_children( array $args ) {
778 750 $validate_args = $this->ensure_args( [ 'source', 'template_id' ], $args );
779 751
780 752 if ( is_wp_error( $validate_args ) ) {
@@ -783,9 +755,9 @@
783 755
784 756 $source = $this->get_source( $args['source'] );
785 757
786 758 if ( ! $source ) {
787 - return new \WP_Error( 'template_error', self::ERROR_TEMPLATE_SOURCE_NOT_FOUND );
759 + return new \WP_Error( 'template_error', 'Template source not found.' );
788 760 }
789 761
790 762 return $source->get_item_children( $args );
791 763 }
@@ -799,9 +771,9 @@
799 771
800 772 $source = $this->get_source( $args['source'] );
801 773
802 774 if ( ! $source ) {
803 - return new \WP_Error( 'template_error', self::ERROR_TEMPLATE_SOURCE_NOT_FOUND );
775 + return new \WP_Error( 'template_error', 'Template source not found.' );
804 776 }
805 777
806 778 return $source->search_templates( $args );
807 779 }
@@ -815,9 +787,9 @@
815 787
816 788 $source = $this->get_source( $args['source'] );
817 789
818 790 if ( ! $source ) {
819 - return new \WP_Error( 'template_error', self::ERROR_TEMPLATE_SOURCE_NOT_FOUND );
791 + return new \WP_Error( 'template_error', 'Template source not found.' );
820 792 }
821 793
822 794 return $source->get_items( $args );
823 795 }
@@ -831,9 +803,9 @@
831 803
832 804 $source = $this->get_source( $args['source'] );
833 805
834 806 if ( ! $source ) {
835 - return new \WP_Error( 'template_error', self::ERROR_TEMPLATE_SOURCE_NOT_FOUND );
807 + return new \WP_Error( 'template_error', 'Template source not found.' );
836 808 }
837 809
838 810 return $source->save_folder( $args );
839 811 }
@@ -892,9 +864,9 @@
892 864 *
893 865 * @param array $data
894 866 *
895 867 * @return mixed
896 - * @throws \Exception If current user has no permission or the post is not found.
868 + * @throws \Exception If the user has no permission or the post is not found.
897 869 */
898 870 private function handle_ajax_request( $ajax_request, array $data ) {
899 871 if ( ! User::is_current_user_can_edit_post_type( Source_Local::CPT ) ) {
900 872 throw new \Exception( 'Access denied.' );
@@ -915,13 +887,13 @@
915 887 if ( is_wp_error( $result ) ) {
916 888 throw new \Exception( esc_html( $result->get_error_message() ) );
917 889 }
918 890
919 - return $result;
891 + return $result; // phpcs:ignore WordPress.Security.EscapeOutput.ExceptionNotEscaped
920 892 }
921 893
922 894 /**
923 - * @throws \Exception If template import fails, file validation errors occur, or processing encounters issues.
895 + * @throws \Exception
924 896 */
925 897 public function save_template_screenshot( $data ): string {
926 898 $validate_args = $this->ensure_args( [ 'template_id', 'screenshot' ], $data );
927 899
@@ -934,9 +906,9 @@
934 906 return $this->get_source( 'cloud' )->save_item_preview( $data['template_id'], $raw_binary );
935 907 }
936 908
937 909 /**
938 - * @throws \Exception If template processing fails or data validation errors occur.
910 + * @throws \Exception
939 911 */
940 912 public function template_screenshot_failed( $data ): string {
941 913 $validate_args = $this->ensure_args( [ 'template_id' ], $data );
942 914
@@ -956,13 +928,13 @@
956 928
957 929 $source = $this->get_source( $data['source'] );
958 930
959 931 if ( ! $source ) {
960 - return new \WP_Error( 'template_error', self::ERROR_TEMPLATE_SOURCE_NOT_FOUND );
932 + return new \WP_Error( 'template_error', 'Template source not found.' );
961 933 }
962 934
963 935 if ( empty( $data['template_ids'] ) || ! is_array( $data['template_ids'] ) ) {
964 - return new \WP_Error( 'template_error', self::ERROR_TEMPLATE_IDS_MISSING );
936 + return new \WP_Error( 'template_error', 'Template IDs are missing.' );
965 937 }
966 938
967 939 return $source->bulk_delete_items( $data['template_ids'] );
968 940 }
@@ -976,13 +948,13 @@
976 948
977 949 $source = $this->get_source( $data['source'] );
978 950
979 951 if ( ! $source ) {
980 - return new \WP_Error( 'template_error', self::ERROR_TEMPLATE_SOURCE_NOT_FOUND );
952 + return new \WP_Error( 'template_error', 'Template source not found.' );
981 953 }
982 954
983 955 if ( empty( $data['template_ids'] ) || ! is_array( $data['template_ids'] ) ) {
984 - return new \WP_Error( 'template_error', self::ERROR_TEMPLATE_IDS_MISSING );
956 + return new \WP_Error( 'template_error', 'Template IDs are missing.' );
985 957 }
986 958
987 959 return $source->bulk_undo_delete_items( $data['template_ids'] );
988 960 }
@@ -1021,9 +993,8 @@
1021 993 'bulk_copy_templates',
1022 994 'bulk_undo_delete_items',
1023 995 'get_templates_quota',
1024 996 'template_screenshot_failed',
1025 - 'process_global_styles',
1026 997 ];
1027 998
1028 999 foreach ( $library_ajax_requests as $ajax_request ) {
1029 1000 $ajax->register_ajax_action( $ajax_request, function( $data ) use ( $ajax_request ) {
@@ -1124,8 +1095,46 @@
1124 1095
1125 1096 return true;
1126 1097 }
1127 1098
1099 + private function is_allowed_to_read_template( array $args ): bool {
1100 + if ( 'remote' === $args['source'] || 'cloud' === $args['source'] ) {
1101 + return true;
1102 + }
1103 +
1104 + if ( null === $this->wordpress_adapter ) {
1105 + $this->set_wordpress_adapter( new WordPress_Adapter() );
1106 + }
1107 +
1108 + if ( ! $this->should_check_permissions( $args ) ) {
1109 + return true;
1110 + }
1111 +
1112 + $post_id = intval( $args['template_id'] );
1113 + $post_status = $this->wordpress_adapter->get_post_status( $post_id );
1114 + $is_private_or_non_published = ( 'private' === $post_status && ! $this->wordpress_adapter->current_user_can( 'read_private_posts', $post_id ) ) || ( 'publish' !== $post_status );
1115 +
1116 + $can_read_template = $is_private_or_non_published || $this->wordpress_adapter->current_user_can( 'edit_post', $post_id );
1117 +
1118 + return apply_filters( 'elementor/template-library/is_allowed_to_read_template', $can_read_template, $args );
1119 + }
1120 +
1121 + private function should_check_permissions( array $args ): bool {
1122 + if ( null === $this->elementor_adapter ) {
1123 + $this->set_elementor_adapter( new Elementor_Adapter() );
1124 + }
1125 +
1126 + // TODO: Remove $isWidgetTemplate in 3.28.0 as there is a Pro dependency
1127 + $check_permissions = isset( $args['check_permissions'] ) && false === $args['check_permissions'];
1128 + $is_widget_template = 'widget' === $this->elementor_adapter->get_template_type( $args['template_id'] );
1129 +
1130 + if ( $check_permissions || $is_widget_template ) {
1131 + return false;
1132 + }
1133 +
1134 + return true;
1135 + }
1136 +
1128 1137 public function bulk_move_templates( array $args ) {
1129 1138 $validate_args = $this->ensure_args( [ 'source', 'from_source', 'from_template_id' ], $args );
1130 1139
1131 1140 if ( is_wp_error( $validate_args ) ) {
@@ -1140,9 +1149,9 @@
1140 1149 private function bulk_move_template_items( array $args ) {
1141 1150 $source = $this->get_source( $args['source'] );
1142 1151
1143 1152 if ( ! $source ) {
1144 - return new \WP_Error( 'template_error', self::ERROR_TEMPLATE_SOURCE_NOT_FOUND );
1153 + return new \WP_Error( 'template_error', 'Template source not found.' );
1145 1154 }
1146 1155
1147 1156 if ( $this->is_action_to_same_source( $args ) ) {
1148 1157 return $source->move_bulk_templates_to_folder( $args );
@@ -1147,24 +1156,20 @@
1147 1156 if ( $this->is_action_to_same_source( $args ) ) {
1148 1157 return $source->move_bulk_templates_to_folder( $args );
1149 1158 }
1150 1159
1151 - $from_source = $this->get_source( $args['from_source'] );
1160 + $bulk_args = 'local' === $args['from_source']
1161 + ? $this->format_args_for_bulk_action_from_local( $args )
1162 + : $this->format_args_for_bulk_action_from_cloud( $args );
1152 1163
1153 - if ( ! $from_source ) {
1154 - return new \WP_Error( 'template_error', self::ERROR_TEMPLATE_SOURCE_NOT_FOUND );
1155 - }
1156 -
1157 - $bulk_args = $from_source->format_args_for_bulk_action( $args );
1158 -
1159 1164 if ( $source->supports_quota() && ! $this->is_action_to_same_source( $args ) ) {
1160 - $quota_validation = $source->validate_quota( $bulk_args );
1165 + $is_quota_valid = $source->validate_quota( $bulk_args );
1161 1166
1162 - if ( is_wp_error( $quota_validation ) ) {
1163 - return $quota_validation;
1167 + if ( is_wp_error( $is_quota_valid ) ) {
1168 + return $is_quota_valid;
1164 1169 }
1165 1170
1166 - if ( false === $quota_validation ) {
1171 + if ( ! $is_quota_valid ) {
1167 1172 return new \WP_Error( 'quota_error', 'The moving failed because it will pass the maximum templates you can save.' );
1168 1173 }
1169 1174 }
1170 1175
@@ -1179,8 +1184,68 @@
1179 1184
1180 1185 return $bulk_save;
1181 1186 }
1182 1187
1188 + private function format_args_for_bulk_action_from_local( $args ) {
1189 + $bulk_args = [];
1190 +
1191 + foreach ( $args['from_template_id'] as $from_template_id ) {
1192 + if ( ! $this->is_allowed_to_read_template( [
1193 + 'source' => $args['from_source'],
1194 + 'template_id' => $from_template_id,
1195 + ] ) ) {
1196 + continue;
1197 + }
1198 +
1199 + $document = Plugin::$instance->documents->get( $from_template_id );
1200 +
1201 + if ( ! $document ) {
1202 + continue;
1203 + }
1204 +
1205 + $page = SettingsManager::get_settings_managers( 'page' )->get_model( $from_template_id );
1206 +
1207 + $bulk_args[] = array_merge(
1208 + $args,
1209 + [
1210 + 'title' => $document->get_post()->post_title,
1211 + 'type' => $document::get_type(),
1212 + 'content' => $document->get_elements_data(),
1213 + 'page_settings' => $page->get_data( 'settings' ),
1214 + ]
1215 + );
1216 + }
1217 +
1218 + return $bulk_args;
1219 + }
1220 +
1221 + private function format_args_for_bulk_action_from_cloud( $args ) {
1222 + $from_source = $this->get_source( $args['from_source'] );
1223 +
1224 + if ( ! $from_source ) {
1225 + return new \WP_Error( 'template_error', 'Template source not found.' );
1226 + }
1227 +
1228 + $templates = $from_source->get_bulk_items( $args );
1229 + $bulk_args = [];
1230 +
1231 + foreach ( $templates as $template ) {
1232 + $content = json_decode( $template['content'], true );
1233 +
1234 + $bulk_args[] = array_merge(
1235 + $args,
1236 + [
1237 + 'title' => $template['title'],
1238 + 'type' => $template['type'],
1239 + 'content' => $content['content'],
1240 + 'page_settings' => $content['page_settings'],
1241 + ]
1242 + );
1243 + }
1244 +
1245 + return $bulk_args;
1246 + }
1247 +
1183 1248 public function bulk_copy_templates( array $args ) {
1184 1249 $validate_args = $this->ensure_args( [ 'source', 'from_source', 'from_template_id' ], $args );
1185 1250
1186 1251 if ( is_wp_error( $validate_args ) ) {
@@ -1195,27 +1260,23 @@
1195 1260 private function bulk_copy_template_items( array $args ) {
1196 1261 $source = $this->get_source( $args['source'] );
1197 1262
1198 1263 if ( ! $source ) {
1199 - return new \WP_Error( 'template_error', self::ERROR_TEMPLATE_SOURCE_NOT_FOUND );
1264 + return new \WP_Error( 'template_error', 'Template source not found.' );
1200 1265 }
1201 1266
1202 - $from_source = $this->get_source( $args['from_source'] );
1267 + $bulk_args = 'local' === $args['from_source']
1268 + ? $this->format_args_for_bulk_action_from_local( $args )
1269 + : $this->format_args_for_bulk_action_from_cloud( $args );
1203 1270
1204 - if ( ! $from_source ) {
1205 - return new \WP_Error( 'template_error', self::ERROR_TEMPLATE_SOURCE_NOT_FOUND );
1206 - }
1207 -
1208 - $bulk_args = $from_source->format_args_for_bulk_action( $args );
1209 -
1210 1271 if ( $source->supports_quota() && ! $this->is_action_to_same_source( $args ) ) {
1211 - $quota_validation = $source->validate_quota( $bulk_args );
1272 + $is_quota_valid = $source->validate_quota( $bulk_args );
1212 1273
1213 - if ( is_wp_error( $quota_validation ) ) {
1214 - return $quota_validation;
1274 + if ( is_wp_error( $is_quota_valid ) ) {
1275 + return $is_quota_valid;
1215 1276 }
1216 1277
1217 - if ( false === $quota_validation ) {
1278 + if ( ! $is_quota_valid ) {
1218 1279 return new \WP_Error( 'quota_error', 'The copying failed because it will pass the maximum templates you can save.' );
1219 1280 }
1220 1281 }
1221 1282