PluginProbe
Elementor Website Builder – more than just a page builder / 3.6.4
Elementor Website Builder – more than just a page builder v3.6.4
4.3.0-beta2 4.3.0-beta1 4.2.4 4.2.3 4.2.2 4.2.1 4.2.0 4.1.5 4.2.0-beta2 4.2.0-dev2 4.2.0-beta1 4.1.4 4.1.3 4.1.2 4.1.1 4.1.0 4.1.0-beta3 4.1.0-dev3 4.0.9 4.1.0-beta2 4.1.0-dev2 4.0.8 4.1.0-beta1 4.1.0-dev1 4.0.7 All 451 releases
elementor / includes / template-library / manager.php

manager.php in Elementor Website Builder – more than just a page builder 3.6.4, at includes/template-library/manager.php

688 lines 16.3 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 namespace Elementor\TemplateLibrary;
3
4 use Elementor\Api;
5 use Elementor\Core\Common\Modules\Ajax\Module as Ajax;
6 use Elementor\Core\Settings\Manager as SettingsManager;
7 use Elementor\Includes\TemplateLibrary\Data\Controller;
8 use Elementor\TemplateLibrary\Classes\Import_Images;
9 use Elementor\Plugin;
10 use Elementor\User;
11
12 if ( ! defined( 'ABSPATH' ) ) {
13 exit; // Exit if accessed directly.
14 }
15
16 /**
17 * Elementor template library manager.
18 *
19 * Elementor template library manager handler class is responsible for
20 * initializing the template library.
21 *
22 * @since 1.0.0
23 */
24 class Manager {
25
26 /**
27 * Registered template sources.
28 *
29 * Holds a list of all the supported sources with their instances.
30 *
31 * @access protected
32 *
33 * @var Source_Base[]
34 */
35 protected $_registered_sources = [];
36
37 /**
38 * Imported template images.
39 *
40 * Holds an instance of `Import_Images` class.
41 *
42 * @access private
43 *
44 * @var Import_Images
45 */
46 private $_import_images = null;
47
48 /**
49 * Template library manager constructor.
50 *
51 * Initializing the template library manager by registering default template
52 * sources and initializing ajax calls.
53 *
54 * @since 1.0.0
55 * @access public
56 */
57 public function __construct() {
58 Plugin::$instance->data_manager_v2->register_controller( new Controller() );
59
60 $this->register_default_sources();
61
62 $this->add_actions();
63 }
64
65 /**
66 * @since 2.3.0
67 * @access public
68 */
69 public function add_actions() {
70 add_action( 'elementor/ajax/register_actions', [ $this, 'register_ajax_actions' ] );
71 add_action( 'wp_ajax_elementor_library_direct_actions', [ $this, 'handle_direct_actions' ] );
72 }
73
74 /**
75 * Get `Import_Images` instance.
76 *
77 * Retrieve the instance of the `Import_Images` class.
78 *
79 * @since 1.0.0
80 * @access public
81 *
82 * @return Import_Images Imported images instance.
83 */
84 public function get_import_images_instance() {
85 if ( null === $this->_import_images ) {
86 $this->_import_images = new Import_Images();
87 }
88
89 return $this->_import_images;
90 }
91
92 /**
93 * Register template source.
94 *
95 * Used to register new template sources displayed in the template library.
96 *
97 * @since 1.0.0
98 * @access public
99 *
100 * @param string $source_class The name of source class.
101 * @param array $args Optional. Class arguments. Default is an
102 * empty array.
103 *
104 * @return \WP_Error|true True if the source was registered, `WP_Error`
105 * otherwise.
106 */
107 public function register_source( $source_class, $args = [] ) {
108 if ( ! class_exists( $source_class ) ) {
109 return new \WP_Error( 'source_class_name_not_exists' );
110 }
111
112 $source_instance = new $source_class( $args );
113
114 if ( ! $source_instance instanceof Source_Base ) {
115 return new \WP_Error( 'wrong_instance_source' );
116 }
117
118 $source_id = $source_instance->get_id();
119
120 if ( isset( $this->_registered_sources[ $source_id ] ) ) {
121 return new \WP_Error( 'source_exists' );
122 }
123
124 $this->_registered_sources[ $source_id ] = $source_instance;
125
126 return true;
127 }
128
129 /**
130 * Unregister template source.
131 *
132 * Remove an existing template sources from the list of registered template
133 * sources.
134 *
135 * @deprecated 2.7.0
136 *
137 * @since 1.0.0
138 * @access public
139 *
140 * @param string $id The source ID.
141 *
142 * @return bool Whether the source was unregistered.
143 */
144 public function unregister_source( $id ) {
145 return true;
146 }
147
148 /**
149 * Get registered template sources.
150 *
151 * Retrieve registered template sources.
152 *
153 * @since 1.0.0
154 * @access public
155 *
156 * @return Source_Base[] Registered template sources.
157 */
158 public function get_registered_sources() {
159 return $this->_registered_sources;
160 }
161
162 /**
163 * Get template source.
164 *
165 * Retrieve single template sources for a given template ID.
166 *
167 * @since 1.0.0
168 * @access public
169 *
170 * @param string $id The source ID.
171 *
172 * @return false|Source_Base Template sources if one exist, False otherwise.
173 */
174 public function get_source( $id ) {
175 $sources = $this->get_registered_sources();
176
177 if ( ! isset( $sources[ $id ] ) ) {
178 return false;
179 }
180
181 return $sources[ $id ];
182 }
183
184 /**
185 * Get templates.
186 *
187 * Retrieve all the templates from all the registered sources.
188 *
189 * @param array $filter_sources
190 *
191 * @return array
192 */
193 public function get_templates( $filter_sources = [] ) {
194 $templates = [];
195
196 foreach ( $this->get_registered_sources() as $source ) {
197 if ( ! empty( $filter_sources ) && ! in_array( $source->get_id(), $filter_sources, true ) ) {
198 continue;
199 }
200
201 $templates = array_merge( $templates, $source->get_items() );
202 }
203
204 return $templates;
205 }
206
207 /**
208 * Get library data.
209 *
210 * Retrieve the library data.
211 *
212 * @since 1.9.0
213 * @access public
214 *
215 * @param array $args Library arguments.
216 *
217 * @return array Library data.
218 */
219 public function get_library_data( array $args ) {
220 $library_data = Api::get_library_data( ! empty( $args['sync'] ) );
221
222 // Ensure all document are registered.
223 Plugin::$instance->documents->get_document_types();
224
225 $filter_sources = ! empty( $args['filter_sources'] ) ? $args['filter_sources'] : [];
226
227 return [
228 'templates' => $this->get_templates( $filter_sources ),
229 'config' => $library_data['types_data'],
230 ];
231 }
232
233 /**
234 * Save template.
235 *
236 * Save new or update existing template on the database.
237 *
238 * @since 1.0.0
239 * @access public
240 *
241 * @param array $args Template arguments.
242 *
243 * @return \WP_Error|int The ID of the saved/updated template.
244 */
245 public function save_template( array $args ) {
246 $validate_args = $this->ensure_args( [ 'post_id', 'source', 'content', 'type' ], $args );
247
248 if ( is_wp_error( $validate_args ) ) {
249 return $validate_args;
250 }
251
252 $source = $this->get_source( $args['source'] );
253
254 if ( ! $source ) {
255 return new \WP_Error( 'template_error', 'Template source not found.' );
256 }
257
258 $args['content'] = json_decode( $args['content'], true );
259
260 $page = SettingsManager::get_settings_managers( 'page' )->get_model( $args['post_id'] );
261
262 $args['page_settings'] = $page->get_data( 'settings' );
263
264 $template_id = $source->save_item( $args );
265
266 if ( is_wp_error( $template_id ) ) {
267 return $template_id;
268 }
269
270 return $source->get_item( $template_id );
271 }
272
273 /**
274 * Update template.
275 *
276 * Update template on the database.
277 *
278 * @since 1.0.0
279 * @access public
280 *
281 * @param array $template_data New template data.
282 *
283 * @return \WP_Error|Source_Base Template sources instance if the templates
284 * was updated, `WP_Error` otherwise.
285 */
286 public function update_template( array $template_data ) {
287 $validate_args = $this->ensure_args( [ 'source', 'content', 'type' ], $template_data );
288
289 if ( is_wp_error( $validate_args ) ) {
290 return $validate_args;
291 }
292
293 $source = $this->get_source( $template_data['source'] );
294
295 if ( ! $source ) {
296 return new \WP_Error( 'template_error', 'Template source not found.' );
297 }
298
299 $template_data['content'] = json_decode( $template_data['content'], true );
300
301 $update = $source->update_item( $template_data );
302
303 if ( is_wp_error( $update ) ) {
304 return $update;
305 }
306
307 return $source->get_item( $template_data['id'] );
308 }
309
310 /**
311 * Update templates.
312 *
313 * Update template on the database.
314 *
315 * @since 1.0.0
316 * @access public
317 *
318 * @param array $args Template arguments.
319 *
320 * @return \WP_Error|true True if templates updated, `WP_Error` otherwise.
321 */
322 public function update_templates( array $args ) {
323 foreach ( $args['templates'] as $template_data ) {
324 $result = $this->update_template( $template_data );
325
326 if ( is_wp_error( $result ) ) {
327 return $result;
328 }
329 }
330
331 return true;
332 }
333
334 /**
335 * Get template data.
336 *
337 * Retrieve the template data.
338 *
339 * @since 1.5.0
340 * @access public
341 *
342 * @param array $args Template arguments.
343 *
344 * @return \WP_Error|bool|array ??
345 */
346 public function get_template_data( array $args ) {
347 $validate_args = $this->ensure_args( [ 'source', 'template_id' ], $args );
348
349 if ( is_wp_error( $validate_args ) ) {
350 return $validate_args;
351 }
352
353 if ( isset( $args['edit_mode'] ) ) {
354 Plugin::$instance->editor->set_edit_mode( $args['edit_mode'] );
355 }
356
357 $source = $this->get_source( $args['source'] );
358
359 if ( ! $source ) {
360 return new \WP_Error( 'template_error', 'Template source not found.' );
361 }
362
363 do_action( 'elementor/template-library/before_get_source_data', $args, $source );
364
365 $data = $source->get_data( $args );
366
367 do_action( 'elementor/template-library/after_get_source_data', $args, $source );
368
369 return $data;
370 }
371
372 /**
373 * Delete template.
374 *
375 * Delete template from the database.
376 *
377 * @since 1.0.0
378 * @access public
379 *
380 * @param array $args Template arguments.
381 *
382 * @return \WP_Post|\WP_Error|false|null Post data on success, false or null
383 * or 'WP_Error' on failure.
384 */
385 public function delete_template( array $args ) {
386 $validate_args = $this->ensure_args( [ 'source', 'template_id' ], $args );
387
388 if ( is_wp_error( $validate_args ) ) {
389 return $validate_args;
390 }
391
392 $source = $this->get_source( $args['source'] );
393
394 if ( ! $source ) {
395 return new \WP_Error( 'template_error', 'Template source not found.' );
396 }
397
398 return $source->delete_template( $args['template_id'] );
399 }
400
401 /**
402 * Export template.
403 *
404 * Export template to a file.
405 *
406 * @since 1.0.0
407 * @access public
408 *
409 * @param array $args Template arguments.
410 *
411 * @return mixed Whether the export succeeded or failed.
412 */
413 public function export_template( array $args ) {
414 $validate_args = $this->ensure_args( [ 'source', 'template_id' ], $args );
415
416 if ( is_wp_error( $validate_args ) ) {
417 return $validate_args;
418 }
419
420 $source = $this->get_source( $args['source'] );
421
422 if ( ! $source ) {
423 return new \WP_Error( 'template_error', 'Template source not found' );
424 }
425
426 return $source->export_template( $args['template_id'] );
427 }
428
429 /**
430 * @since 2.3.0
431 * @access public
432 */
433 public function direct_import_template() {
434 /** @var Source_Local $source */
435 $source = $this->get_source( 'local' );
436
437 return $source->import_template( $_FILES['file']['name'], $_FILES['file']['tmp_name'] );
438 }
439
440 /**
441 * Import template.
442 *
443 * Import template from a file.
444 *
445 * @since 1.0.0
446 * @access public
447 *
448 * @param array $data
449 *
450 * @return mixed Whether the export succeeded or failed.
451 */
452 public function import_template( array $data ) {
453 // If the template is a JSON file, allow uploading it.
454 add_filter( 'elementor/files/allow-file-type/json', [ $this, 'enable_json_template_upload' ] );
455 add_filter( 'elementor/files/allow_unfiltered_upload', [ $this, 'enable_json_template_upload' ] );
456
457 // Imported templates can be either JSON files, or Zip files containing multiple JSON files
458 $upload_result = Plugin::$instance->uploads_manager->handle_elementor_upload( $data, [ 'zip', 'json' ] );
459
460 remove_filter( 'elementor/files/allow-file-type/json', [ $this, 'enable_json_template_upload' ] );
461 remove_filter( 'elementor/files/allow_unfiltered_upload', [ $this, 'enable_json_template_upload' ] );
462
463 if ( is_wp_error( $upload_result ) ) {
464 Plugin::$instance->uploads_manager->remove_file_or_dir( dirname( $upload_result['tmp_name'] ) );
465
466 return $upload_result;
467 }
468
469 /** @var Source_Local $source_local */
470 $source_local = $this->get_source( 'local' );
471
472 $import_result = $source_local->import_template( $upload_result['name'], $upload_result['tmp_name'] );
473
474 // Remove the temporary directory generated for the stream-uploaded file.
475 Plugin::$instance->uploads_manager->remove_file_or_dir( dirname( $upload_result['tmp_name'] ) );
476
477 return $import_result;
478 }
479
480 /**
481 * Enable JSON Template Upload
482 *
483 * Runs on the 'elementor/files/allow-file-type/json' Uploads Manager filter.
484 *
485 * @since 3.5.0
486 * @access public
487 *
488 * return bool
489 */
490 public function enable_json_template_upload() {
491 return true;
492 }
493
494 /**
495 * Mark template as favorite.
496 *
497 * Add the template to the user favorite templates.
498 *
499 * @since 1.9.0
500 * @access public
501 *
502 * @param array $args Template arguments.
503 *
504 * @return mixed Whether the template marked as favorite.
505 */
506 public function mark_template_as_favorite( $args ) {
507 $validate_args = $this->ensure_args( [ 'source', 'template_id', 'favorite' ], $args );
508
509 if ( is_wp_error( $validate_args ) ) {
510 return $validate_args;
511 }
512
513 $source = $this->get_source( $args['source'] );
514
515 return $source->mark_as_favorite( $args['template_id'], filter_var( $args['favorite'], FILTER_VALIDATE_BOOLEAN ) );
516 }
517
518 /**
519 * Register default template sources.
520 *
521 * Register the 'local' and 'remote' template sources that Elementor use by
522 * default.
523 *
524 * @since 1.0.0
525 * @access private
526 */
527 private function register_default_sources() {
528 $sources = [
529 'local',
530 'remote',
531 ];
532
533 foreach ( $sources as $source_filename ) {
534 $class_name = ucwords( $source_filename );
535 $class_name = str_replace( '-', '_', $class_name );
536
537 $this->register_source( __NAMESPACE__ . '\Source_' . $class_name );
538 }
539 }
540
541 /**
542 * Handle ajax request.
543 *
544 * Fire authenticated ajax actions for any given ajax request.
545 *
546 * @since 1.0.0
547 * @access private
548 *
549 * @param string $ajax_request Ajax request.
550 *
551 * @param array $data
552 *
553 * @return mixed
554 * @throws \Exception
555 */
556 private function handle_ajax_request( $ajax_request, array $data ) {
557 if ( ! User::is_current_user_can_edit_post_type( Source_Local::CPT ) ) {
558 throw new \Exception( 'Access Denied' );
559 }
560
561 if ( ! empty( $data['editor_post_id'] ) ) {
562 $editor_post_id = absint( $data['editor_post_id'] );
563
564 if ( ! get_post( $editor_post_id ) ) {
565 throw new \Exception( esc_html__( 'Post not found.', 'elementor' ) );
566 }
567
568 Plugin::$instance->db->switch_to_post( $editor_post_id );
569 }
570
571 $result = call_user_func( [ $this, $ajax_request ], $data );
572
573 if ( is_wp_error( $result ) ) {
574 throw new \Exception( $result->get_error_message() );
575 }
576
577 return $result;
578 }
579
580 /**
581 * Init ajax calls.
582 *
583 * Initialize template library ajax calls for allowed ajax requests.
584 *
585 * @since 2.3.0
586 * @access public
587 *
588 * @param Ajax $ajax
589 */
590 public function register_ajax_actions( Ajax $ajax ) {
591 $library_ajax_requests = [
592 'get_library_data',
593 'get_template_data',
594 'save_template',
595 'update_templates',
596 'delete_template',
597 'import_template',
598 'mark_template_as_favorite',
599 ];
600
601 foreach ( $library_ajax_requests as $ajax_request ) {
602 $ajax->register_ajax_action( $ajax_request, function( $data ) use ( $ajax_request ) {
603 return $this->handle_ajax_request( $ajax_request, $data );
604 } );
605 }
606 }
607
608 /**
609 * @since 2.3.0
610 * @access public
611 */
612 public function handle_direct_actions() {
613 if ( ! User::is_current_user_can_edit_post_type( Source_Local::CPT ) ) {
614 return;
615 }
616
617 /** @var Ajax $ajax */
618 $ajax = Plugin::$instance->common->get_component( 'ajax' );
619
620 if ( ! $ajax->verify_request_nonce() ) {
621 $this->handle_direct_action_error( 'Access Denied' );
622 }
623
624 $action = $_REQUEST['library_action'];
625
626 $result = $this->$action( $_REQUEST );
627
628 if ( is_wp_error( $result ) ) {
629 /** @var \WP_Error $result */
630 $this->handle_direct_action_error( $result->get_error_message() . '.' );
631 }
632
633 $callback = "on_{$action}_success";
634
635 if ( method_exists( $this, $callback ) ) {
636 $this->$callback( $result );
637 }
638
639 die;
640 }
641
642 /**
643 * On successful template import.
644 *
645 * Redirect the user to the template library after template import was
646 * successful finished.
647 *
648 * @since 2.3.0
649 * @access private
650 */
651 private function on_direct_import_template_success() {
652 wp_safe_redirect( admin_url( Source_Local::ADMIN_MENU_SLUG ) );
653 }
654
655 /**
656 * @since 2.3.0
657 * @access private
658 */
659 private function handle_direct_action_error( $message ) {
660 _default_wp_die_handler( $message, 'Elementor Library' );
661 }
662
663 /**
664 * Ensure arguments exist.
665 *
666 * Checks whether the required arguments exist in the specified arguments.
667 *
668 * @since 1.0.0
669 * @access private
670 *
671 * @param array $required_args Required arguments to check whether they
672 * exist.
673 * @param array $specified_args The list of all the specified arguments to
674 * check against.
675 *
676 * @return \WP_Error|true True on success, 'WP_Error' otherwise.
677 */
678 private function ensure_args( array $required_args, array $specified_args ) {
679 $not_specified_args = array_diff( $required_args, array_keys( array_filter( $specified_args ) ) );
680
681 if ( $not_specified_args ) {
682 return new \WP_Error( 'arguments_not_specified', sprintf( 'The required argument(s) "%s" not specified.', implode( ', ', $not_specified_args ) ) );
683 }
684
685 return true;
686 }
687 }
688