Diff: STRATO-apps/wordpress_03/app/wp-content/plugins/elementor/includes/base/widget-base.php

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