PluginProbe
Elementor Website Builder – more than just a page builder / 3.32.0-dev3
Elementor Website Builder – more than just a page builder v3.32.0-dev3
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 +222 -178 4.3.0-beta23.32.0-dev3 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,12 +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 - const ERROR_JSON_UPLOAD_NOT_ALLOWED = 'Uploading JSON files is not allowed for this user.';
31 -
32 31 /**
33 32 * Registered template sources.
34 33 *
35 34 * Holds a list of all the supported sources with their instances.
@@ -51,8 +50,18 @@
51 50 */
52 51 private $_import_images = null; // phpcs:ignore PSR2.Classes.PropertyDeclaration.Underscore
53 52
54 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 + /**
55 64 * Template library manager constructor.
56 65 *
57 66 * Initializing the template library manager by registering default template
58 67 * sources and initializing ajax calls.
@@ -94,8 +103,16 @@
94 103
95 104 return $this->_import_images;
96 105 }
97 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 +
98 115 /**
99 116 * Register template source.
100 117 *
101 118 * Used to register new template sources displayed in the template library.
@@ -234,20 +251,12 @@
234 251 Plugin::$instance->documents->get_document_types();
235 252
236 253 $filter_sources = ! empty( $args['filter_sources'] ) ? $args['filter_sources'] : [];
237 254
238 - $full_library_data = [
255 + return [
239 256 'templates' => $this->get_templates( $filter_sources, $force_update ),
240 257 'config' => $library_data['types_data'],
241 258 ];
242 -
243 - /**
244 - * Filter the full library data.
245 - *
246 - * @since 3.32.2
247 - * @param-out $full_library_data - 'templates' and 'config' data ('config' holds the list of categories).
248 - */
249 - return apply_filters( 'elementor/library/full-data', $full_library_data );
250 259 }
251 260
252 261 /**
253 262 * Save template.
@@ -283,9 +292,9 @@
283 292 private function save_template_item( array $args ) {
284 293 $source = $this->get_source( $args['source'] );
285 294
286 295 if ( ! $source ) {
287 - return new \WP_Error( 'template_error', self::ERROR_TEMPLATE_SOURCE_NOT_FOUND );
296 + return new \WP_Error( 'template_error', 'Template source not found.' );
288 297 }
289 298
290 299 $args['content'] = json_decode( $args['content'], true );
291 300
@@ -332,9 +341,9 @@
332 341
333 342 $source = $this->get_source( $args['source'] );
334 343
335 344 if ( ! $source ) {
336 - return new \WP_Error( 'template_error', self::ERROR_TEMPLATE_SOURCE_NOT_FOUND );
345 + return new \WP_Error( 'template_error', 'Template source not found.' );
337 346 }
338 347
339 348 if ( $this->is_action_to_same_source( $args ) ) {
340 349 return $source->move_template_to_folder( $args );
@@ -339,16 +348,16 @@
339 348 if ( $this->is_action_to_same_source( $args ) ) {
340 349 return $source->move_template_to_folder( $args );
341 350 }
342 351
343 - $from_source = $this->get_source( $args['from_source'] );
352 + if ( 'local' === $args['from_source'] ) {
353 + $args = $this->format_args_for_single_action_from_local_to_cloud( $args );
354 + }
344 355
345 - if ( ! $from_source ) {
346 - return new \WP_Error( 'template_error', self::ERROR_TEMPLATE_SOURCE_NOT_FOUND );
356 + if ( 'cloud' === $args['from_source'] ) {
357 + $args = $this->format_args_for_single_action_from_cloud_to_local( $args );
347 358 }
348 359
349 - $args = $from_source->format_args_for_single_action( $args );
350 -
351 360 $template_id = $source->save_item( $args );
352 361
353 362 if ( is_wp_error( $template_id ) ) {
354 363 return $template_id;
@@ -366,19 +375,19 @@
366 375
367 376 $source = $this->get_source( $args['source'][0] );
368 377
369 378 if ( ! $source ) {
370 - return new \WP_Error( 'template_error', self::ERROR_TEMPLATE_SOURCE_NOT_FOUND );
379 + return new \WP_Error( 'template_error', 'Template source not found.' );
371 380 }
372 381
373 - $from_source = $this->get_source( $args['from_source'] );
382 + if ( 'local' === $args['from_source'] ) {
383 + $args = $this->format_args_for_single_action_from_local_to_cloud( $args );
384 + }
374 385
375 - if ( ! $from_source ) {
376 - return new \WP_Error( 'template_error', self::ERROR_TEMPLATE_SOURCE_NOT_FOUND );
386 + if ( 'cloud' === $args['from_source'] ) {
387 + $args = $this->format_args_for_single_action_from_cloud_to_local( $args );
377 388 }
378 389
379 - $args = $from_source->format_args_for_single_action( $args );
380 -
381 390 $template_id = $source->save_item( $args );
382 391
383 392 if ( is_wp_error( $template_id ) ) {
384 393 return $template_id;
@@ -390,8 +399,53 @@
390 399 private function is_action_to_same_source( $args ) {
391 400 return $args['source'] === $args['from_source'];
392 401 }
393 402
403 + private function format_args_for_single_action_from_local_to_cloud( $args ) {
404 + if ( ! $this->is_allowed_to_read_template( [
405 + 'source' => $args['from_source'],
406 + 'template_id' => $args['from_template_id'],
407 + ] ) ) {
408 + return new \WP_Error(
409 + 'template_error',
410 + esc_html__( 'You do not have permission to access this template.', 'elementor' )
411 + );
412 + }
413 +
414 + $document = Plugin::$instance->documents->get( $args['from_template_id'] );
415 +
416 + if ( ! $document ) {
417 + return new \WP_Error( 'template_error', 'Document not found.' );
418 + }
419 +
420 + $args['content'] = $document->get_elements_data();
421 +
422 + $page = SettingsManager::get_settings_managers( 'page' )->get_model( $args['from_template_id'] );
423 + $args['page_settings'] = $page->get_data( 'settings' );
424 +
425 + return $args;
426 + }
427 +
428 + private function format_args_for_single_action_from_cloud_to_local( $args ) {
429 + $from_source = $this->get_source( $args['from_source'] );
430 +
431 + if ( ! $from_source ) {
432 + return new \WP_Error( 'template_error', 'Template source not found.' );
433 + }
434 +
435 + $data = $from_source->get_item( $args['from_template_id'] );
436 +
437 + if ( is_wp_error( $data ) || empty( $data['content'] ) ) {
438 + return new \WP_Error( 'template_error', 'Unable to format template args.' );
439 + }
440 +
441 + $decoded_data = json_decode( $data['content'], true );
442 + $args['content'] = $decoded_data['content'];
443 + $args['page_settings'] = $decoded_data['page_settings'];
444 +
445 + return $args;
446 + }
447 +
394 448 /**
395 449 * Update template.
396 450 *
397 451 * Update template on the database.
@@ -413,9 +467,9 @@
413 467
414 468 $source = $this->get_source( $template_data['source'] );
415 469
416 470 if ( ! $source ) {
417 - return new \WP_Error( 'template_error', self::ERROR_TEMPLATE_SOURCE_NOT_FOUND );
471 + return new \WP_Error( 'template_error', 'Template source not found.' );
418 472 }
419 473
420 474 $template_data['content'] = json_decode( $template_data['content'], true );
421 475
@@ -437,9 +491,9 @@
437 491
438 492 $source = $this->get_source( $template_data['source'] );
439 493
440 494 if ( ! $source ) {
441 - return new \WP_Error( 'template_error', self::ERROR_TEMPLATE_SOURCE_NOT_FOUND );
495 + return new \WP_Error( 'template_error', 'Template source not found.' );
442 496 }
443 497
444 498 $update = $source->update_item( $template_data );
445 499
@@ -492,15 +546,9 @@
492 546 if ( is_wp_error( $validate_args ) ) {
493 547 return $validate_args;
494 548 }
495 549
496 - $source = $this->get_source( $args['source'] );
497 -
498 - if ( ! $source ) {
499 - return new \WP_Error( 'template_error', self::ERROR_TEMPLATE_SOURCE_NOT_FOUND );
500 - }
501 -
502 - if ( method_exists( $source, 'is_allowed_to_read_template' ) && ! $source->is_allowed_to_read_template( $args ) ) {
550 + if ( ! $this->is_allowed_to_read_template( $args ) ) {
503 551 return new \WP_Error(
504 552 'template_error',
505 553 esc_html__( 'You do not have permission to access this template.', 'elementor' )
506 554 );
@@ -509,8 +557,14 @@
509 557 if ( isset( $args['edit_mode'] ) ) {
510 558 Plugin::$instance->editor->set_edit_mode( $args['edit_mode'] );
511 559 }
512 560
561 + $source = $this->get_source( $args['source'] );
562 +
563 + if ( ! $source ) {
564 + return new \WP_Error( 'template_error', 'Template source not found.' );
565 + }
566 +
513 567 do_action( 'elementor/template-library/before_get_source_data', $args, $source );
514 568
515 569 $data = $source->get_data( $args );
516 570
@@ -541,9 +595,9 @@
541 595
542 596 $source = $this->get_source( $args['source'] );
543 597
544 598 if ( ! $source ) {
545 - return new \WP_Error( 'template_error', self::ERROR_TEMPLATE_SOURCE_NOT_FOUND );
599 + return new \WP_Error( 'template_error', 'Template source not found.' );
546 600 }
547 601
548 602 return $source->delete_template( $args['template_id'] );
549 603 }
@@ -570,9 +624,9 @@
570 624
571 625 $source = $this->get_source( $args['source'] );
572 626
573 627 if ( ! $source ) {
574 - return new \WP_Error( 'template_error', self::ERROR_TEMPLATE_SOURCE_NOT_FOUND );
628 + return new \WP_Error( 'template_error', 'Template source not found' );
575 629 }
576 630
577 631 return $source->export_template( $args['template_id'] );
578 632 }
@@ -600,12 +654,8 @@
600 654 *
601 655 * @return mixed Whether the export succeeded or failed.
602 656 */
603 657 public function import_template( array $data ) {
604 - if ( ! User::is_current_user_can_upload_json() ) {
605 - return new \WP_Error( 'template_error', self::ERROR_JSON_UPLOAD_NOT_ALLOWED );
606 - }
607 -
608 658 // If the template is a JSON file, allow uploading it.
609 659 add_filter( 'elementor/files/allow-file-type/json', [ $this, 'enable_json_template_upload' ] );
610 660 add_filter( 'elementor/files/allow_unfiltered_upload', [ $this, 'enable_json_template_upload' ] );
611 661
@@ -615,15 +665,16 @@
615 665 remove_filter( 'elementor/files/allow-file-type/json', [ $this, 'enable_json_template_upload' ] );
616 666 remove_filter( 'elementor/files/allow_unfiltered_upload', [ $this, 'enable_json_template_upload' ] );
617 667
618 668 if ( is_wp_error( $upload_result ) ) {
669 + Plugin::$instance->uploads_manager->remove_file_or_dir( dirname( $upload_result['tmp_name'] ) );
670 +
619 671 return $upload_result;
620 672 }
621 673
622 674 $source = $this->get_source( $data['source'] ?? 'local' );
623 675
624 - $import_mode = $data['import_mode'] ?? 'match_site';
625 - $import_result = $source->import_template( $upload_result['name'], $upload_result['tmp_name'], $import_mode );
676 + $import_result = $source->import_template( $upload_result['name'], $upload_result['tmp_name'] );
626 677
627 678 // Remove the temporary directory generated for the stream-uploaded file.
628 679 Plugin::$instance->uploads_manager->remove_file_or_dir( dirname( $upload_result['tmp_name'] ) );
629 680
@@ -683,103 +734,11 @@
683 734 }
684 735
685 736 $import_data = $document->get_import_data( [ 'content' => $elements ] );
686 737
687 - $content = $document::on_import_update_dynamic_content(
688 - $import_data['content'],
689 - [ 'post_ids' => [] ]
690 - );
691 -
692 - return Plugin::$instance->db->iterate_data( $content, function( $element_data ) {
693 - unset( $element_data['htmlCache'] );
694 - return $element_data;
695 - } );
738 + return $import_data['content'];
696 739 }
697 740
698 - public function process_global_styles( array $args ) {
699 - $validate_args = $this->ensure_args( [ 'content', 'import_mode' ], $args );
700 -
701 - if ( is_wp_error( $validate_args ) ) {
702 - return $validate_args;
703 - }
704 -
705 - $import_mode = Template_Library_Import_Export_Utils::sanitize_import_mode( $args['import_mode'] );
706 -
707 - $content = $this->get_validated_json_arg( $args, 'content' );
708 - if ( is_wp_error( $content ) ) {
709 - return $content;
710 - }
711 -
712 - $global_classes = $this->get_validated_json_arg( $args, 'global_classes', true );
713 - if ( is_wp_error( $global_classes ) ) {
714 - return $global_classes;
715 - }
716 -
717 - $global_variables = $this->get_validated_json_arg( $args, 'global_variables', true );
718 - if ( is_wp_error( $global_variables ) ) {
719 - return $global_variables;
720 - }
721 -
722 - $data = [
723 - 'global_classes' => $global_classes,
724 - 'global_variables' => $global_variables,
725 - ];
726 -
727 - $result = apply_filters(
728 - 'elementor/template_library/import/process_content',
729 - [ 'content' => $content ],
730 - $import_mode,
731 - $data,
732 - null
733 - );
734 -
735 - $response = [
736 - 'content' => $result['content'],
737 - ];
738 -
739 - if ( ! empty( $result['updated_global_classes'] ) ) {
740 - $response['updated_global_classes'] = $result['updated_global_classes'];
741 - }
742 -
743 - if ( ! empty( $result['updated_global_variables'] ) ) {
744 - $response['updated_global_variables'] = $result['updated_global_variables'];
745 - }
746 -
747 - $classes_to_flatten = $result['classes_to_flatten'] ?? [];
748 - $variables_to_flatten = $result['variables_to_flatten'] ?? [];
749 -
750 - if ( ! empty( $classes_to_flatten ) ) {
751 - $response['flattened_classes_count'] = count( $classes_to_flatten );
752 - }
753 -
754 - if ( ! empty( $variables_to_flatten ) ) {
755 - $response['flattened_variables_count'] = count( $variables_to_flatten );
756 - }
757 -
758 - return $response;
759 - }
760 -
761 - private function get_validated_json_arg( array $args, string $key, bool $is_optional = false ) {
762 - if ( ! array_key_exists( $key, $args ) || null === $args[ $key ] || '' === $args[ $key ] ) {
763 - return $is_optional ? null : new \WP_Error( "invalid_$key", "Invalid $key." );
764 - }
765 -
766 - $value = $args[ $key ];
767 - if ( is_string( $value ) ) {
768 - $decoded = json_decode( $value, true );
769 - if ( JSON_ERROR_NONE !== json_last_error() ) {
770 - return new \WP_Error( "invalid_$key", "Invalid JSON $key." );
771 - }
772 - return $decoded;
773 - }
774 -
775 - if ( ! is_array( $value ) ) {
776 - return new \WP_Error( "invalid_$key", "Invalid $key format." );
777 - }
778 -
779 - return $value;
780 - }
781 -
782 741 public function get_item_children( array $args ) {
783 742 $validate_args = $this->ensure_args( [ 'source', 'template_id' ], $args );
784 743
785 744 if ( is_wp_error( $validate_args ) ) {
@@ -788,9 +747,9 @@
788 747
789 748 $source = $this->get_source( $args['source'] );
790 749
791 750 if ( ! $source ) {
792 - return new \WP_Error( 'template_error', self::ERROR_TEMPLATE_SOURCE_NOT_FOUND );
751 + return new \WP_Error( 'template_error', 'Template source not found.' );
793 752 }
794 753
795 754 return $source->get_item_children( $args );
796 755 }
@@ -804,9 +763,9 @@
804 763
805 764 $source = $this->get_source( $args['source'] );
806 765
807 766 if ( ! $source ) {
808 - return new \WP_Error( 'template_error', self::ERROR_TEMPLATE_SOURCE_NOT_FOUND );
767 + return new \WP_Error( 'template_error', 'Template source not found.' );
809 768 }
810 769
811 770 return $source->search_templates( $args );
812 771 }
@@ -820,9 +779,9 @@
820 779
821 780 $source = $this->get_source( $args['source'] );
822 781
823 782 if ( ! $source ) {
824 - return new \WP_Error( 'template_error', self::ERROR_TEMPLATE_SOURCE_NOT_FOUND );
783 + return new \WP_Error( 'template_error', 'Template source not found.' );
825 784 }
826 785
827 786 return $source->get_items( $args );
828 787 }
@@ -836,9 +795,9 @@
836 795
837 796 $source = $this->get_source( $args['source'] );
838 797
839 798 if ( ! $source ) {
840 - return new \WP_Error( 'template_error', self::ERROR_TEMPLATE_SOURCE_NOT_FOUND );
799 + return new \WP_Error( 'template_error', 'Template source not found.' );
841 800 }
842 801
843 802 return $source->save_folder( $args );
844 803 }
@@ -897,9 +856,9 @@
897 856 *
898 857 * @param array $data
899 858 *
900 859 * @return mixed
901 - * @throws \Exception If current user has no permission or the post is not found.
860 + * @throws \Exception If the user has no permission or the post is not found.
902 861 */
903 862 private function handle_ajax_request( $ajax_request, array $data ) {
904 863 if ( ! User::is_current_user_can_edit_post_type( Source_Local::CPT ) ) {
905 864 throw new \Exception( 'Access denied.' );
@@ -904,12 +863,8 @@
904 863 if ( ! User::is_current_user_can_edit_post_type( Source_Local::CPT ) ) {
905 864 throw new \Exception( 'Access denied.' );
906 865 }
907 866
908 - if ( 'import_template' === $ajax_request && ! User::is_current_user_can_upload_json() ) {
909 - throw new \Exception( 'Access denied.' );
910 - }
911 -
912 867 if ( ! empty( $data['editor_post_id'] ) ) {
913 868 $editor_post_id = absint( $data['editor_post_id'] );
914 869
915 870 if ( ! get_post( $editor_post_id ) ) {
@@ -924,13 +879,13 @@
924 879 if ( is_wp_error( $result ) ) {
925 880 throw new \Exception( esc_html( $result->get_error_message() ) );
926 881 }
927 882
928 - return $result;
883 + return $result; // phpcs:ignore WordPress.Security.EscapeOutput.ExceptionNotEscaped
929 884 }
930 885
931 886 /**
932 - * @throws \Exception If template import fails, file validation errors occur, or processing encounters issues.
887 + * @throws \Exception
933 888 */
934 889 public function save_template_screenshot( $data ): string {
935 890 $validate_args = $this->ensure_args( [ 'template_id', 'screenshot' ], $data );
936 891
@@ -943,9 +898,9 @@
943 898 return $this->get_source( 'cloud' )->save_item_preview( $data['template_id'], $raw_binary );
944 899 }
945 900
946 901 /**
947 - * @throws \Exception If template processing fails or data validation errors occur.
902 + * @throws \Exception
948 903 */
949 904 public function template_screenshot_failed( $data ): string {
950 905 $validate_args = $this->ensure_args( [ 'template_id' ], $data );
951 906
@@ -965,13 +920,13 @@
965 920
966 921 $source = $this->get_source( $data['source'] );
967 922
968 923 if ( ! $source ) {
969 - return new \WP_Error( 'template_error', self::ERROR_TEMPLATE_SOURCE_NOT_FOUND );
924 + return new \WP_Error( 'template_error', 'Template source not found.' );
970 925 }
971 926
972 927 if ( empty( $data['template_ids'] ) || ! is_array( $data['template_ids'] ) ) {
973 - return new \WP_Error( 'template_error', self::ERROR_TEMPLATE_IDS_MISSING );
928 + return new \WP_Error( 'template_error', 'Template IDs are missing.' );
974 929 }
975 930
976 931 return $source->bulk_delete_items( $data['template_ids'] );
977 932 }
@@ -985,13 +940,13 @@
985 940
986 941 $source = $this->get_source( $data['source'] );
987 942
988 943 if ( ! $source ) {
989 - return new \WP_Error( 'template_error', self::ERROR_TEMPLATE_SOURCE_NOT_FOUND );
944 + return new \WP_Error( 'template_error', 'Template source not found.' );
990 945 }
991 946
992 947 if ( empty( $data['template_ids'] ) || ! is_array( $data['template_ids'] ) ) {
993 - return new \WP_Error( 'template_error', self::ERROR_TEMPLATE_IDS_MISSING );
948 + return new \WP_Error( 'template_error', 'Template IDs are missing.' );
994 949 }
995 950
996 951 return $source->bulk_undo_delete_items( $data['template_ids'] );
997 952 }
@@ -1030,9 +985,8 @@
1030 985 'bulk_copy_templates',
1031 986 'bulk_undo_delete_items',
1032 987 'get_templates_quota',
1033 988 'template_screenshot_failed',
1034 - 'process_global_styles',
1035 989 ];
1036 990
1037 991 foreach ( $library_ajax_requests as $ajax_request ) {
1038 992 $ajax->register_ajax_action( $ajax_request, function( $data ) use ( $ajax_request ) {
@@ -1133,8 +1087,46 @@
1133 1087
1134 1088 return true;
1135 1089 }
1136 1090
1091 + private function is_allowed_to_read_template( array $args ): bool {
1092 + if ( 'remote' === $args['source'] || 'cloud' === $args['source'] ) {
1093 + return true;
1094 + }
1095 +
1096 + if ( null === $this->wordpress_adapter ) {
1097 + $this->set_wordpress_adapter( new WordPress_Adapter() );
1098 + }
1099 +
1100 + if ( ! $this->should_check_permissions( $args ) ) {
1101 + return true;
1102 + }
1103 +
1104 + $post_id = intval( $args['template_id'] );
1105 + $post_status = $this->wordpress_adapter->get_post_status( $post_id );
1106 + $is_private_or_non_published = ( 'private' === $post_status && ! $this->wordpress_adapter->current_user_can( 'read_private_posts', $post_id ) ) || ( 'publish' !== $post_status );
1107 +
1108 + $can_read_template = $is_private_or_non_published || $this->wordpress_adapter->current_user_can( 'edit_post', $post_id );
1109 +
1110 + return apply_filters( 'elementor/template-library/is_allowed_to_read_template', $can_read_template, $args );
1111 + }
1112 +
1113 + private function should_check_permissions( array $args ): bool {
1114 + if ( null === $this->elementor_adapter ) {
1115 + $this->set_elementor_adapter( new Elementor_Adapter() );
1116 + }
1117 +
1118 + // TODO: Remove $isWidgetTemplate in 3.28.0 as there is a Pro dependency
1119 + $check_permissions = isset( $args['check_permissions'] ) && false === $args['check_permissions'];
1120 + $is_widget_template = 'widget' === $this->elementor_adapter->get_template_type( $args['template_id'] );
1121 +
1122 + if ( $check_permissions || $is_widget_template ) {
1123 + return false;
1124 + }
1125 +
1126 + return true;
1127 + }
1128 +
1137 1129 public function bulk_move_templates( array $args ) {
1138 1130 $validate_args = $this->ensure_args( [ 'source', 'from_source', 'from_template_id' ], $args );
1139 1131
1140 1132 if ( is_wp_error( $validate_args ) ) {
@@ -1149,9 +1141,9 @@
1149 1141 private function bulk_move_template_items( array $args ) {
1150 1142 $source = $this->get_source( $args['source'] );
1151 1143
1152 1144 if ( ! $source ) {
1153 - return new \WP_Error( 'template_error', self::ERROR_TEMPLATE_SOURCE_NOT_FOUND );
1145 + return new \WP_Error( 'template_error', 'Template source not found.' );
1154 1146 }
1155 1147
1156 1148 if ( $this->is_action_to_same_source( $args ) ) {
1157 1149 return $source->move_bulk_templates_to_folder( $args );
@@ -1156,24 +1148,20 @@
1156 1148 if ( $this->is_action_to_same_source( $args ) ) {
1157 1149 return $source->move_bulk_templates_to_folder( $args );
1158 1150 }
1159 1151
1160 - $from_source = $this->get_source( $args['from_source'] );
1152 + $bulk_args = 'local' === $args['from_source']
1153 + ? $this->format_args_for_bulk_action_from_local( $args )
1154 + : $this->format_args_for_bulk_action_from_cloud( $args );
1161 1155
1162 - if ( ! $from_source ) {
1163 - return new \WP_Error( 'template_error', self::ERROR_TEMPLATE_SOURCE_NOT_FOUND );
1164 - }
1165 -
1166 - $bulk_args = $from_source->format_args_for_bulk_action( $args );
1167 -
1168 1156 if ( $source->supports_quota() && ! $this->is_action_to_same_source( $args ) ) {
1169 - $quota_validation = $source->validate_quota( $bulk_args );
1157 + $is_quota_valid = $source->validate_quota( $bulk_args );
1170 1158
1171 - if ( is_wp_error( $quota_validation ) ) {
1172 - return $quota_validation;
1159 + if ( is_wp_error( $is_quota_valid ) ) {
1160 + return $is_quota_valid;
1173 1161 }
1174 1162
1175 - if ( false === $quota_validation ) {
1163 + if ( ! $is_quota_valid ) {
1176 1164 return new \WP_Error( 'quota_error', 'The moving failed because it will pass the maximum templates you can save.' );
1177 1165 }
1178 1166 }
1179 1167
@@ -1188,8 +1176,68 @@
1188 1176
1189 1177 return $bulk_save;
1190 1178 }
1191 1179
1180 + private function format_args_for_bulk_action_from_local( $args ) {
1181 + $bulk_args = [];
1182 +
1183 + foreach ( $args['from_template_id'] as $from_template_id ) {
1184 + if ( ! $this->is_allowed_to_read_template( [
1185 + 'source' => $args['from_source'],
1186 + 'template_id' => $from_template_id,
1187 + ] ) ) {
1188 + continue;
1189 + }
1190 +
1191 + $document = Plugin::$instance->documents->get( $from_template_id );
1192 +
1193 + if ( ! $document ) {
1194 + continue;
1195 + }
1196 +
1197 + $page = SettingsManager::get_settings_managers( 'page' )->get_model( $from_template_id );
1198 +
1199 + $bulk_args[] = array_merge(
1200 + $args,
1201 + [
1202 + 'title' => $document->get_post()->post_title,
1203 + 'type' => $document::get_type(),
1204 + 'content' => $document->get_elements_data(),
1205 + 'page_settings' => $page->get_data( 'settings' ),
1206 + ]
1207 + );
1208 + }
1209 +
1210 + return $bulk_args;
1211 + }
1212 +
1213 + private function format_args_for_bulk_action_from_cloud( $args ) {
1214 + $from_source = $this->get_source( $args['from_source'] );
1215 +
1216 + if ( ! $from_source ) {
1217 + return new \WP_Error( 'template_error', 'Template source not found.' );
1218 + }
1219 +
1220 + $templates = $from_source->get_bulk_items( $args );
1221 + $bulk_args = [];
1222 +
1223 + foreach ( $templates as $template ) {
1224 + $content = json_decode( $template['content'], true );
1225 +
1226 + $bulk_args[] = array_merge(
1227 + $args,
1228 + [
1229 + 'title' => $template['title'],
1230 + 'type' => $template['type'],
1231 + 'content' => $content['content'],
1232 + 'page_settings' => $content['page_settings'],
1233 + ]
1234 + );
1235 + }
1236 +
1237 + return $bulk_args;
1238 + }
1239 +
1192 1240 public function bulk_copy_templates( array $args ) {
1193 1241 $validate_args = $this->ensure_args( [ 'source', 'from_source', 'from_template_id' ], $args );
1194 1242
1195 1243 if ( is_wp_error( $validate_args ) ) {
@@ -1204,27 +1252,23 @@
1204 1252 private function bulk_copy_template_items( array $args ) {
1205 1253 $source = $this->get_source( $args['source'] );
1206 1254
1207 1255 if ( ! $source ) {
1208 - return new \WP_Error( 'template_error', self::ERROR_TEMPLATE_SOURCE_NOT_FOUND );
1256 + return new \WP_Error( 'template_error', 'Template source not found.' );
1209 1257 }
1210 1258
1211 - $from_source = $this->get_source( $args['from_source'] );
1259 + $bulk_args = 'local' === $args['from_source']
1260 + ? $this->format_args_for_bulk_action_from_local( $args )
1261 + : $this->format_args_for_bulk_action_from_cloud( $args );
1212 1262
1213 - if ( ! $from_source ) {
1214 - return new \WP_Error( 'template_error', self::ERROR_TEMPLATE_SOURCE_NOT_FOUND );
1215 - }
1216 -
1217 - $bulk_args = $from_source->format_args_for_bulk_action( $args );
1218 -
1219 1263 if ( $source->supports_quota() && ! $this->is_action_to_same_source( $args ) ) {
1220 - $quota_validation = $source->validate_quota( $bulk_args );
1264 + $is_quota_valid = $source->validate_quota( $bulk_args );
1221 1265
1222 - if ( is_wp_error( $quota_validation ) ) {
1223 - return $quota_validation;
1266 + if ( is_wp_error( $is_quota_valid ) ) {
1267 + return $is_quota_valid;
1224 1268 }
1225 1269
1226 - if ( false === $quota_validation ) {
1270 + if ( ! $is_quota_valid ) {
1227 1271 return new \WP_Error( 'quota_error', 'The copying failed because it will pass the maximum templates you can save.' );
1228 1272 }
1229 1273 }
1230 1274