PluginProbe
Elementor Website Builder – more than just a page builder / 3.28.0-dev2
Elementor Website Builder – more than just a page builder v3.28.0-dev2
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 / managers / widgets.php

widgets.php in Elementor Website Builder – more than just a page builder 3.28.0-dev2, at includes/managers/widgets.php

755 lines 17.0 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 namespace Elementor;
3
4 use Elementor\Core\Common\Modules\Ajax\Module as Ajax;
5 use Elementor\Core\Utils\Collection;
6 use Elementor\Core\Utils\Exceptions;
7 use Elementor\Core\Utils\Force_Locale;
8 use Elementor\Modules\AtomicWidgets\Elements\Atomic_Button\Atomic_Button;
9 use Elementor\Modules\AtomicWidgets\Elements\Atomic_Heading\Atomic_Heading;
10 use Elementor\Modules\AtomicWidgets\Elements\Atomic_Image\Atomic_Image;
11 use Elementor\Modules\AtomicWidgets\Elements\Atomic_Paragraph\Atomic_Paragraph;
12 use Elementor\Modules\AtomicWidgets\Elements\Atomic_Svg\Atomic_Svg;
13 use Elementor\Modules\NestedAccordion\Widgets\Nested_Accordion;
14 use Elementor\Modules\NestedElements\Module as NestedElementsModule;
15 use Elementor\Modules\NestedTabs\Widgets\NestedTabs;
16
17 if ( ! defined( 'ABSPATH' ) ) {
18 exit; // Exit if accessed directly.
19 }
20
21 /**
22 * Elementor widgets manager.
23 *
24 * Elementor widgets manager handler class is responsible for registering and
25 * initializing all the supported Elementor widgets.
26 *
27 * @since 1.0.0
28 */
29 class Widgets_Manager {
30
31 /**
32 * Widget types.
33 *
34 * Holds the list of all the widget types.
35 *
36 * @since 1.0.0
37 * @access private
38 *
39 * @var Widget_Base[]
40 */
41 private $_widget_types = null;
42
43 /**
44 * Promoted widget types.
45 *
46 * Holds the list of all the Promoted widget types.
47 *
48 * @since 3.15.0
49 * @access private
50 *
51 * @var Widget_Base[]
52 *
53 * @return array
54 */
55 private array $promoted_widgets = [
56 NestedElementsModule::EXPERIMENT_NAME => [
57 NestedTabs::class,
58 Nested_Accordion::class,
59 ],
60 'atomic_widgets' => [
61 Atomic_Heading::class,
62 Atomic_Image::class,
63 Atomic_Paragraph::class,
64 Atomic_Button::class,
65 Atomic_Svg::class,
66 ],
67 ];
68
69 /**
70 * Init widgets.
71 *
72 * Initialize Elementor widgets manager. Include all the widgets files
73 * and register each Elementor and WordPress widget.
74 *
75 * @since 2.0.0
76 * @access private
77 */
78 private function init_widgets() {
79 $build_widgets_filename = [
80 'common-base',
81 'common',
82 'common-optimized',
83 'inner-section',
84 'heading',
85 'image',
86 'text-editor',
87 'video',
88 'button',
89 'divider',
90 'spacer',
91 'image-box',
92 'google-maps',
93 'icon',
94 'icon-box',
95 'star-rating',
96 'image-carousel',
97 'image-gallery',
98 'icon-list',
99 'counter',
100 'progress',
101 'testimonial',
102 'tabs',
103 'accordion',
104 'toggle',
105 'social-icons',
106 'alert',
107 'audio',
108 'shortcode',
109 'html',
110 'menu-anchor',
111 'sidebar',
112 'read-more',
113 'rating',
114 ];
115
116 $this->_widget_types = [];
117
118 $this->register_promoted_widgets();
119
120 foreach ( $build_widgets_filename as $widget_filename ) {
121 include ELEMENTOR_PATH . 'includes/widgets/' . $widget_filename . '.php';
122
123 $class_name = str_replace( '-', '_', $widget_filename );
124
125 $class_name = __NAMESPACE__ . '\Widget_' . $class_name;
126
127 $this->register( new $class_name() );
128 }
129
130 $this->register_wp_widgets();
131
132 /**
133 * After widgets registered.
134 *
135 * Fires after Elementor widgets are registered.
136 *
137 * @since 1.0.0
138 * @deprecated 3.5.0 Use `elementor/widgets/register` hook instead.
139 *
140 * @param Widgets_Manager $this The widgets manager.
141 */
142 Plugin::$instance->modules_manager->get_modules( 'dev-tools' )->deprecation->do_deprecated_action(
143 'elementor/widgets/widgets_registered',
144 [ $this ],
145 '3.5.0',
146 'elementor/widgets/register'
147 );
148
149 /**
150 * After widgets registered.
151 *
152 * Fires after Elementor widgets are registered.
153 *
154 * @since 3.5.0
155 *
156 * @param Widgets_Manager $this The widgets manager.
157 */
158 do_action( 'elementor/widgets/register', $this );
159 }
160
161 /**
162 * Register WordPress widgets.
163 *
164 * Add native WordPress widget to the list of registered widget types.
165 *
166 * Exclude the widgets that are in Elementor widgets black list. Theme and
167 * plugin authors can filter the black list.
168 *
169 * @since 2.0.0
170 * @access private
171 */
172 private function register_wp_widgets() {
173 global $wp_widget_factory;
174
175 // Allow themes/plugins to filter out their widgets.
176 $black_list = [];
177
178 /**
179 * Elementor widgets black list.
180 *
181 * Filters the widgets black list that won't be displayed in the panel.
182 *
183 * @since 1.0.0
184 *
185 * @param array $black_list A black list of widgets. Default is an empty array.
186 */
187 $black_list = apply_filters( 'elementor/widgets/black_list', $black_list );
188
189 foreach ( $wp_widget_factory->widgets as $widget_class => $widget_obj ) {
190
191 if ( in_array( $widget_class, $black_list ) ) {
192 continue;
193 }
194
195 $elementor_widget_class = __NAMESPACE__ . '\Widget_WordPress';
196
197 $this->register(
198 new $elementor_widget_class( [], [
199 'widget_name' => $widget_class,
200 ] )
201 );
202 }
203 }
204
205 /**
206 * Require files.
207 *
208 * Require Elementor widget base class.
209 *
210 * @since 2.0.0
211 * @access private
212 */
213 private function require_files() {
214 require ELEMENTOR_PATH . 'includes/base/widget-base.php';
215 }
216
217 private function pluck_default_controls( $controls ) {
218 return ( new Collection( $controls ) )
219 ->reduce( function ( $controls_defaults, $control, $control_key ) {
220 if ( ! empty( $control['default'] ) ) {
221 $controls_defaults[ $control_key ]['default'] = $control['default'];
222 }
223
224 return $controls_defaults;
225 }, [] );
226 }
227
228 /**
229 * Register widget type.
230 *
231 * Add a new widget type to the list of registered widget types.
232 *
233 * @since 1.0.0
234 * @access public
235 * @deprecated 3.5.0 Use `register()` method instead.
236 *
237 * @param Widget_Base $widget Elementor widget.
238 *
239 * @return true True if the widget was registered.
240 */
241 public function register_widget_type( Widget_Base $widget ) {
242 Plugin::$instance->modules_manager->get_modules( 'dev-tools' )->deprecation->deprecated_function(
243 __METHOD__,
244 '3.5.0',
245 'register()'
246 );
247
248 return $this->register( $widget );
249 }
250
251 /**
252 * Register a new widget type.
253 *
254 * @param \Elementor\Widget_Base $widget_instance Elementor Widget.
255 *
256 * @return bool True if the widget was registered.
257 * @since 3.5.0
258 * @access public
259 */
260 public function register( Widget_Base $widget_instance ) {
261 if ( is_null( $this->_widget_types ) ) {
262 $this->init_widgets();
263 }
264
265 /**
266 * Should widget be registered.
267 *
268 * @since 3.18.0
269 *
270 * @param bool $should_register Should widget be registered. Default is `true`.
271 * @param \Elementor\Widget_Base $widget_instance Widget instance.
272 */
273 $should_register = apply_filters( 'elementor/widgets/is_widget_enabled', true, $widget_instance );
274
275 if ( ! $should_register ) {
276 return false;
277 }
278
279 $this->_widget_types[ $widget_instance->get_name() ] = $widget_instance;
280
281 return true;
282 }
283
284 /** Register promoted widgets
285 *
286 * Since we cannot allow widgets to place themselves is a specific
287 * location on our widgets panel we need to use a hard coded solution for this.
288 *
289 * @return void
290 */
291 private function register_promoted_widgets() {
292
293 foreach ( $this->promoted_widgets as $experiment_name => $classes ) {
294 $this->register_promoted_active_widgets( $experiment_name, $classes );
295 }
296 }
297
298 /**
299 * Unregister widget type.
300 *
301 * Removes widget type from the list of registered widget types.
302 *
303 * @since 1.0.0
304 * @access public
305 * @deprecated 3.5.0 Use `unregister()` method instead.
306 *
307 * @param string $name Widget name.
308 *
309 * @return true True if the widget was unregistered, False otherwise.
310 */
311 public function unregister_widget_type( $name ) {
312 Plugin::$instance->modules_manager->get_modules( 'dev-tools' )->deprecation->deprecated_function(
313 __METHOD__,
314 '3.5.0',
315 'unregister()'
316 );
317
318 return $this->unregister( $name );
319 }
320
321 /**
322 * Unregister widget type.
323 *
324 * Removes widget type from the list of registered widget types.
325 *
326 * @since 3.5.0
327 * @access public
328 *
329 * @param string $name Widget name.
330 *
331 * @return boolean Whether the widget was unregistered.
332 */
333 public function unregister( $name ) {
334 if ( ! isset( $this->_widget_types[ $name ] ) ) {
335 return false;
336 }
337
338 unset( $this->_widget_types[ $name ] );
339
340 return true;
341 }
342
343 /**
344 * Get widget types.
345 *
346 * Retrieve the registered widget types list.
347 *
348 * @since 1.0.0
349 * @access public
350 *
351 * @param string $widget_name Optional. Widget name. Default is null.
352 *
353 * @return Widget_Base|Widget_Base[]|null Registered widget types.
354 */
355 public function get_widget_types( $widget_name = null ) {
356 if ( is_null( $this->_widget_types ) ) {
357 $this->init_widgets();
358 }
359
360 if ( null !== $widget_name ) {
361 return isset( $this->_widget_types[ $widget_name ] ) ? $this->_widget_types[ $widget_name ] : null;
362 }
363
364 return $this->_widget_types;
365 }
366
367 /**
368 * Get widget types config.
369 *
370 * Retrieve all the registered widgets with config for each widgets.
371 *
372 * @since 1.0.0
373 * @access public
374 *
375 * @return array Registered widget types with each widget config.
376 */
377 public function get_widget_types_config() {
378 $config = [];
379
380 foreach ( $this->get_widget_types() as $widget_key => $widget ) {
381 $config[ $widget_key ] = $widget->get_config();
382 }
383
384 return $config;
385 }
386
387 /**
388 * @throws \Exception Exception.
389 */
390 public function ajax_get_widget_types_controls_config( array $data ) {
391 Plugin::$instance->documents->check_permissions( $data['editor_post_id'] );
392
393 wp_raise_memory_limit( 'admin' );
394
395 $config = [];
396
397 foreach ( $this->get_widget_types() as $widget_key => $widget ) {
398 if ( isset( $data['exclude'][ $widget_key ] ) ) {
399 continue;
400 }
401
402 $config[ $widget_key ] = [
403 'controls' => $widget->get_stack( false )['controls'],
404 'tabs_controls' => $widget->get_tabs_controls(),
405 ];
406 }
407
408 return $config;
409 }
410
411 public function ajax_get_widgets_default_value_translations( array $data = [] ) {
412 $locale = empty( $data['locale'] )
413 ? get_locale()
414 : $data['locale'];
415
416 $force_locale = new Force_Locale( $locale );
417 $force_locale->force();
418
419 $controls = ( new Collection( $this->get_widget_types() ) )
420 ->map( function ( Widget_Base $widget ) {
421 $controls = $widget->get_stack( false )['controls'];
422
423 return [
424 'controls' => $this->pluck_default_controls( $controls ),
425 ];
426 } )
427 ->filter( function ( $widget ) {
428 return ! empty( $widget['controls'] );
429 } )
430 ->all();
431
432 $force_locale->restore();
433
434 return $controls;
435 }
436
437 /**
438 * Ajax render widget.
439 *
440 * Ajax handler for Elementor render_widget.
441 *
442 * Fired by `wp_ajax_elementor_render_widget` action.
443 *
444 * @since 1.0.0
445 * @access public
446 *
447 * @throws \Exception If current user don't have permissions to edit the post.
448 *
449 * @param array $request Ajax request.
450 *
451 * @return array {
452 * Rendered widget.
453 *
454 * @type string $render The rendered HTML.
455 * }
456 */
457 public function ajax_render_widget( $request ) {
458 $document = Plugin::$instance->documents->get_with_permissions( $request['editor_post_id'] );
459
460 // Override the global $post for the render.
461 query_posts(
462 [
463 'p' => $request['editor_post_id'],
464 'post_type' => 'any',
465 ]
466 );
467
468 $editor = Plugin::$instance->editor;
469 $is_edit_mode = $editor->is_edit_mode();
470 $editor->set_edit_mode( true );
471
472 Plugin::$instance->documents->switch_to_document( $document );
473
474 $render_html = $document->render_element( $request['data'] );
475
476 $editor->set_edit_mode( $is_edit_mode );
477
478 return [
479 'render' => $render_html,
480 ];
481 }
482
483 /**
484 * Ajax get WordPress widget form.
485 *
486 * Ajax handler for Elementor editor get_wp_widget_form.
487 *
488 * Fired by `wp_ajax_elementor_editor_get_wp_widget_form` action.
489 *
490 * @since 1.0.0
491 * @access public
492 *
493 * @param array $request Ajax request.
494 *
495 * @return bool|string Rendered widget form.
496 * @throws \Exception If there is an error processing the request.
497 */
498 public function ajax_get_wp_widget_form( $request ) {
499 Plugin::$instance->documents->check_permissions( $request['editor_post_id'] );
500
501 if ( empty( $request['widget_type'] ) ) {
502 return false;
503 }
504
505 if ( empty( $request['data'] ) ) {
506 $request['data'] = [];
507 }
508
509 $element_data = [
510 'id' => $request['id'],
511 'elType' => 'widget',
512 'widgetType' => $request['widget_type'],
513 'settings' => $request['data'],
514 ];
515
516 /**
517 * @var $widget_obj Widget_WordPress
518 */
519 $widget_obj = Plugin::$instance->elements_manager->create_element_instance( $element_data );
520
521 if ( ! $widget_obj ) {
522 return false;
523 }
524
525 return $widget_obj->get_form();
526 }
527
528 /**
529 * Render widgets content.
530 *
531 * Used to generate the widget templates on the editor using Underscore JS
532 * template, for all the registered widget types.
533 *
534 * @since 1.0.0
535 * @access public
536 */
537 public function render_widgets_content() {
538 foreach ( $this->get_widget_types() as $widget ) {
539 $widget->print_template();
540 }
541 }
542
543 /**
544 * Get widgets frontend settings keys.
545 *
546 * Retrieve frontend controls settings keys for all the registered widget
547 * types.
548 *
549 * @since 1.3.0
550 * @access public
551 *
552 * @return array Registered widget types with settings keys for each widget.
553 */
554 public function get_widgets_frontend_settings_keys() {
555 $keys = [];
556
557 foreach ( $this->get_widget_types() as $widget_type_name => $widget_type ) {
558 $widget_type_keys = $widget_type->get_frontend_settings_keys();
559
560 if ( $widget_type_keys ) {
561 $keys[ $widget_type_name ] = $widget_type_keys;
562 }
563 }
564
565 return $keys;
566 }
567
568 /**
569 * Widgets with styles.
570 *
571 * This method returns the list of all the widgets in the `/includes/`
572 * folder that have styles.
573 *
574 * @since 3.24.0
575 * @access public
576 *
577 * @return array The names of the widgets that have styles.
578 */
579 public function widgets_with_styles(): array {
580 return [
581 'counter',
582 'divider',
583 'google_maps',
584 'heading',
585 'image',
586 'image-carousel',
587 'menu-anchor',
588 'rating',
589 'social-icons',
590 'spacer',
591 'testimonial',
592 'text-editor',
593 'video',
594 ];
595 }
596
597 /**
598 * Widgets with responsive styles.
599 *
600 * This method returns the list of all the widgets in the `/includes/`
601 * folder that have responsive styles.
602 *
603 * @since 3.24.0
604 * @access public
605 *
606 * @return array The names of the widgets that have responsive styles.
607 */
608 public function widgets_with_responsive_styles(): array {
609 return [
610 'accordion',
611 'alert',
612 'icon-box',
613 'icon-list',
614 'image-box',
615 'image-gallery',
616 'progress',
617 'star-rating',
618 'tabs',
619 'toggle',
620 ];
621 }
622
623 /**
624 * Enqueue widgets scripts.
625 *
626 * Enqueue all the scripts defined as a dependency for each widget.
627 *
628 * @since 1.3.0
629 * @access public
630 */
631 public function enqueue_widgets_scripts() {
632 foreach ( $this->get_widget_types() as $widget ) {
633 $widget->enqueue_scripts();
634 }
635 }
636
637 /**
638 * Enqueue widgets styles
639 *
640 * Enqueue all the styles defined as a dependency for each widget
641 *
642 * @access public
643 */
644 public function enqueue_widgets_styles() {
645 foreach ( $this->get_widget_types() as $widget ) {
646 $widget->enqueue_styles();
647 }
648 }
649
650 /**
651 * Retrieve inline editing configuration.
652 *
653 * Returns general inline editing configurations like toolbar types etc.
654 *
655 * @access public
656 * @since 1.8.0
657 *
658 * @return array {
659 * Inline editing configuration.
660 *
661 * @type array $toolbar {
662 * Toolbar types and the actions each toolbar includes.
663 * Note: Wysiwyg controls uses the advanced toolbar, textarea controls
664 * uses the basic toolbar and text controls has no toolbar.
665 *
666 * @type array $basic Basic actions included in the edit tool.
667 * @type array $advanced Advanced actions included in the edit tool.
668 * }
669 * }
670 */
671 public function get_inline_editing_config() {
672 $basic_tools = [
673 'bold',
674 'underline',
675 'italic',
676 ];
677
678 $advanced_tools = array_merge( $basic_tools, [
679 'createlink',
680 'unlink',
681 'h1' => [
682 'h1',
683 'h2',
684 'h3',
685 'h4',
686 'h5',
687 'h6',
688 'p',
689 'blockquote',
690 'pre',
691 ],
692 'list' => [
693 'insertOrderedList',
694 'insertUnorderedList',
695 ],
696 ] );
697
698 return [
699 'toolbar' => [
700 'basic' => $basic_tools,
701 'advanced' => $advanced_tools,
702 ],
703 ];
704 }
705
706 /**
707 * Widgets manager constructor.
708 *
709 * Initializing Elementor widgets manager.
710 *
711 * @since 1.0.0
712 * @access public
713 */
714 public function __construct() {
715 $this->require_files();
716
717 add_action( 'elementor/ajax/register_actions', [ $this, 'register_ajax_actions' ] );
718 }
719
720 /**
721 * Register ajax actions.
722 *
723 * Add new actions to handle data after an ajax requests returned.
724 *
725 * @since 2.0.0
726 * @access public
727 *
728 * @param Ajax $ajax_manager
729 */
730 public function register_ajax_actions( Ajax $ajax_manager ) {
731 $ajax_manager->register_ajax_action( 'render_widget', [ $this, 'ajax_render_widget' ] );
732 $ajax_manager->register_ajax_action( 'editor_get_wp_widget_form', [ $this, 'ajax_get_wp_widget_form' ] );
733 $ajax_manager->register_ajax_action( 'get_widgets_config', [ $this, 'ajax_get_widget_types_controls_config' ] );
734
735 $ajax_manager->register_ajax_action( 'get_widgets_default_value_translations', function ( array $data ) {
736 return $this->ajax_get_widgets_default_value_translations( $data );
737 } );
738 }
739
740 /**
741 * @param string $experiment_name
742 * @param array $classes
743 * @return void
744 */
745 public function register_promoted_active_widgets( string $experiment_name, array $classes ): void {
746 if ( ! Plugin::$instance->experiments->is_feature_active( $experiment_name ) || empty( $classes ) ) {
747 return;
748 }
749
750 foreach ( $classes as $class_name ) {
751 $this->register( new $class_name() );
752 }
753 }
754 }
755