PluginProbe
Elementor Website Builder – more than just a page builder / 3.24.4
Elementor Website Builder – more than just a page builder v3.24.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.24.4, at includes/managers/widgets.php

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