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

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

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