PluginProbe
Elementor Website Builder – more than just a page builder / 3.5.2
Elementor Website Builder – more than just a page builder v3.5.2
4.3.1 4.3.0 4.3.0-beta3 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 All 454 releases
← All changes | includes/base/widget-base.php +207 -163 4.3.0-beta23.5.2 View file →
@@ -1,10 +1,9 @@
1 1 <?php
2 2 namespace Elementor;
3 3
4 -use Elementor\Core\Frontend\Widget_Content_Render_Mode;
5 -use Elementor\Core\Utils\Promotions\Filtered_Promotions_Manager;
6 -use Elementor\Utils;
4 +use Elementor\Core\Page_Assets\Data_Managers\Responsive_Widgets as Responsive_Widgets_Data_Manager;
5 +use Elementor\Core\Page_Assets\Data_Managers\Widgets_Css as Widgets_Css_Data_Manager;
7 6
8 7 if ( ! defined( 'ABSPATH' ) ) {
9 8 exit; // Exit if accessed directly.
10 9 }
@@ -34,10 +33,8 @@
34 33 * @var bool
35 34 */
36 35 protected $_has_template_content = true;
37 36
38 - private $is_first_section = true;
39 -
40 37 /**
41 38 * Registered Runtime Widgets.
42 39 *
43 40 * Registering in runtime all widgets that are being used on the page.
@@ -49,8 +46,14 @@
49 46 * @var array
50 47 */
51 48 public static $registered_runtime_widgets = [];
52 49
50 + public static $registered_inline_css_widgets = [];
51 +
52 + private static $widgets_css_data_manager;
53 +
54 + private static $responsive_widgets_data_manager;
55 +
53 56 /**
54 57 * Get element type.
55 58 *
56 59 * Retrieve the element type, in this case `widget`.
@@ -107,22 +110,8 @@
107 110 return [ 'general' ];
108 111 }
109 112
110 113 /**
111 - * Get widget upsale data.
112 - *
113 - * Retrieve the widget promotion data.
114 - *
115 - * @since 3.18.0
116 - * @access protected
117 - *
118 - * @return array|null Widget promotion data.
119 - */
120 - protected function get_upsale_data() {
121 - return null;
122 - }
123 -
124 - /**
125 114 * Widget base constructor.
126 115 *
127 116 * Initializing the widget base class.
128 117 *
@@ -140,9 +129,9 @@
140 129
141 130 $is_type_instance = $this->is_type_instance();
142 131
143 132 if ( ! $is_type_instance && null === $args ) {
144 - throw new \Exception( 'An `$args` argument is required when initializing a full widget instance.' );
133 + throw new \Exception( '`$args` argument is required when initializing a full widget instance.' );
145 134 }
146 135
147 136 if ( $is_type_instance ) {
148 137 if ( $this->has_own_method( '_register_skins', self::class ) ) {
@@ -184,11 +173,11 @@
184 173 */
185 174 public function get_stack( $with_common_controls = true ) {
186 175 $stack = parent::get_stack();
187 176
188 - if ( $with_common_controls && ! $this instanceof Widget_Common_Base ) {
189 - /** @var Widget_Common_Base $common_widget */
190 - $common_widget = Plugin::$instance->widgets_manager->get_widget_types( $this->get_common_widget_name() );
177 + if ( $with_common_controls && 'common' !== $this->get_unique_name() ) {
178 + /** @var Widget_Common $common_widget */
179 + $common_widget = Plugin::$instance->widgets_manager->get_widget_types( 'common' );
191 180
192 181 $stack['controls'] = array_merge( $stack['controls'], $common_widget->get_controls() );
193 182
194 183 $stack['tabs'] = array_merge( $stack['tabs'], $common_widget->get_tabs_controls() );
@@ -196,16 +185,8 @@
196 185
197 186 return $stack;
198 187 }
199 188
200 - private function get_common_widget_name() {
201 - if ( Plugin::$instance->experiments->is_feature_active( 'e_optimized_markup' ) ) {
202 - return $this->has_widget_inner_wrapper() ? 'common' : 'common-optimized';
203 - }
204 -
205 - return 'common';
206 - }
207 -
208 189 /**
209 190 * Get widget controls pointer index.
210 191 *
211 192 * Retrieve widget pointer index where the next control should be added.
@@ -242,21 +223,8 @@
242 223 return true;
243 224 }
244 225
245 226 /**
246 - * Hide on search.
247 - *
248 - * Whether to hide the widget on search in the panel or not. By default returns false.
249 - *
250 - * @access public
251 - *
252 - * @return bool Whether to hide the widget when searching for widget or not.
253 - */
254 - public function hide_on_search() {
255 - return false;
256 - }
257 -
258 - /**
259 227 * Start widget controls section.
260 228 *
261 229 * Used to add a new section of controls to the widget. Regular controls and
262 230 * skin controls.
@@ -272,12 +240,14 @@
272 240 */
273 241 public function start_controls_section( $section_id, array $args = [] ) {
274 242 parent::start_controls_section( $section_id, $args );
275 243
276 - if ( $this->is_first_section ) {
244 + static $is_first_section = true;
245 +
246 + if ( $is_first_section ) {
277 247 $this->register_skin_control();
278 248
279 - $this->is_first_section = false;
249 + $is_first_section = false;
280 250 }
281 251 }
282 252
283 253 /**
@@ -301,9 +271,9 @@
301 271 foreach ( $skins as $skin_id => $skin ) {
302 272 $skin_options[ $skin_id ] = $skin->get_title();
303 273 }
304 274
305 - // Get the first item for default value.
275 + // Get the first item for default value
306 276 $default_value = array_keys( $skin_options );
307 277 $default_value = array_shift( $default_value );
308 278
309 279 if ( 1 >= count( $skin_options ) ) {
@@ -333,12 +303,12 @@
333 303 * Register widget skins - deprecated prefixed method
334 304 *
335 305 * @since 1.7.12
336 306 * @access protected
337 - * @deprecated 3.1.0 Use `register_skins()` method instead.
307 + * @deprecated 3.1.0
338 308 */
339 309 protected function _register_skins() {
340 - Plugin::$instance->modules_manager->get_modules( 'dev-tools' )->deprecation->deprecated_function( __METHOD__, '3.1.0', 'register_skins()' );
310 + Plugin::$instance->modules_manager->get_modules( 'dev-tools' )->deprecation->deprecated_function( __METHOD__, '3.1.0', __CLASS__ . '::register_skins()' );
341 311
342 312 $this->register_skins();
343 313 }
344 314
@@ -379,23 +349,10 @@
379 349 'keywords' => $this->get_keywords(),
380 350 'categories' => $this->get_categories(),
381 351 'html_wrapper_class' => $this->get_html_wrapper_class(),
382 352 'show_in_panel' => $this->show_in_panel(),
383 - 'hide_on_search' => $this->hide_on_search(),
384 - 'upsale_data' => null,
385 - 'is_dynamic_content' => $this->is_dynamic_content(),
386 - 'has_widget_inner_wrapper' => $this->has_widget_inner_wrapper(),
387 353 ];
388 354
389 - if ( isset( $config['upsale_data'] ) && is_array( $config['upsale_data'] ) ) {
390 - $filter_name = 'elementor/widgets/' . $this->get_name() . '/custom_promotion';
391 - $config['upsale_data'] = Filtered_Promotions_Manager::get_filtered_promotion_data( $config['upsale_data'], $filter_name, 'upgrade_url' );
392 - }
393 -
394 - if ( isset( $config['upsale_data']['image'] ) ) {
395 - $config['upsale_data']['image'] = esc_url( $config['upsale_data']['image'] );
396 - }
397 -
398 355 $stack = Plugin::$instance->controls_manager->get_element_stack( $this );
399 356
400 357 if ( $stack ) {
401 358 $config['controls'] = $this->get_stack( false )['controls'];
@@ -424,15 +381,15 @@
424 381 *
425 382 * @param string $template_content Template content.
426 383 */
427 384 protected function print_template_content( $template_content ) {
428 - if ( $this->has_widget_inner_wrapper() ) : ?>
385 + ?>
429 386 <div class="elementor-widget-container">
430 - <?php endif;
431 - Utils::print_unescaped_internal_string( $template_content );
432 - if ( $this->has_widget_inner_wrapper() ) : ?>
387 + <?php
388 + echo $template_content; // XSS ok.
389 + ?>
433 390 </div>
434 - <?php endif;
391 + <?php
435 392 }
436 393
437 394 /**
438 395 * Parse text editor.
@@ -542,17 +499,18 @@
542 499 *
543 500 * Used to add Light-Box-related data attributes to links that open media files.
544 501 *
545 502 * @param array|string $element The link HTML element.
546 - * @param int $id The ID of the image.
547 - * @param string $lightbox_setting_key The setting key that dictates whether to open the image in a lightbox.
548 - * @param string $group_id Unique ID for a group of lightbox images.
549 - * @param bool $overwrite Optional. Whether to overwrite existing
550 - * attribute. Default is false, not to overwrite.
503 + * @param int $id The ID of the image
504 + * @param string $lightbox_setting_key The setting key that dictates weather to open the image in a lightbox
505 + * @param string $group_id Unique ID for a group of lightbox images
506 + * @param bool $overwrite Optional. Whether to overwrite existing
507 + * attribute. Default is false, not to overwrite.
551 508 *
552 509 * @return Widget_Base Current instance of the widget.
553 510 * @since 2.9.0
554 511 * @access public
512 + *
555 513 */
556 514 public function add_lightbox_data_attributes( $element, $id = null, $lightbox_setting_key = null, $group_id = null, $overwrite = false ) {
557 515 $kit = Plugin::$instance->kits_manager->get_active_kit();
558 516
@@ -571,19 +529,10 @@
571 529 }
572 530
573 531 $attributes['data-elementor-open-lightbox'] = 'yes';
574 532
575 - $action_hash_params = [];
576 -
577 - if ( $id ) {
578 - $action_hash_params['id'] = $id;
579 - $action_hash_params['url'] = wp_get_attachment_url( $id );
580 - }
581 -
582 533 if ( $group_id ) {
583 534 $attributes['data-elementor-lightbox-slideshow'] = $group_id;
584 -
585 - $action_hash_params['slideshow'] = $group_id;
586 535 }
587 536
588 537 if ( $id ) {
589 538 $lightbox_image_attributes = Plugin::$instance->images_manager->get_lightbox_image_attributes( $id );
@@ -596,10 +545,8 @@
596 545 $attributes['data-elementor-lightbox-description'] = $lightbox_image_attributes['description'];
597 546 }
598 547 }
599 548
600 - $attributes['data-e-action-hash'] = Plugin::instance()->frontend->create_action_hash( 'lightbox', $action_hash_params );
601 -
602 549 $this->add_render_attribute( $element, $attributes, null, $overwrite );
603 550
604 551 return $this;
605 552 }
@@ -624,9 +571,9 @@
624 571 * @since 1.0.0
625 572 *
626 573 * @param Widget_Base $this The current widget.
627 574 */
628 - do_action( 'elementor/widget/before_render_content', $this, [ 'mode' => Widget_Content_Render_Mode::NORMAL ] );
575 + do_action( 'elementor/widget/before_render_content', $this );
629 576
630 577 ob_start();
631 578
632 579 $skin = $this->get_current_skin();
@@ -641,16 +588,19 @@
641 588
642 589 if ( empty( $widget_content ) ) {
643 590 return;
644 591 }
645 - if ( $this->has_widget_inner_wrapper() ) : ?>
592 + ?>
646 593 <div class="elementor-widget-container">
647 - <?php endif; ?>
648 594 <?php
649 595 if ( $this->is_widget_first_render( $this->get_group_name() ) ) {
650 596 $this->register_runtime_widget( $this->get_group_name() );
651 597 }
652 598
599 + $this->print_widget_css();
600 +
601 + // get_name
602 +
653 603 /**
654 604 * Render widget content.
655 605 *
656 606 * Filters the widget content before it's rendered.
@@ -659,14 +609,14 @@
659 609 *
660 610 * @param string $widget_content The content of the widget.
661 611 * @param Widget_Base $this The widget.
662 612 */
663 - $widget_content = apply_filters( 'elementor/widget/render_content', $widget_content, $this, [ 'mode' => Widget_Content_Render_Mode::NORMAL ] );
664 - Utils::print_unescaped_internal_string( $widget_content );
613 + $widget_content = apply_filters( 'elementor/widget/render_content', $widget_content, $this );
614 +
615 + echo $widget_content; // XSS ok.
665 616 ?>
666 - <?php if ( $this->has_widget_inner_wrapper() ) : ?>
667 617 </div>
668 - <?php endif;
618 + <?php
669 619 }
670 620
671 621 protected function is_widget_first_render( $widget_name ) {
672 622 return ! in_array( $widget_name, self::$registered_runtime_widgets, true );
@@ -697,43 +647,8 @@
697 647 public function render_plain_content() {
698 648 $this->render_content();
699 649 }
700 650
701 - public function render_markdown(): string {
702 - $content = $this->get_render_content_for_markdown();
703 -
704 - if ( '' === $content ) {
705 - return '';
706 - }
707 -
708 - return \Elementor\Modules\MarkdownRender\Html_To_Markdown::convert( $content );
709 - }
710 -
711 - protected function get_render_content_for_markdown(): string {
712 - $render_args = [ 'mode' => Widget_Content_Render_Mode::MARKDOWN ];
713 -
714 - do_action( 'elementor/widget/before_render_content', $this, $render_args );
715 -
716 - ob_start();
717 -
718 - $skin = $this->get_current_skin();
719 -
720 - if ( $skin ) {
721 - $skin->set_parent( $this );
722 - $skin->render_by_mode();
723 - } else {
724 - $this->render_by_mode();
725 - }
726 -
727 - $widget_content = ob_get_clean();
728 -
729 - if ( '' === $widget_content ) {
730 - return '';
731 - }
732 -
733 - return apply_filters( 'elementor/widget/render_content', $widget_content, $this, $render_args );
734 - }
735 -
736 651 /**
737 652 * Before widget rendering.
738 653 *
739 654 * Used to add stuff before the widget `_wrapper` element.
@@ -815,10 +730,10 @@
815 730 *
816 731 * Script tags are allowed on frontend according to the WP theme securing policy.
817 732 *
818 733 * @param string $setting
819 - * @param null $repeater_name
820 - * @param null $index
734 + * @param null $repeater_name
735 + * @param null $index
821 736 */
822 737 final public function print_unescaped_setting( $setting, $repeater_name = null, $index = null ) {
823 738 if ( $repeater_name ) {
824 739 $repeater = $this->get_settings_for_display( $repeater_name );
@@ -883,9 +798,9 @@
883 798 * @access protected
884 799 *
885 800 * @param string $setting_key The current setting key inside the repeater item (e.g. `tab_title`).
886 801 * @param string $repeater_key The repeater key containing the array of all the items in the repeater (e.g. `tabs`).
887 - * @param int $repeater_item_index The current item index in the repeater array (e.g. `3`).
802 + * @param int $repeater_item_index The current item index in the repeater array (e.g. `3`).
888 803 *
889 804 * @return string The repeater setting key (e.g. `tabs.3.tab_title`).
890 805 */
891 806 protected function get_repeater_setting_key( $setting_key, $repeater_key, $repeater_item_index ) {
@@ -1042,13 +957,27 @@
1042 957 return $this->get_name();
1043 958 }
1044 959
1045 960 /**
1046 - * @param string $plugin_title Plugin's title.
1047 - * @param string $since Plugin version widget was deprecated.
1048 - * @param string $last Plugin version in which the widget will be removed.
1049 - * @param string $replacement Widget replacement.
961 + * Get Inline CSS dependencies.
962 + *
963 + * Retrieve a list of inline CSS dependencies that the element requires.
964 + *
965 + * @since 3.3.0
966 + * @access public
967 + *
968 + * @return array.
1050 969 */
970 + public function get_inline_css_depends() {
971 + return [];
972 + }
973 +
974 + /**
975 + * @param string $plugin_title Plugin's title
976 + * @param string $since Plugin version widget was deprecated
977 + * @param string $last Plugin version in which the widget will be removed
978 + * @param string $replacement Widget replacement
979 + */
1051 980 protected function deprecated_notice( $plugin_title, $since, $last = '', $replacement = '' ) {
1052 981 $this->start_controls_section(
1053 982 'Deprecated',
1054 983 [
@@ -1068,52 +997,167 @@
1068 997 ]
1069 998 );
1070 999
1071 1000 $this->end_controls_section();
1001 +
1072 1002 }
1073 1003
1004 + public function register_runtime_widget( $widget_name ) {
1005 + self::$registered_runtime_widgets[] = $widget_name;
1006 + }
1007 +
1008 + public function get_widget_css_config( $widget_name ) {
1009 + $direction = is_rtl() ? '-rtl' : '';
1010 +
1011 + $has_custom_breakpoints = $this->is_custom_breakpoints_widget();
1012 +
1013 + $file_name = 'widget-' . $widget_name . $direction . '.min.css';
1014 +
1015 + // The URL of the widget's external CSS file that is loaded in case that the CSS content is too large to be printed inline.
1016 + $file_url = Plugin::$instance->frontend->get_frontend_file_url( $file_name, $has_custom_breakpoints );
1017 +
1018 + // The local path of the widget's CSS file that is being read and saved in the DB when the CSS content should be printed inline.
1019 + $file_path = Plugin::$instance->frontend->get_frontend_file_path( $file_name, $has_custom_breakpoints );
1020 +
1021 + return [
1022 + 'key' => $widget_name,
1023 + 'version' => ELEMENTOR_VERSION,
1024 + 'file_path' => $file_path,
1025 + 'data' => [
1026 + 'file_url' => $file_url,
1027 + ],
1028 + ];
1029 + }
1030 +
1031 + public function get_css_config() {
1032 + return $this->get_widget_css_config( $this->get_group_name() );
1033 + }
1034 +
1035 + public function get_responsive_widgets_config() {
1036 + $responsive_widgets_data_manager = $this->get_responsive_widgets_data_manager();
1037 +
1038 + return [
1039 + 'key' => $responsive_widgets_data_manager::RESPONSIVE_WIDGETS_DATABASE_KEY,
1040 + 'version' => ELEMENTOR_VERSION,
1041 + 'file_path' => ELEMENTOR_ASSETS_PATH . $responsive_widgets_data_manager::RESPONSIVE_WIDGETS_FILE_PATH,
1042 + ];
1043 + }
1044 +
1045 + public function get_responsive_widgets() {
1046 + $responsive_widgets_data_manager = $this->get_responsive_widgets_data_manager();
1047 +
1048 + $config = $this->get_responsive_widgets_config();
1049 +
1050 + return $responsive_widgets_data_manager->get_asset_data_from_config( $config );
1051 + }
1052 +
1074 1053 /**
1075 - * Init controls.
1054 + * Get Responsive Widgets Data Manager.
1076 1055 *
1077 - * Reset the `is_first_section` flag to true, so when the Stacks are cleared
1078 - * all the controls will be registered again with their skins and settings.
1056 + * Retrieve the data manager that handles widgets that are using media queries for custom-breakpoints values.
1079 1057 *
1080 - * @since 3.14.0
1058 + * @since 3.5.0
1081 1059 * @access protected
1060 + *
1061 + * @return Responsive_Widgets_Data_Manager
1082 1062 */
1083 - protected function init_controls() {
1084 - $this->is_first_section = true;
1085 - parent::init_controls();
1086 - }
1063 + protected function get_responsive_widgets_data_manager() {
1064 + if ( ! self::$responsive_widgets_data_manager ) {
1065 + self::$responsive_widgets_data_manager = new Responsive_Widgets_Data_Manager();
1066 + }
1087 1067
1088 - public function register_runtime_widget( $widget_name ) {
1089 - self::$registered_runtime_widgets[] = $widget_name;
1068 + return self::$responsive_widgets_data_manager;
1090 1069 }
1091 1070
1092 1071 /**
1093 - * Mark widget as deprecated.
1072 + * Is Custom Breakpoints Widget.
1094 1073 *
1095 - * Use `get_deprecation_message()` method to print the message control at specific location in register_controls().
1074 + * Checking if there are active custom-breakpoints and if the widget use them.
1096 1075 *
1097 - * @param string $version The version of Elementor that deprecated the widget.
1098 - * @param string $message A message regarding the deprecation.
1099 - * @param string $replacement The widget that should be used instead.
1076 + * @since 3.5.0
1077 + * @access protected
1078 + *
1079 + * @return boolean
1100 1080 */
1101 - protected function add_deprecation_message( $version, $message, $replacement ) {
1102 - // Expose the config for handling in JS.
1103 - $this->set_config( 'deprecation', [
1104 - 'version' => $version,
1105 - 'message' => $message,
1106 - 'replacement' => $replacement,
1107 - ] );
1081 + protected function is_custom_breakpoints_widget() {
1082 + $has_custom_breakpoints = Plugin::$instance->breakpoints->has_custom_breakpoints();
1108 1083
1109 - $this->add_control(
1110 - 'deprecation_message',
1111 - [
1112 - 'type' => Controls_Manager::ALERT,
1113 - 'alert_type' => 'info',
1114 - 'content' => $message,
1115 - 'separator' => 'after',
1116 - ]
1117 - );
1084 + if ( $has_custom_breakpoints ) {
1085 + $responsive_widgets = $this->get_responsive_widgets();
1086 +
1087 + // The $widget_name can also represents a widgets group name, therefore we need to use the current widget name to check if it's responsive widget.
1088 + $current_widget_name = $this->get_name();
1089 +
1090 + // If the widget is not implementing custom-breakpoints media queries then it has no custom- css file.
1091 + if ( ! isset( $responsive_widgets[ $current_widget_name ] ) ) {
1092 + $has_custom_breakpoints = false;
1093 + }
1094 + }
1095 +
1096 + return $has_custom_breakpoints;
1097 + }
1098 +
1099 + private function get_widget_css() {
1100 + $widgets_css_data_manager = $this->get_widgets_css_data_manager();
1101 +
1102 + $widgets_list = $this->get_inline_css_depends();
1103 +
1104 + $widgets_list[] = $this->get_group_name();
1105 +
1106 + $widget_css = '';
1107 +
1108 + foreach ( $widgets_list as $widget_data ) {
1109 + $widget_name = isset( $widget_data['name'] ) ? $widget_data['name'] : $widget_data;
1110 +
1111 + if ( ! in_array( $widget_name, self::$registered_inline_css_widgets, true ) ) {
1112 + if ( $this->get_group_name() === $widget_name ) {
1113 + $config = $this->get_css_config();
1114 + } else {
1115 + /**
1116 + * The core-dependency allowing to create a dependency specifically with the core widgets.
1117 + * Otherwise, the config will be taken from the class that inherits from Widget_Base.
1118 + */
1119 + $is_core_dependency = isset( $widget_data['is_core_dependency'] ) ? true : false;
1120 +
1121 + $config = $is_core_dependency ? self::get_widget_css_config( $widget_name ) : $this->get_widget_css_config( $widget_name );
1122 + }
1123 +
1124 + $widget_css .= $widgets_css_data_manager->get_asset_data_from_config( $config );
1125 +
1126 + self::$registered_inline_css_widgets[] = $widget_name;
1127 + }
1128 + }
1129 +
1130 + return $widget_css;
1131 +
1132 + }
1133 +
1134 + private function is_inline_css_mode() {
1135 + static $is_active;
1136 +
1137 + if ( null === $is_active ) {
1138 + $is_edit_mode = Plugin::$instance->editor->is_edit_mode();
1139 + $is_preview_mode = Plugin::$instance->preview->is_preview_mode();
1140 + $is_optimized_mode = Plugin::$instance->experiments->is_feature_active( 'e_optimized_css_loading' );
1141 +
1142 + $is_active = ( Utils::is_script_debug() || $is_edit_mode || $is_preview_mode || ! $is_optimized_mode ) ? false : true;
1143 + }
1144 +
1145 + return $is_active;
1146 + }
1147 +
1148 + private function print_widget_css() {
1149 + if ( ! $this->is_inline_css_mode() ) {
1150 + return;
1151 + }
1152 +
1153 + Utils::print_unescaped_internal_string( $this->get_widget_css() );
1154 + }
1155 +
1156 + private function get_widgets_css_data_manager() {
1157 + if ( ! self::$widgets_css_data_manager ) {
1158 + self::$widgets_css_data_manager = new Widgets_Css_Data_Manager();
1159 + }
1160 +
1161 + return self::$widgets_css_data_manager;
1118 1162 }
1119 1163 }