PluginProbe
Elementor Website Builder – more than just a page builder / 3.3.0
Elementor Website Builder – more than just a page builder v3.3.0
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 / base / widget-base.php

widget-base.php in Elementor Website Builder – more than just a page builder 3.3.0, at includes/base/widget-base.php

1,021 lines 26.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\Page_Assets\Data_Managers\Widgets_Css as Widgets_Css_Data_Manager;
5
6 if ( ! defined( 'ABSPATH' ) ) {
7 exit; // Exit if accessed directly.
8 }
9
10 /**
11 * Elementor widget base.
12 *
13 * An abstract class to register new Elementor widgets. It extended the
14 * `Element_Base` class to inherit its properties.
15 *
16 * This abstract class must be extended in order to register new widgets.
17 *
18 * @since 1.0.0
19 * @abstract
20 */
21 abstract class Widget_Base extends Element_Base {
22 /**
23 * Whether the widget has content.
24 *
25 * Used in cases where the widget has no content. When widgets uses only
26 * skins to display dynamic content generated on the server. For example the
27 * posts widget in Elementor Pro. Default is true, the widget has content
28 * template.
29 *
30 * @access protected
31 *
32 * @var bool
33 */
34 protected $_has_template_content = true;
35
36 /**
37 * Registered Runtime Widgets.
38 *
39 * Registering in runtime all widgets that are being used on the page.
40 *
41 * @since 3.3.0
42 * @access public
43 * @static
44 *
45 * @var array
46 */
47 public static $registered_runtime_widgets = [];
48
49 private static $widgets_css_data_manager;
50
51 /**
52 * Get element type.
53 *
54 * Retrieve the element type, in this case `widget`.
55 *
56 * @since 1.0.0
57 * @access public
58 * @static
59 *
60 * @return string The type.
61 */
62 public static function get_type() {
63 return 'widget';
64 }
65
66 /**
67 * Get widget icon.
68 *
69 * Retrieve the widget icon.
70 *
71 * @since 1.0.0
72 * @access public
73 *
74 * @return string Widget icon.
75 */
76 public function get_icon() {
77 return 'eicon-apps';
78 }
79
80 /**
81 * Get widget keywords.
82 *
83 * Retrieve the widget keywords.
84 *
85 * @since 1.0.10
86 * @access public
87 *
88 * @return array Widget keywords.
89 */
90 public function get_keywords() {
91 return [];
92 }
93
94 /**
95 * Get widget categories.
96 *
97 * Retrieve the widget categories.
98 *
99 * @since 1.0.10
100 * @access public
101 *
102 * @return array Widget categories.
103 */
104 public function get_categories() {
105 return [ 'general' ];
106 }
107
108 /**
109 * Widget base constructor.
110 *
111 * Initializing the widget base class.
112 *
113 * @since 1.0.0
114 * @access public
115 *
116 * @throws \Exception If arguments are missing when initializing a full widget
117 * instance.
118 *
119 * @param array $data Widget data. Default is an empty array.
120 * @param array|null $args Optional. Widget default arguments. Default is null.
121 */
122 public function __construct( $data = [], $args = null ) {
123 parent::__construct( $data, $args );
124
125 $is_type_instance = $this->is_type_instance();
126
127 if ( ! $is_type_instance && null === $args ) {
128 throw new \Exception( '`$args` argument is required when initializing a full widget instance.' );
129 }
130
131 if ( $is_type_instance ) {
132 if ( $this->has_own_method( '_register_skins', self::class ) ) {
133 Plugin::$instance->modules_manager->get_modules( 'dev-tools' )->deprecation->deprecated_function( '_register_skins', '3.1.0', __CLASS__ . '::register_skins()' );
134
135 $this->_register_skins();
136 } else {
137 $this->register_skins();
138 }
139
140 $widget_name = $this->get_name();
141
142 /**
143 * Widget skin init.
144 *
145 * Fires when Elementor widget is being initialized.
146 *
147 * The dynamic portion of the hook name, `$widget_name`, refers to the widget name.
148 *
149 * @since 1.0.0
150 *
151 * @param Widget_Base $this The current widget.
152 */
153 do_action( "elementor/widget/{$widget_name}/skins_init", $this );
154 }
155 }
156
157 /**
158 * Get stack.
159 *
160 * Retrieve the widget stack of controls.
161 *
162 * @since 1.9.2
163 * @access public
164 *
165 * @param bool $with_common_controls Optional. Whether to include the common controls. Default is true.
166 *
167 * @return array Widget stack of controls.
168 */
169 public function get_stack( $with_common_controls = true ) {
170 $stack = parent::get_stack();
171
172 if ( $with_common_controls && 'common' !== $this->get_unique_name() ) {
173 /** @var Widget_Common $common_widget */
174 $common_widget = Plugin::$instance->widgets_manager->get_widget_types( 'common' );
175
176 $stack['controls'] = array_merge( $stack['controls'], $common_widget->get_controls() );
177
178 $stack['tabs'] = array_merge( $stack['tabs'], $common_widget->get_tabs_controls() );
179 }
180
181 return $stack;
182 }
183
184 /**
185 * Get widget controls pointer index.
186 *
187 * Retrieve widget pointer index where the next control should be added.
188 *
189 * While using injection point, it will return the injection point index. Otherwise index of the last control of the
190 * current widget itself without the common controls, plus one.
191 *
192 * @since 1.9.2
193 * @access public
194 *
195 * @return int Widget controls pointer index.
196 */
197 public function get_pointer_index() {
198 $injection_point = $this->get_injection_point();
199
200 if ( null !== $injection_point ) {
201 return $injection_point['index'];
202 }
203
204 return count( $this->get_stack( false )['controls'] );
205 }
206
207 /**
208 * Show in panel.
209 *
210 * Whether to show the widget in the panel or not. By default returns true.
211 *
212 * @since 1.0.0
213 * @access public
214 *
215 * @return bool Whether to show the widget in the panel or not.
216 */
217 public function show_in_panel() {
218 return true;
219 }
220
221 /**
222 * Start widget controls section.
223 *
224 * Used to add a new section of controls to the widget. Regular controls and
225 * skin controls.
226 *
227 * Note that when you add new controls to widgets they must be wrapped by
228 * `start_controls_section()` and `end_controls_section()`.
229 *
230 * @since 1.0.0
231 * @access public
232 *
233 * @param string $section_id Section ID.
234 * @param array $args Section arguments Optional.
235 */
236 public function start_controls_section( $section_id, array $args = [] ) {
237 parent::start_controls_section( $section_id, $args );
238
239 static $is_first_section = true;
240
241 if ( $is_first_section ) {
242 $this->register_skin_control();
243
244 $is_first_section = false;
245 }
246 }
247
248 /**
249 * Register the Skin Control if the widget has skins.
250 *
251 * An internal method that is used to add a skin control to the widget.
252 * Added at the top of the controls section.
253 *
254 * @since 2.0.0
255 * @access private
256 */
257 private function register_skin_control() {
258 $skins = $this->get_skins();
259 if ( ! empty( $skins ) ) {
260 $skin_options = [];
261
262 if ( $this->_has_template_content ) {
263 $skin_options[''] = __( 'Default', 'elementor' );
264 }
265
266 foreach ( $skins as $skin_id => $skin ) {
267 $skin_options[ $skin_id ] = $skin->get_title();
268 }
269
270 // Get the first item for default value
271 $default_value = array_keys( $skin_options );
272 $default_value = array_shift( $default_value );
273
274 if ( 1 >= count( $skin_options ) ) {
275 $this->add_control(
276 '_skin',
277 [
278 'label' => __( 'Skin', 'elementor' ),
279 'type' => Controls_Manager::HIDDEN,
280 'default' => $default_value,
281 ]
282 );
283 } else {
284 $this->add_control(
285 '_skin',
286 [
287 'label' => __( 'Skin', 'elementor' ),
288 'type' => Controls_Manager::SELECT,
289 'default' => $default_value,
290 'options' => $skin_options,
291 ]
292 );
293 }
294 }
295 }
296
297 /**
298 * Register widget skins - deprecated prefixed method
299 *
300 * @since 1.7.12
301 * @access protected
302 * @deprecated 3.1.0
303 */
304 protected function _register_skins() {
305 Plugin::$instance->modules_manager->get_modules( 'dev-tools' )->deprecation->deprecated_function( __METHOD__, '3.1.0', __CLASS__ . '::register_skins()' );
306
307 $this->register_skins();
308 }
309
310 /**
311 * Register widget skins.
312 *
313 * This method is activated while initializing the widget base class. It is
314 * used to assign skins to widgets with `add_skin()` method.
315 *
316 * Usage:
317 *
318 * protected function register_skins() {
319 * $this->add_skin( new Skin_Classic( $this ) );
320 * }
321 *
322 * @since 3.1.0
323 * @access protected
324 */
325 protected function register_skins() {}
326
327 /**
328 * Get initial config.
329 *
330 * Retrieve the current widget initial configuration.
331 *
332 * Adds more configuration on top of the controls list, the tabs assigned to
333 * the control, element name, type, icon and more. This method also adds
334 * widget type, keywords and categories.
335 *
336 * @since 2.9.0
337 * @access protected
338 *
339 * @return array The initial widget config.
340 */
341 protected function get_initial_config() {
342 $config = [
343 'widget_type' => $this->get_name(),
344 'keywords' => $this->get_keywords(),
345 'categories' => $this->get_categories(),
346 'html_wrapper_class' => $this->get_html_wrapper_class(),
347 'show_in_panel' => $this->show_in_panel(),
348 ];
349
350 $stack = Plugin::$instance->controls_manager->get_element_stack( $this );
351
352 if ( $stack ) {
353 $config['controls'] = $this->get_stack( false )['controls'];
354 $config['tabs_controls'] = $this->get_tabs_controls();
355 }
356
357 return array_merge( parent::get_initial_config(), $config );
358 }
359
360 /**
361 * @since 2.3.1
362 * @access protected
363 */
364 protected function should_print_empty() {
365 return false;
366 }
367
368 /**
369 * Print widget content template.
370 *
371 * Used to generate the widget content template on the editor, using a
372 * Backbone JavaScript template.
373 *
374 * @since 2.0.0
375 * @access protected
376 *
377 * @param string $template_content Template content.
378 */
379 protected function print_template_content( $template_content ) {
380 ?>
381 <div class="elementor-widget-container">
382 <?php
383 echo $template_content; // XSS ok.
384 ?>
385 </div>
386 <?php
387 }
388
389 /**
390 * Parse text editor.
391 *
392 * Parses the content from rich text editor with shortcodes, oEmbed and
393 * filtered data.
394 *
395 * @since 1.0.0
396 * @access protected
397 *
398 * @param string $content Text editor content.
399 *
400 * @return string Parsed content.
401 */
402 protected function parse_text_editor( $content ) {
403 /** This filter is documented in wp-includes/widgets/class-wp-widget-text.php */
404 $content = apply_filters( 'widget_text', $content, $this->get_settings() );
405
406 $content = shortcode_unautop( $content );
407 $content = do_shortcode( $content );
408 $content = wptexturize( $content );
409
410 if ( $GLOBALS['wp_embed'] instanceof \WP_Embed ) {
411 $content = $GLOBALS['wp_embed']->autoembed( $content );
412 }
413
414 return $content;
415 }
416
417 /**
418 * Get HTML wrapper class.
419 *
420 * Retrieve the widget container class. Can be used to override the
421 * container class for specific widgets.
422 *
423 * @since 2.0.9
424 * @access protected
425 */
426 protected function get_html_wrapper_class() {
427 return 'elementor-widget-' . $this->get_name();
428 }
429
430 /**
431 * Add widget render attributes.
432 *
433 * Used to add attributes to the current widget wrapper HTML tag.
434 *
435 * @since 1.0.0
436 * @access protected
437 */
438 protected function add_render_attributes() {
439 parent::add_render_attributes();
440
441 $this->add_render_attribute(
442 '_wrapper', 'class', [
443 'elementor-widget',
444 $this->get_html_wrapper_class(),
445 ]
446 );
447
448 $settings = $this->get_settings();
449
450 $this->add_render_attribute( '_wrapper', 'data-widget_type', $this->get_name() . '.' . ( ! empty( $settings['_skin'] ) ? $settings['_skin'] : 'default' ) );
451 }
452
453 /**
454 * Add lightbox data to image link.
455 *
456 * Used to add lightbox data attributes to image link HTML.
457 *
458 * @since 2.9.1
459 * @access public
460 *
461 * @param string $link_html Image link HTML.
462 * @param string $id Attachment id.
463 *
464 * @return string Image link HTML with lightbox data attributes.
465 */
466 public function add_lightbox_data_to_image_link( $link_html, $id ) {
467 $settings = $this->get_settings_for_display();
468 $open_lightbox = isset( $settings['open_lightbox'] ) ? $settings['open_lightbox'] : null;
469
470 if ( Plugin::$instance->editor->is_edit_mode() ) {
471 $this->add_render_attribute( 'link', 'class', 'elementor-clickable', true );
472 }
473
474 $this->add_lightbox_data_attributes( 'link', $id, $open_lightbox, $this->get_id(), true );
475 return preg_replace( '/^<a/', '<a ' . $this->get_render_attribute_string( 'link' ), $link_html );
476 }
477
478 /**
479 * Add Light-Box attributes.
480 *
481 * Used to add Light-Box-related data attributes to links that open media files.
482 *
483 * @param array|string $element The link HTML element.
484 * @param int $id The ID of the image
485 * @param string $lightbox_setting_key The setting key that dictates weather to open the image in a lightbox
486 * @param string $group_id Unique ID for a group of lightbox images
487 * @param bool $overwrite Optional. Whether to overwrite existing
488 * attribute. Default is false, not to overwrite.
489 *
490 * @return Widget_Base Current instance of the widget.
491 * @since 2.9.0
492 * @access public
493 *
494 */
495 public function add_lightbox_data_attributes( $element, $id = null, $lightbox_setting_key = null, $group_id = null, $overwrite = false ) {
496 $kit = Plugin::$instance->kits_manager->get_active_kit();
497
498 $is_global_image_lightbox_enabled = 'yes' === $kit->get_settings( 'global_image_lightbox' );
499
500 if ( 'no' === $lightbox_setting_key ) {
501 if ( $is_global_image_lightbox_enabled ) {
502 $this->add_render_attribute( $element, 'data-elementor-open-lightbox', 'no', $overwrite );
503 }
504
505 return $this;
506 }
507
508 if ( 'yes' !== $lightbox_setting_key && ! $is_global_image_lightbox_enabled ) {
509 return $this;
510 }
511
512 $attributes['data-elementor-open-lightbox'] = 'yes';
513
514 if ( $group_id ) {
515 $attributes['data-elementor-lightbox-slideshow'] = $group_id;
516 }
517
518 if ( $id ) {
519 $lightbox_image_attributes = Plugin::$instance->images_manager->get_lightbox_image_attributes( $id );
520
521 if ( isset( $lightbox_image_attributes['title'] ) ) {
522 $attributes['data-elementor-lightbox-title'] = $lightbox_image_attributes['title'];
523 }
524
525 if ( isset( $lightbox_image_attributes['description'] ) ) {
526 $attributes['data-elementor-lightbox-description'] = $lightbox_image_attributes['description'];
527 }
528 }
529
530 $this->add_render_attribute( $element, $attributes, null, $overwrite );
531
532 return $this;
533 }
534
535 /**
536 * Render widget output on the frontend.
537 *
538 * Used to generate the final HTML displayed on the frontend.
539 *
540 * Note that if skin is selected, it will be rendered by the skin itself,
541 * not the widget.
542 *
543 * @since 1.0.0
544 * @access public
545 */
546 public function render_content() {
547 /**
548 * Before widget render content.
549 *
550 * Fires before Elementor widget is being rendered.
551 *
552 * @since 1.0.0
553 *
554 * @param Widget_Base $this The current widget.
555 */
556 do_action( 'elementor/widget/before_render_content', $this );
557
558 ob_start();
559
560 $skin = $this->get_current_skin();
561 if ( $skin ) {
562 $skin->set_parent( $this );
563 $skin->render_by_mode();
564 } else {
565 $this->render_by_mode();
566 }
567
568 $widget_content = ob_get_clean();
569
570 if ( empty( $widget_content ) ) {
571 return;
572 }
573 ?>
574 <div class="elementor-widget-container">
575 <?php
576 if ( $this->is_widget_first_render() ) {
577
578 $this->register_runtime_widget( $this->get_group_name() );
579
580 $this->print_widget_css();
581 }
582
583 // get_name
584
585 /**
586 * Render widget content.
587 *
588 * Filters the widget content before it's rendered.
589 *
590 * @since 1.0.0
591 *
592 * @param string $widget_content The content of the widget.
593 * @param Widget_Base $this The widget.
594 */
595 $widget_content = apply_filters( 'elementor/widget/render_content', $widget_content, $this );
596
597 echo $widget_content; // XSS ok.
598 ?>
599 </div>
600 <?php
601 }
602
603 protected function is_widget_first_render() {
604 return ! in_array( $this->get_group_name(), self::$registered_runtime_widgets, true );
605 }
606
607 /**
608 * Render widget plain content.
609 *
610 * Elementor saves the page content in a unique way, but it's not the way
611 * WordPress saves data. This method is used to save generated HTML to the
612 * database as plain content the WordPress way.
613 *
614 * When rendering plain content, it allows other WordPress plugins to
615 * interact with the content - to search, check SEO and other purposes. It
616 * also allows the site to keep working even if Elementor is deactivated.
617 *
618 * Note that if the widget uses shortcodes to display the data, the best
619 * practice is to return the shortcode itself.
620 *
621 * Also note that if the widget don't display any content it should return
622 * an empty string. For example Elementor Pro Form Widget uses this method
623 * to return an empty string because there is no content to return. This way
624 * if Elementor Pro will be deactivated there won't be any form to display.
625 *
626 * @since 1.0.0
627 * @access public
628 */
629 public function render_plain_content() {
630 $this->render_content();
631 }
632
633 /**
634 * Before widget rendering.
635 *
636 * Used to add stuff before the widget `_wrapper` element.
637 *
638 * @since 1.0.0
639 * @access public
640 */
641 public function before_render() {
642 ?>
643 <div <?php $this->print_render_attribute_string( '_wrapper' ); ?>>
644 <?php
645 }
646
647 /**
648 * After widget rendering.
649 *
650 * Used to add stuff after the widget `_wrapper` element.
651 *
652 * @since 1.0.0
653 * @access public
654 */
655 public function after_render() {
656 ?>
657 </div>
658 <?php
659 }
660
661 /**
662 * Get the element raw data.
663 *
664 * Retrieve the raw element data, including the id, type, settings, child
665 * elements and whether it is an inner element.
666 *
667 * The data with the HTML used always to display the data, but the Elementor
668 * editor uses the raw data without the HTML in order not to render the data
669 * again.
670 *
671 * @since 1.0.0
672 * @access public
673 *
674 * @param bool $with_html_content Optional. Whether to return the data with
675 * HTML content or without. Used for caching.
676 * Default is false, without HTML.
677 *
678 * @return array Element raw data.
679 */
680 public function get_raw_data( $with_html_content = false ) {
681 $data = parent::get_raw_data( $with_html_content );
682
683 unset( $data['isInner'] );
684
685 $data['widgetType'] = $this->get_data( 'widgetType' );
686
687 if ( $with_html_content ) {
688 ob_start();
689
690 $this->render_content();
691
692 $data['htmlCache'] = ob_get_clean();
693 }
694
695 return $data;
696 }
697
698 /**
699 * Print widget content.
700 *
701 * Output the widget final HTML on the frontend.
702 *
703 * @since 1.0.0
704 * @access protected
705 */
706 protected function print_content() {
707 $this->render_content();
708 }
709
710 /**
711 * Print a setting content without escaping.
712 *
713 * Script tags are allowed on frontend according to the WP theme securing policy.
714 *
715 * @param string $setting
716 * @param null $repeater_name
717 * @param null $index
718 */
719 final protected function print_unescaped_setting( $setting, $repeater_name = null, $index = null ) {
720 if ( $repeater_name ) {
721 $repeater = $this->get_settings_for_display( $repeater_name );
722 $output = $repeater[ $index ][ $setting ];
723 } else {
724 $output = $this->get_settings_for_display( $setting );
725 }
726
727 echo $output; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
728 }
729
730 /**
731 * Get default data.
732 *
733 * Retrieve the default widget data. Used to reset the data on initialization.
734 *
735 * @since 1.0.0
736 * @access protected
737 *
738 * @return array Default data.
739 */
740 protected function get_default_data() {
741 $data = parent::get_default_data();
742
743 $data['widgetType'] = '';
744
745 return $data;
746 }
747
748 /**
749 * Get default child type.
750 *
751 * Retrieve the widget child type based on element data.
752 *
753 * @since 1.0.0
754 * @access protected
755 *
756 * @param array $element_data Widget ID.
757 *
758 * @return array|false Child type or false if it's not a valid widget.
759 */
760 protected function _get_default_child_type( array $element_data ) {
761 return Plugin::$instance->elements_manager->get_element_types( 'section' );
762 }
763
764 /**
765 * Get repeater setting key.
766 *
767 * Retrieve the unique setting key for the current repeater item. Used to connect the current element in the
768 * repeater to it's settings model and it's control in the panel.
769 *
770 * PHP usage (inside `Widget_Base::render()` method):
771 *
772 * $tabs = $this->get_settings( 'tabs' );
773 * foreach ( $tabs as $index => $item ) {
774 * $tab_title_setting_key = $this->get_repeater_setting_key( 'tab_title', 'tabs', $index );
775 * $this->add_inline_editing_attributes( $tab_title_setting_key, 'none' );
776 * echo '<div ' . $this->get_render_attribute_string( $tab_title_setting_key ) . '>' . $item['tab_title'] . '</div>';
777 * }
778 *
779 * @since 1.8.0
780 * @access protected
781 *
782 * @param string $setting_key The current setting key inside the repeater item (e.g. `tab_title`).
783 * @param string $repeater_key The repeater key containing the array of all the items in the repeater (e.g. `tabs`).
784 * @param int $repeater_item_index The current item index in the repeater array (e.g. `3`).
785 *
786 * @return string The repeater setting key (e.g. `tabs.3.tab_title`).
787 */
788 protected function get_repeater_setting_key( $setting_key, $repeater_key, $repeater_item_index ) {
789 return implode( '.', [ $repeater_key, $repeater_item_index, $setting_key ] );
790 }
791
792 /**
793 * Add inline editing attributes.
794 *
795 * Define specific area in the element to be editable inline. The element can have several areas, with this method
796 * you can set the area inside the element that can be edited inline. You can also define the type of toolbar the
797 * user will see, whether it will be a basic toolbar or an advanced one.
798 *
799 * Note: When you use wysiwyg control use the advanced toolbar, with textarea control use the basic toolbar. Text
800 * control should not have toolbar.
801 *
802 * PHP usage (inside `Widget_Base::render()` method):
803 *
804 * $this->add_inline_editing_attributes( 'text', 'advanced' );
805 * echo '<div ' . $this->get_render_attribute_string( 'text' ) . '>' . $this->get_settings( 'text' ) . '</div>';
806 *
807 * @since 1.8.0
808 * @access protected
809 *
810 * @param string $key Element key.
811 * @param string $toolbar Optional. Toolbar type. Accepted values are `advanced`, `basic` or `none`. Default is
812 * `basic`.
813 */
814 protected function add_inline_editing_attributes( $key, $toolbar = 'basic' ) {
815 if ( ! Plugin::$instance->editor->is_edit_mode() ) {
816 return;
817 }
818
819 $this->add_render_attribute( $key, [
820 'class' => 'elementor-inline-editing',
821 'data-elementor-setting-key' => $key,
822 ] );
823
824 if ( 'basic' !== $toolbar ) {
825 $this->add_render_attribute( $key, [
826 'data-elementor-inline-editing-toolbar' => $toolbar,
827 ] );
828 }
829 }
830
831 /**
832 * Add new skin.
833 *
834 * Register new widget skin to allow the user to set custom designs. Must be
835 * called inside the `register_skins()` method.
836 *
837 * @since 1.0.0
838 * @access public
839 *
840 * @param Skin_Base $skin Skin instance.
841 */
842 public function add_skin( Skin_Base $skin ) {
843 Plugin::$instance->skins_manager->add_skin( $this, $skin );
844 }
845
846 /**
847 * Get single skin.
848 *
849 * Retrieve a single skin based on skin ID, from all the skin assigned to
850 * the widget. If the skin does not exist or not assigned to the widget,
851 * return false.
852 *
853 * @since 1.0.0
854 * @access public
855 *
856 * @param string $skin_id Skin ID.
857 *
858 * @return string|false Single skin, or false.
859 */
860 public function get_skin( $skin_id ) {
861 $skins = $this->get_skins();
862 if ( isset( $skins[ $skin_id ] ) ) {
863 return $skins[ $skin_id ];
864 }
865
866 return false;
867 }
868
869 /**
870 * Get current skin ID.
871 *
872 * Retrieve the ID of the current skin.
873 *
874 * @since 1.0.0
875 * @access public
876 *
877 * @return string Current skin.
878 */
879 public function get_current_skin_id() {
880 return $this->get_settings( '_skin' );
881 }
882
883 /**
884 * Get current skin.
885 *
886 * Retrieve the current skin, or if non exist return false.
887 *
888 * @since 1.0.0
889 * @access public
890 *
891 * @return Skin_Base|false Current skin or false.
892 */
893 public function get_current_skin() {
894 return $this->get_skin( $this->get_current_skin_id() );
895 }
896
897 /**
898 * Remove widget skin.
899 *
900 * Unregister an existing skin and remove it from the widget.
901 *
902 * @since 1.0.0
903 * @access public
904 *
905 * @param string $skin_id Skin ID.
906 *
907 * @return \WP_Error|true Whether the skin was removed successfully from the widget.
908 */
909 public function remove_skin( $skin_id ) {
910 return Plugin::$instance->skins_manager->remove_skin( $this, $skin_id );
911 }
912
913 /**
914 * Get widget skins.
915 *
916 * Retrieve all the skin assigned to the widget.
917 *
918 * @since 1.0.0
919 * @access public
920 *
921 * @return Skin_Base[]
922 */
923 public function get_skins() {
924 return Plugin::$instance->skins_manager->get_skins( $this );
925 }
926
927 /**
928 * Get group name.
929 *
930 * Some widgets need to use group names, this method allows you to create them.
931 * By default it retrieves the regular name.
932 *
933 * @since 3.3.0
934 * @access public
935 *
936 * @return string Unique name.
937 */
938 public function get_group_name() {
939 return $this->get_name();
940 }
941
942 /**
943 * @param string $plugin_title Plugin's title
944 * @param string $since Plugin version widget was deprecated
945 * @param string $last Plugin version in which the widget will be removed
946 * @param string $replacement Widget replacement
947 */
948 protected function deprecated_notice( $plugin_title, $since, $last = '', $replacement = '' ) {
949 $this->start_controls_section( 'Deprecated',
950 [
951 'label' => __( 'Deprecated', 'elementor' ),
952 ]
953 );
954
955 $this->add_control(
956 'deprecated_notice',
957 [
958 'type' => Controls_Manager::DEPRECATED_NOTICE,
959 'widget' => $this->get_title(),
960 'since' => $since,
961 'last' => $last,
962 'plugin' => $plugin_title,
963 'replacement' => $replacement,
964 ]
965 );
966
967 $this->end_controls_section();
968
969 }
970
971 public function register_runtime_widget( $widget_name ) {
972 self::$registered_runtime_widgets[] = $widget_name;
973 }
974
975 public function get_css_config() {
976 $widget_name = $this->get_group_name();
977
978 $direction = is_rtl() ? '-rtl' : '';
979
980 $css_file_path = 'css/widget-' . $widget_name . $direction . '.min.css';
981
982 return [
983 'key' => $widget_name,
984 'version' => ELEMENTOR_VERSION,
985 'file_path' => ELEMENTOR_ASSETS_PATH . $css_file_path,
986 'data' => [
987 'file_url' => ELEMENTOR_ASSETS_URL . $css_file_path,
988 ],
989 ];
990 }
991
992 private function get_widget_css() {
993 $widgets_css_data_manager = $this->get_widgets_css_data_manager();
994
995 $widget_css = $widgets_css_data_manager->get_asset_data( $this->get_css_config() );
996
997 return $widget_css;
998
999 }
1000
1001 private function print_widget_css() {
1002 $is_edit_mode = Plugin::$instance->editor->is_edit_mode();
1003 $is_preview_mode = Plugin::$instance->preview->is_preview_mode();
1004 $is_optimized_mode = Plugin::$instance->experiments->is_feature_active( 'e_optimized_css_loading' );
1005
1006 if ( Utils::is_script_debug() || $is_edit_mode || $is_preview_mode || ! $is_optimized_mode ) {
1007 return;
1008 }
1009
1010 echo $this->get_widget_css();
1011 }
1012
1013 private function get_widgets_css_data_manager() {
1014 if ( ! self::$widgets_css_data_manager ) {
1015 self::$widgets_css_data_manager = new Widgets_Css_Data_Manager();
1016 }
1017
1018 return self::$widgets_css_data_manager;
1019 }
1020 }
1021