PluginProbe
Elementor Website Builder – more than just a page builder / 3.3.1
Elementor Website Builder – more than just a page builder v3.3.1
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.3.1, at includes/template-library/manager.php

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