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

672 lines 15.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\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 /** @var Source_Local $source */
463 $file_content = base64_decode( $data['fileData'] );
464
465 $tmp_file = tmpfile();
466
467 fwrite( $tmp_file, $file_content );
468
469 $source = $this->get_source( 'local' );
470
471 $result = $source->import_template( $data['fileName'], stream_get_meta_data( $tmp_file )['uri'] );
472
473 fclose( $tmp_file );
474
475 return $result;
476 }
477
478 /**
479 * Mark template as favorite.
480 *
481 * Add the template to the user favorite templates.
482 *
483 * @since 1.9.0
484 * @access public
485 *
486 * @param array $args Template arguments.
487 *
488 * @return mixed Whether the template marked as favorite.
489 */
490 public function mark_template_as_favorite( $args ) {
491 $validate_args = $this->ensure_args( [ 'source', 'template_id', 'favorite' ], $args );
492
493 if ( is_wp_error( $validate_args ) ) {
494 return $validate_args;
495 }
496
497 $source = $this->get_source( $args['source'] );
498
499 return $source->mark_as_favorite( $args['template_id'], filter_var( $args['favorite'], FILTER_VALIDATE_BOOLEAN ) );
500 }
501
502 /**
503 * Register default template sources.
504 *
505 * Register the 'local' and 'remote' template sources that Elementor use by
506 * default.
507 *
508 * @since 1.0.0
509 * @access private
510 */
511 private function register_default_sources() {
512 $sources = [
513 'local',
514 'remote',
515 ];
516
517 foreach ( $sources as $source_filename ) {
518 $class_name = ucwords( $source_filename );
519 $class_name = str_replace( '-', '_', $class_name );
520
521 $this->register_source( __NAMESPACE__ . '\Source_' . $class_name );
522 }
523 }
524
525 /**
526 * Handle ajax request.
527 *
528 * Fire authenticated ajax actions for any given ajax request.
529 *
530 * @since 1.0.0
531 * @access private
532 *
533 * @param string $ajax_request Ajax request.
534 *
535 * @param array $data
536 *
537 * @return mixed
538 * @throws \Exception
539 */
540 private function handle_ajax_request( $ajax_request, array $data ) {
541 if ( ! User::is_current_user_can_edit_post_type( Source_Local::CPT ) ) {
542 throw new \Exception( 'Access Denied' );
543 }
544
545 if ( ! empty( $data['editor_post_id'] ) ) {
546 $editor_post_id = absint( $data['editor_post_id'] );
547
548 if ( ! get_post( $editor_post_id ) ) {
549 throw new \Exception( __( 'Post not found.', 'elementor' ) );
550 }
551
552 Plugin::$instance->db->switch_to_post( $editor_post_id );
553 }
554
555 $result = call_user_func( [ $this, $ajax_request ], $data );
556
557 if ( is_wp_error( $result ) ) {
558 throw new \Exception( $result->get_error_message() );
559 }
560
561 return $result;
562 }
563
564 /**
565 * Init ajax calls.
566 *
567 * Initialize template library ajax calls for allowed ajax requests.
568 *
569 * @since 2.3.0
570 * @access public
571 *
572 * @param Ajax $ajax
573 */
574 public function register_ajax_actions( Ajax $ajax ) {
575 $library_ajax_requests = [
576 'get_library_data',
577 'get_template_data',
578 'save_template',
579 'update_templates',
580 'delete_template',
581 'import_template',
582 'mark_template_as_favorite',
583 ];
584
585 foreach ( $library_ajax_requests as $ajax_request ) {
586 $ajax->register_ajax_action( $ajax_request, function( $data ) use ( $ajax_request ) {
587 return $this->handle_ajax_request( $ajax_request, $data );
588 } );
589 }
590 }
591
592 /**
593 * @since 2.3.0
594 * @access public
595 */
596 public function handle_direct_actions() {
597 if ( ! User::is_current_user_can_edit_post_type( Source_Local::CPT ) ) {
598 return;
599 }
600
601 /** @var Ajax $ajax */
602 $ajax = Plugin::$instance->common->get_component( 'ajax' );
603
604 if ( ! $ajax->verify_request_nonce() ) {
605 $this->handle_direct_action_error( 'Access Denied' );
606 }
607
608 $action = $_REQUEST['library_action'];
609
610 $result = $this->$action( $_REQUEST );
611
612 if ( is_wp_error( $result ) ) {
613 /** @var \WP_Error $result */
614 $this->handle_direct_action_error( $result->get_error_message() . '.' );
615 }
616
617 $callback = "on_{$action}_success";
618
619 if ( method_exists( $this, $callback ) ) {
620 $this->$callback( $result );
621 }
622
623 die;
624 }
625
626 /**
627 * On successful template import.
628 *
629 * Redirect the user to the template library after template import was
630 * successful finished.
631 *
632 * @since 2.3.0
633 * @access private
634 */
635 private function on_direct_import_template_success() {
636 wp_safe_redirect( admin_url( Source_Local::ADMIN_MENU_SLUG ) );
637 }
638
639 /**
640 * @since 2.3.0
641 * @access private
642 */
643 private function handle_direct_action_error( $message ) {
644 _default_wp_die_handler( $message, 'Elementor Library' );
645 }
646
647 /**
648 * Ensure arguments exist.
649 *
650 * Checks whether the required arguments exist in the specified arguments.
651 *
652 * @since 1.0.0
653 * @access private
654 *
655 * @param array $required_args Required arguments to check whether they
656 * exist.
657 * @param array $specified_args The list of all the specified arguments to
658 * check against.
659 *
660 * @return \WP_Error|true True on success, 'WP_Error' otherwise.
661 */
662 private function ensure_args( array $required_args, array $specified_args ) {
663 $not_specified_args = array_diff( $required_args, array_keys( array_filter( $specified_args ) ) );
664
665 if ( $not_specified_args ) {
666 return new \WP_Error( 'arguments_not_specified', sprintf( 'The required argument(s) "%s" not specified.', implode( ', ', $not_specified_args ) ) );
667 }
668
669 return true;
670 }
671 }
672