PluginProbe
Elementor Website Builder – more than just a page builder / 3.10.0-dev1
Elementor Website Builder – more than just a page builder v3.10.0-dev1
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 / elements / container.php

container.php in Elementor Website Builder – more than just a page builder 3.10.0-dev1, at includes/elements/container.php

1,638 lines 38.9 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 namespace Elementor\Includes\Elements;
3
4 use Elementor\Controls_Manager;
5 use Elementor\Core\Breakpoints\Manager as Breakpoints_Manager;
6 use Elementor\Element_Base;
7 use Elementor\Embed;
8 use Elementor\Group_Control_Background;
9 use Elementor\Group_Control_Border;
10 use Elementor\Group_Control_Box_Shadow;
11 use Elementor\Group_Control_Css_Filter;
12 use Elementor\Group_Control_Flex_Container;
13 use Elementor\Group_Control_Flex_Item;
14 use Elementor\Plugin;
15 use Elementor\Shapes;
16 use Elementor\Utils;
17
18 if ( ! defined( 'ABSPATH' ) ) {
19 exit; // Exit if accessed directly.
20 }
21
22 class Container extends Element_Base {
23
24 /**
25 * @var \Elementor\Core\Kits\Documents\Kit
26 */
27 private $active_kit;
28
29 /**
30 * Container constructor.
31 *
32 * @param array $data
33 * @param array|null $args
34 *
35 * @return void
36 */
37 public function __construct( array $data = [], array $args = null ) {
38 parent::__construct( $data, $args );
39
40 $this->active_kit = Plugin::$instance->kits_manager->get_active_kit();
41 }
42
43 /**
44 * Get the element type.
45 *
46 * @return string
47 */
48 public static function get_type() {
49 return 'container';
50 }
51
52 /**
53 * Get the element name.
54 *
55 * @return string
56 */
57 public function get_name() {
58 return 'container';
59 }
60
61 /**
62 * Get the element display name.
63 *
64 * @return string
65 */
66 public function get_title() {
67 return esc_html__( 'Container', 'elementor' );
68 }
69
70 /**
71 * Get the element display icon.
72 *
73 * @return string
74 */
75 public function get_icon() {
76 return 'eicon-container';
77 }
78
79 /**
80 * Override the render attributes to add a custom wrapper class.
81 *
82 * @return void
83 */
84 protected function add_render_attributes() {
85 parent::add_render_attributes();
86
87 $this->add_render_attribute( '_wrapper', [
88 'class' => [
89 'e-con',
90 ],
91 ] );
92 }
93
94 /**
95 * Override the initial element config to display the Container in the panel.
96 *
97 * @return array
98 */
99 protected function get_initial_config() {
100 $config = parent::get_initial_config();
101
102 $config['controls'] = $this->get_controls();
103 $config['tabs_controls'] = $this->get_tabs_controls();
104 $config['show_in_panel'] = true;
105 $config['categories'] = [ 'layout' ];
106
107 return $config;
108 }
109
110 /**
111 * Render the element JS template.
112 *
113 * @return void
114 */
115 protected function content_template() {
116 ?>
117 <# if ( 'boxed' === settings.content_width ) { #>
118 <div class="e-con-inner">
119 <#
120 }
121 if ( settings.background_video_link ) {
122 let videoAttributes = 'autoplay muted playsinline';
123
124 if ( ! settings.background_play_once ) {
125 videoAttributes += ' loop';
126 }
127
128 view.addRenderAttribute( 'background-video-container', 'class', 'elementor-background-video-container' );
129
130 if ( ! settings.background_play_on_mobile ) {
131 view.addRenderAttribute( 'background-video-container', 'class', 'elementor-hidden-phone' );
132 }
133 #>
134 <div {{{ view.getRenderAttributeString( 'background-video-container' ) }}}>
135 <div class="elementor-background-video-embed"></div>
136 <video class="elementor-background-video-hosted elementor-html5-video" {{ videoAttributes }}></video>
137 </div>
138 <# } #>
139 <div class="elementor-shape elementor-shape-top"></div>
140 <div class="elementor-shape elementor-shape-bottom"></div>
141 <# if ( 'boxed' === settings.content_width ) { #>
142 </div>
143 <# } #>
144 <?php
145 }
146
147 /**
148 * Render the video background markup.
149 *
150 * @return void
151 */
152 private function render_video_background() {
153 $settings = $this->get_settings_for_display();
154
155 if ( 'video' !== $settings['background_background'] ) {
156 return;
157 }
158
159 if ( ! $settings['background_video_link'] ) {
160 return;
161 }
162
163 $video_properties = Embed::get_video_properties( $settings['background_video_link'] );
164
165 $this->add_render_attribute( 'background-video-container', 'class', 'elementor-background-video-container' );
166
167 if ( ! $settings['background_play_on_mobile'] ) {
168 $this->add_render_attribute( 'background-video-container', 'class', 'elementor-hidden-phone' );
169 }
170
171 ?><div <?php $this->print_render_attribute_string( 'background-video-container' ); ?>>
172 <?php if ( $video_properties ) : ?>
173 <div class="elementor-background-video-embed"></div>
174 <?php
175 else :
176 $video_tag_attributes = 'autoplay muted playsinline';
177
178 if ( 'yes' !== $settings['background_play_once'] ) {
179 $video_tag_attributes .= ' loop';
180 }
181 ?>
182 <video class="elementor-background-video-hosted elementor-html5-video" <?php echo esc_attr( $video_tag_attributes ); ?>></video>
183 <?php endif; ?>
184 </div><?php
185 }
186
187 /**
188 * Render the Container's shape divider.
189 * TODO: Copied from `section.php`.
190 *
191 * Used to generate the shape dividers HTML.
192 *
193 * @param string $side - Shape divider side, used to set the shape key.
194 *
195 * @return void
196 */
197 private function render_shape_divider( $side ) {
198 $settings = $this->get_active_settings();
199 $base_setting_key = "shape_divider_$side";
200 $negative = ! empty( $settings[ $base_setting_key . '_negative' ] );
201 $shape_path = Shapes::get_shape_path( $settings[ $base_setting_key ], $negative );
202
203 if ( ! is_file( $shape_path ) || ! is_readable( $shape_path ) ) {
204 return;
205 }
206 ?>
207 <div class="elementor-shape elementor-shape-<?php echo esc_attr( $side ); ?>" data-negative="<?php
208 Utils::print_unescaped_internal_string( $negative ? 'true' : 'false' );
209 ?>">
210 <?php
211 // PHPCS - The file content is being read from a strict file path structure.
212 echo Utils::file_get_contents( $shape_path ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
213 ?>
214 </div>
215 <?php
216 }
217
218 /**
219 * Print safe HTML tag for the element based on the element settings.
220 *
221 * @return void
222 */
223 private function print_html_tag() {
224 $html_tag = $this->get_settings( 'html_tag' );
225
226 if ( empty( $html_tag ) ) {
227 $html_tag = 'div';
228 }
229
230 Utils::print_validated_html_tag( $html_tag );
231 }
232
233 /**
234 * Before rendering the container content. (Print the opening tag, etc.)
235 *
236 * @return void
237 */
238 public function before_render() {
239 $settings = $this->get_settings_for_display();
240 $link = $settings['link'];
241
242 if ( ! empty( $link['url'] ) ) {
243 $this->add_link_attributes( '_wrapper', $link );
244 }
245
246 ?><<?php $this->print_html_tag(); ?> <?php $this->print_render_attribute_string( '_wrapper' ); ?>>
247 <?php
248 if ( $this->is_boxed_container( $settings ) ) { ?>
249 <div class="e-con-inner">
250 <?php }
251
252 $this->render_video_background();
253
254 if ( ! empty( $settings['shape_divider_top'] ) ) {
255 $this->render_shape_divider( 'top' );
256 }
257
258 if ( ! empty( $settings['shape_divider_bottom'] ) ) {
259 $this->render_shape_divider( 'bottom' );
260 }
261 }
262
263 /**
264 * After rendering the Container content. (Print the closing tag, etc.)
265 *
266 * @return void
267 */
268 public function after_render() {
269 $settings = $this->get_settings_for_display();
270 if ( $this->is_boxed_container( $settings ) ) { ?>
271 </div>
272 <?php } ?>
273 </<?php $this->print_html_tag(); ?>>
274 <?php
275 }
276
277 private function is_boxed_container( array $settings ) {
278 return ! empty( $settings['content_width'] ) && 'boxed' === $settings['content_width'];
279 }
280
281 /**
282 * Override the default child type to allow widgets & containers as children.
283 *
284 * @param array $element_data
285 *
286 * @return \Elementor\Element_Base|\Elementor\Widget_Base|null
287 */
288 protected function _get_default_child_type( array $element_data ) {
289 if ( 'container' === $element_data['elType'] ) {
290 return Plugin::$instance->elements_manager->get_element_types( 'container' );
291 }
292
293 return Plugin::$instance->widgets_manager->get_widget_types( $element_data['widgetType'] );
294 }
295
296 /**
297 * Register the Container's layout controls.
298 *
299 * @return void
300 */
301 protected function register_container_layout_controls() {
302 $this->start_controls_section(
303 'section_layout_container',
304 [
305 'label' => esc_html__( 'Container', 'elementor' ),
306 'tab' => Controls_Manager::TAB_LAYOUT,
307 ]
308 );
309
310 $active_breakpoints = Plugin::$instance->breakpoints->get_active_breakpoints();
311
312 if ( array_key_exists( Breakpoints_Manager::BREAKPOINT_KEY_MOBILE_EXTRA, $active_breakpoints ) ) {
313 $min_affected_device = Breakpoints_Manager::BREAKPOINT_KEY_MOBILE_EXTRA;
314 } else {
315 $min_affected_device = Breakpoints_Manager::BREAKPOINT_KEY_TABLET;
316 }
317
318 $this->add_control(
319 'content_width',
320 [
321 'label' => esc_html__( 'Content Width', 'elementor' ),
322 'type' => Controls_Manager::SELECT,
323 'default' => 'boxed',
324 'options' => [
325 'boxed' => esc_html__( 'Boxed', 'elementor' ),
326 'full' => esc_html__( 'Full Width', 'elementor' ),
327 ],
328 'render_type' => 'template',
329 'prefix_class' => 'e-con-',
330 'frontend_available' => true,
331 ]
332 );
333
334 $width_control_settings = [
335 'label' => esc_html__( 'Width', 'elementor' ),
336 'type' => Controls_Manager::SLIDER,
337 'size_units' => [ 'px', '%', 'vw' ],
338 'range' => [
339 'px' => [
340 'min' => 500,
341 'max' => 1600,
342 ],
343 '%' => [
344 'min' => 0,
345 'max' => 100,
346 ],
347 'vw' => [
348 'min' => 0,
349 'max' => 100,
350 ],
351 ],
352 'default' => [
353 'unit' => '%',
354 ],
355 'min_affected_device' => [
356 Breakpoints_Manager::BREAKPOINT_KEY_DESKTOP => $min_affected_device,
357 Breakpoints_Manager::BREAKPOINT_KEY_LAPTOP => $min_affected_device,
358 Breakpoints_Manager::BREAKPOINT_KEY_TABLET_EXTRA => $min_affected_device,
359 Breakpoints_Manager::BREAKPOINT_KEY_TABLET => $min_affected_device,
360 Breakpoints_Manager::BREAKPOINT_KEY_MOBILE_EXTRA => $min_affected_device,
361 ],
362 'separator' => 'none',
363 ];
364
365 $this->add_responsive_control(
366 'width',
367 array_merge( $width_control_settings, [
368 'selectors' => [
369 '{{WRAPPER}}' => '--width: {{SIZE}}{{UNIT}};',
370 ],
371 'condition' => [
372 'content_width' => 'full',
373 ],
374 'device_args' => [
375 Breakpoints_Manager::BREAKPOINT_KEY_DESKTOP => [
376 'placeholder' => [
377 'size' => 100,
378 'unit' => '%',
379 ],
380 ],
381 Breakpoints_Manager::BREAKPOINT_KEY_MOBILE => [
382 // The mobile width is not inherited from the higher breakpoint width controls.
383 'placeholder' => [
384 'size' => 100,
385 'unit' => '%',
386 ],
387 ],
388 ],
389 ] )
390 );
391
392 $this->add_responsive_control(
393 'boxed_width',
394 array_merge( $width_control_settings, [
395 'selectors' => [
396 '{{WRAPPER}}' => '--content-width: {{SIZE}}{{UNIT}};',
397 ],
398 'condition' => [
399 'content_width' => 'boxed',
400 ],
401 'default' => [
402 'unit' => 'px',
403 ],
404 'device_args' => [
405 Breakpoints_Manager::BREAKPOINT_KEY_DESKTOP => [
406 // Use the default width from the kit as a placeholder.
407 'placeholder' => $this->active_kit->get_settings_for_display( 'container_width' ),
408 ],
409 Breakpoints_Manager::BREAKPOINT_KEY_MOBILE => [
410 // The mobile width is not inherited from the higher breakpoint width controls.
411 'placeholder' => [
412 'size' => 100,
413 'unit' => '%',
414 ],
415 ],
416 ],
417 ] )
418 );
419
420 $this->add_responsive_control(
421 'min_height',
422 [
423 'label' => esc_html__( 'Min Height', 'elementor' ),
424 'type' => Controls_Manager::SLIDER,
425 'size_units' => [ 'px', 'vh' ],
426 'range' => [
427 'px' => [
428 'min' => 0,
429 'max' => 1440,
430 ],
431 'vh' => [
432 'min' => 0,
433 'max' => 100,
434 ],
435 ],
436 'description' => sprintf(
437 esc_html__( 'To achieve full height Container use %s.', 'elementor' ),
438 '100vh'
439 ),
440 'selectors' => [
441 '{{WRAPPER}}' => '--min-height: {{SIZE}}{{UNIT}};',
442 ],
443 ]
444 );
445
446 $this->add_group_control(
447 Group_Control_Flex_Container::get_type(),
448 [
449 'name' => 'flex',
450 'selector' => '{{WRAPPER}}',
451 'fields_options' => [
452 'gap' => [
453 'label' => esc_html_x( 'Gap between elements', 'Flex Container Control', 'elementor' ),
454 'device_args' => [
455 Breakpoints_Manager::BREAKPOINT_KEY_DESKTOP => [
456 // Use the default gap from the kit as a placeholder.
457 'placeholder' => $this->active_kit->get_settings_for_display( 'space_between_widgets' ),
458 ],
459 ],
460 ],
461 ],
462 ]
463 );
464
465 $this->end_controls_section();
466 }
467
468 /**
469 * Register the Container's items layout controls.
470 *
471 * @return void
472 */
473 protected function register_items_layout_controls() {
474 $this->start_controls_section(
475 'section_layout_additional_options',
476 [
477 'label' => esc_html__( 'Additional Options', 'elementor' ),
478 'tab' => Controls_Manager::TAB_LAYOUT,
479 ]
480 );
481
482 $this->add_control(
483 'overflow',
484 [
485 'label' => esc_html__( 'Overflow', 'elementor' ),
486 'type' => Controls_Manager::SELECT,
487 'default' => '',
488 'options' => [
489 '' => esc_html__( 'Default', 'elementor' ),
490 'hidden' => esc_html__( 'Hidden', 'elementor' ),
491 'auto' => esc_html__( 'Auto', 'elementor' ),
492 ],
493 'selectors' => [
494 '{{WRAPPER}}' => '--overflow: {{VALUE}}',
495 ],
496 ]
497 );
498
499 $possible_tags = [
500 'div' => 'div',
501 'header' => 'header',
502 'footer' => 'footer',
503 'main' => 'main',
504 'article' => 'article',
505 'section' => 'section',
506 'aside' => 'aside',
507 'nav' => 'nav',
508 'a' => 'a ' . esc_html__( '(link)', 'elementor' ),
509 ];
510
511 $options = [
512 '' => esc_html__( 'Default', 'elementor' ),
513 ] + $possible_tags;
514
515 $this->add_control(
516 'html_tag',
517 [
518 'label' => esc_html__( 'HTML Tag', 'elementor' ),
519 'type' => Controls_Manager::SELECT,
520 'options' => $options,
521 ]
522 );
523
524 $this->add_control(
525 'link_note',
526 [
527 'type' => Controls_Manager::RAW_HTML,
528 'content_classes' => 'elementor-panel-alert elementor-panel-alert-warning',
529 'raw' => esc_html__( 'Don’t add links to elements nested in this container - it will break the layout.', 'elementor' ),
530 'condition' => [
531 'html_tag' => 'a',
532 ],
533 ]
534 );
535
536 $this->add_control(
537 'link',
538 [
539 'label' => esc_html__( 'Link', 'elementor' ),
540 'type' => Controls_Manager::URL,
541 'dynamic' => [
542 'active' => true,
543 ],
544 'placeholder' => esc_html__( 'https://your-link.com', 'elementor' ),
545 'condition' => [
546 'html_tag' => 'a',
547 ],
548 ]
549 );
550
551 $this->end_controls_section();
552 }
553
554 /**
555 * Register the Container's layout tab.
556 *
557 * @return void
558 */
559 protected function register_layout_tab() {
560 $this->register_container_layout_controls();
561
562 $this->register_items_layout_controls();
563 }
564
565 /**
566 * Register the Container's background controls.
567 *
568 * @return void
569 */
570 protected function register_background_controls() {
571 $this->start_controls_section(
572 'section_background',
573 [
574 'label' => esc_html__( 'Background', 'elementor' ),
575 'tab' => Controls_Manager::TAB_STYLE,
576 ]
577 );
578
579 $this->start_controls_tabs( 'tabs_background' );
580
581 /**
582 * Normal.
583 */
584 $this->start_controls_tab(
585 'tab_background_normal',
586 [
587 'label' => esc_html__( 'Normal', 'elementor' ),
588 ]
589 );
590
591 $this->add_group_control(
592 Group_Control_Background::get_type(),
593 [
594 'name' => 'background',
595 'types' => [ 'classic', 'gradient', 'video', 'slideshow' ],
596 'fields_options' => [
597 'background' => [
598 'frontend_available' => true,
599 ],
600 'image' => [
601 'background_lazyload' => [
602 'active' => true,
603 'keys' => [ 'background_image', 'url' ],
604 ],
605 ],
606 ],
607 ]
608 );
609
610 $this->end_controls_tab();
611
612 /**
613 * Hover.
614 */
615 $this->start_controls_tab(
616 'tab_background_hover',
617 [
618 'label' => esc_html__( 'Hover', 'elementor' ),
619 ]
620 );
621
622 $this->add_group_control(
623 Group_Control_Background::get_type(),
624 [
625 'name' => 'background_hover',
626 'selector' => '{{WRAPPER}}:hover',
627 ]
628 );
629
630 $this->add_control(
631 'background_hover_transition',
632 [
633 'label' => esc_html__( 'Transition Duration', 'elementor' ),
634 'type' => Controls_Manager::SLIDER,
635 'size_units' => [ 's', 'ms' ],
636 'default' => [
637 'unit' => 's',
638 'size' => 0.3,
639 ],
640 'render_type' => 'ui',
641 'separator' => 'before',
642 ]
643 );
644
645 $this->end_controls_tab();
646
647 $this->end_controls_tabs();
648
649 $this->end_controls_section();
650 }
651
652 /**
653 * Register the Container's background overlay controls.
654 *
655 * @return void
656 */
657 protected function register_background_overlay_controls() {
658 $this->start_controls_section(
659 'section_background_overlay',
660 [
661 'label' => esc_html__( 'Background Overlay', 'elementor' ),
662 'tab' => Controls_Manager::TAB_STYLE,
663 ]
664 );
665
666 $this->start_controls_tabs( 'tabs_background_overlay' );
667
668 /**
669 * Normal.
670 */
671 $this->start_controls_tab(
672 'tab_background_overlay',
673 [
674 'label' => esc_html__( 'Normal', 'elementor' ),
675 ]
676 );
677
678 $background_overlay_selector = '{{WRAPPER}}::before, {{WRAPPER}} > .elementor-background-video-container::before, {{WRAPPER}} > .e-con-inner > .elementor-background-video-container::before, {{WRAPPER}} > .elementor-background-slideshow::before, {{WRAPPER}} > .e-con-inner > .elementor-background-slideshow::before';
679
680 $this->add_group_control(
681 Group_Control_Background::get_type(),
682 [
683 'name' => 'background_overlay',
684 'selector' => $background_overlay_selector,
685 'fields_options' => [
686 'background' => [
687 'selectors' => [
688 // Hack to set the `::before` content in order to render it only when there is a background overlay.
689 $background_overlay_selector => '--background-overlay: \'\';',
690 ],
691 ],
692 ],
693 ]
694 );
695
696 $this->add_responsive_control(
697 'background_overlay_opacity',
698 [
699 'label' => esc_html__( 'Opacity', 'elementor' ),
700 'type' => Controls_Manager::SLIDER,
701 'default' => [
702 'size' => .5,
703 ],
704 'range' => [
705 'px' => [
706 'max' => 1,
707 'step' => 0.01,
708 ],
709 ],
710 'selectors' => [
711 '{{WRAPPER}}' => '--overlay-opacity: {{SIZE}};',
712 ],
713 'condition' => [
714 'background_overlay_background' => [ 'classic', 'gradient' ],
715 ],
716 ]
717 );
718
719 $this->add_group_control(
720 Group_Control_Css_Filter::get_type(),
721 [
722 'name' => 'css_filters',
723 'selector' => '{{WRAPPER}}::before',
724 'conditions' => [
725 'relation' => 'or',
726 'terms' => [
727 [
728 'name' => 'background_overlay_image[url]',
729 'operator' => '!==',
730 'value' => '',
731 ],
732 [
733 'name' => 'background_overlay_color',
734 'operator' => '!==',
735 'value' => '',
736 ],
737 ],
738 ],
739 ]
740 );
741
742 $this->add_control(
743 'overlay_blend_mode',
744 [
745 'label' => esc_html__( 'Blend Mode', 'elementor' ),
746 'type' => Controls_Manager::SELECT,
747 'options' => [
748 '' => esc_html__( 'Normal', 'elementor' ),
749 'multiply' => esc_html__( 'Multiply', 'elementor' ),
750 'screen' => esc_html__( 'Screen', 'elementor' ),
751 'overlay' => esc_html__( 'Overlay', 'elementor' ),
752 'darken' => esc_html__( 'Darken', 'elementor' ),
753 'lighten' => esc_html__( 'Lighten', 'elementor' ),
754 'color-dodge' => esc_html__( 'Color Dodge', 'elementor' ),
755 'saturation' => esc_html__( 'Saturation', 'elementor' ),
756 'color' => esc_html__( 'Color', 'elementor' ),
757 'luminosity' => esc_html__( 'Luminosity', 'elementor' ),
758 ],
759 'selectors' => [
760 '{{WRAPPER}}' => '--overlay-mix-blend-mode: {{VALUE}}',
761 ],
762 'conditions' => [
763 'relation' => 'or',
764 'terms' => [
765 [
766 'name' => 'background_overlay_image[url]',
767 'operator' => '!==',
768 'value' => '',
769 ],
770 [
771 'name' => 'background_overlay_color',
772 'operator' => '!==',
773 'value' => '',
774 ],
775 ],
776 ],
777 ]
778 );
779
780 $this->end_controls_tab();
781
782 /**
783 * Hover.
784 */
785 $this->start_controls_tab(
786 'tab_background_overlay_hover',
787 [
788 'label' => esc_html__( 'Hover', 'elementor' ),
789 ]
790 );
791
792 $background_overlay_hover_selector = '{{WRAPPER}}:hover::before, {{WRAPPER}}:hover > .elementor-background-video-container::before, {{WRAPPER}}:hover > .e-con-inner > .elementor-background-video-container::before, {{WRAPPER}} > .elementor-background-slideshow:hover::before, {{WRAPPER}} > .e-con-inner > .elementor-background-slideshow:hover::before';
793
794 $this->add_group_control(
795 Group_Control_Background::get_type(),
796 [
797 'name' => 'background_overlay_hover',
798 'selector' => $background_overlay_hover_selector,
799 'fields_options' => [
800 'background' => [
801 'selectors' => [
802 // Hack to set the `::before` content in order to render it only when there is a background overlay.
803 $background_overlay_hover_selector => '--background-overlay: \'\';',
804 ],
805 ],
806 ],
807 ]
808 );
809
810 $this->add_responsive_control(
811 'background_overlay_hover_opacity',
812 [
813 'label' => esc_html__( 'Opacity', 'elementor' ),
814 'type' => Controls_Manager::SLIDER,
815 'default' => [
816 'size' => .5,
817 ],
818 'range' => [
819 'px' => [
820 'max' => 1,
821 'step' => 0.01,
822 ],
823 ],
824 'selectors' => [
825 '{{WRAPPER}}:hover' => '--overlay-opacity: {{SIZE}};',
826 ],
827 'condition' => [
828 'background_overlay_hover_background' => [ 'classic', 'gradient' ],
829 ],
830 ]
831 );
832
833 $this->add_group_control(
834 Group_Control_Css_Filter::get_type(),
835 [
836 'name' => 'css_filters_hover',
837 'selector' => '{{WRAPPER}}:hover::before',
838 ]
839 );
840
841 $this->add_control(
842 'background_overlay_hover_transition',
843 [
844 'label' => esc_html__( 'Transition Duration', 'elementor' ),
845 'type' => Controls_Manager::SLIDER,
846 'size_units' => [ 's', 'ms' ],
847 'default' => [
848 'unit' => 's',
849 'size' => 0.3,
850 ],
851 'render_type' => 'ui',
852 'separator' => 'before',
853 'selectors' => [
854 '{{WRAPPER}}' => '--overlay-transition: {{SIZE}}{{UNIT}};',
855 ],
856 ]
857 );
858
859 $this->end_controls_tab();
860
861 $this->end_controls_tabs();
862
863 $this->end_controls_section();
864 }
865
866 /**
867 * Register the Container's border controls.
868 *
869 * @return void
870 */
871 protected function register_border_controls() {
872 $this->start_controls_section(
873 'section_border',
874 [
875 'label' => esc_html__( 'Border', 'elementor' ),
876 'tab' => Controls_Manager::TAB_STYLE,
877 ]
878 );
879
880 $this->start_controls_tabs( 'tabs_border' );
881
882 /**
883 * Normal.
884 */
885 $this->start_controls_tab(
886 'tab_border',
887 [
888 'label' => esc_html__( 'Normal', 'elementor' ),
889 ]
890 );
891
892 $this->add_group_control(
893 Group_Control_Border::get_type(),
894 [
895 'name' => 'border',
896 ]
897 );
898
899 $this->add_responsive_control(
900 'border_radius',
901 [
902 'label' => esc_html__( 'Border Radius', 'elementor' ),
903 'type' => Controls_Manager::DIMENSIONS,
904 'size_units' => [ 'px', '%', 'em' ],
905 'selectors' => [
906 '{{WRAPPER}}' => '--border-radius: {{TOP}}{{UNIT}} {{RIGHT}}{{UNIT}} {{BOTTOM}}{{UNIT}} {{LEFT}}{{UNIT}};',
907 ],
908 ]
909 );
910
911 $this->add_group_control(
912 Group_Control_Box_Shadow::get_type(),
913 [
914 'name' => 'box_shadow',
915 ]
916 );
917
918 $this->end_controls_tab();
919
920 /**
921 * Hover.
922 */
923 $this->start_controls_tab(
924 'tab_border_hover',
925 [
926 'label' => esc_html__( 'Hover', 'elementor' ),
927 ]
928 );
929
930 $this->add_group_control(
931 Group_Control_Border::get_type(),
932 [
933 'name' => 'border_hover',
934 'selector' => '{{WRAPPER}}:hover',
935 ]
936 );
937
938 $this->add_responsive_control(
939 'border_radius_hover',
940 [
941 'label' => esc_html__( 'Border Radius', 'elementor' ),
942 'type' => Controls_Manager::DIMENSIONS,
943 'size_units' => [ 'px', '%', 'em' ],
944 'selectors' => [
945 '{{WRAPPER}}:hover' => '--border-radius: {{TOP}}{{UNIT}} {{RIGHT}}{{UNIT}} {{BOTTOM}}{{UNIT}} {{LEFT}}{{UNIT}};',
946 ],
947 ]
948 );
949
950 $this->add_group_control(
951 Group_Control_Box_Shadow::get_type(),
952 [
953 'name' => 'box_shadow_hover',
954 'selector' => '{{WRAPPER}}:hover',
955 ]
956 );
957
958 $this->add_control(
959 'border_hover_transition',
960 [
961 'label' => esc_html__( 'Transition Duration', 'elementor' ),
962 'type' => Controls_Manager::SLIDER,
963 'separator' => 'before',
964 'size_units' => [ 's', 'ms' ],
965 'default' => [
966 'unit' => 's',
967 'size' => 0.3,
968 ],
969 'conditions' => [
970 'relation' => 'or',
971 'terms' => [
972 [
973 'name' => 'background_background',
974 'operator' => '!==',
975 'value' => '',
976 ],
977 [
978 'name' => 'border_border',
979 'operator' => '!==',
980 'value' => '',
981 ],
982 ],
983 ],
984 'selectors' => [
985 '{{WRAPPER}}' => '--transition: background {{background_hover_transition.SIZE}}{{background_hover_transition.UNIT}}, border {{SIZE}}{{UNIT}}, border-radius {{SIZE}}{{UNIT}}, box-shadow {{SIZE}}{{UNIT}}',
986 '{{WRAPPER}}::before' => '--overlay-transition: background {{background_overlay_hover_transition.SIZE}}{{background_overlay_hover_transition.UNIT}}, border-radius {{SIZE}}{{UNIT}}, opacity {{background_overlay_hover_transition.SIZE}}{{background_overlay_hover_transition.UNIT}}',
987 ],
988 ]
989 );
990
991 $this->end_controls_tab();
992
993 $this->end_controls_tabs();
994
995 $this->end_controls_section();
996 }
997
998 /**
999 * Register the Container's shape dividers controls.
1000 * TODO: Copied from `section.php`.
1001 *
1002 * @return void
1003 */
1004 protected function register_shape_dividers_controls() {
1005 $this->start_controls_section(
1006 'section_shape_divider',
1007 [
1008 'label' => esc_html__( 'Shape Divider', 'elementor' ),
1009 'tab' => Controls_Manager::TAB_STYLE,
1010 ]
1011 );
1012
1013 $this->start_controls_tabs( 'tabs_shape_dividers' );
1014
1015 $shapes_options = [
1016 '' => esc_html__( 'None', 'elementor' ),
1017 ];
1018
1019 foreach ( Shapes::get_shapes() as $shape_name => $shape_props ) {
1020 $shapes_options[ $shape_name ] = $shape_props['title'];
1021 }
1022
1023 foreach ( [
1024 'top' => esc_html__( 'Top', 'elementor' ),
1025 'bottom' => esc_html__( 'Bottom', 'elementor' ),
1026 ] as $side => $side_label ) {
1027 $base_control_key = "shape_divider_$side";
1028
1029 $this->start_controls_tab(
1030 "tab_$base_control_key",
1031 [
1032 'label' => $side_label,
1033 ]
1034 );
1035
1036 $this->add_control(
1037 $base_control_key,
1038 [
1039 'label' => esc_html__( 'Type', 'elementor' ),
1040 'type' => Controls_Manager::SELECT,
1041 'options' => $shapes_options,
1042 'render_type' => 'none',
1043 'frontend_available' => true,
1044 ]
1045 );
1046
1047 $this->add_control(
1048 $base_control_key . '_color',
1049 [
1050 'label' => esc_html__( 'Color', 'elementor' ),
1051 'type' => Controls_Manager::COLOR,
1052 'condition' => [
1053 "shape_divider_$side!" => '',
1054 ],
1055 'selectors' => [
1056 "{{WRAPPER}} > .elementor-shape-$side .elementor-shape-fill, {{WRAPPER}} > .e-con-inner > .elementor-shape-$side .elementor-shape-fill" => 'fill: {{UNIT}};',
1057 ],
1058 ]
1059 );
1060
1061 $this->add_responsive_control(
1062 $base_control_key . '_width',
1063 [
1064 'label' => esc_html__( 'Width', 'elementor' ),
1065 'type' => Controls_Manager::SLIDER,
1066 'default' => [
1067 'unit' => '%',
1068 ],
1069 'tablet_default' => [
1070 'unit' => '%',
1071 ],
1072 'mobile_default' => [
1073 'unit' => '%',
1074 ],
1075 'range' => [
1076 '%' => [
1077 'min' => 100,
1078 'max' => 300,
1079 ],
1080 ],
1081 'condition' => [
1082 "shape_divider_$side" => array_keys( Shapes::filter_shapes( 'height_only', Shapes::FILTER_EXCLUDE ) ),
1083 ],
1084 'selectors' => [
1085 "{{WRAPPER}} > .elementor-shape-$side svg, {{WRAPPER}} > .e-con-inner > .elementor-shape-$side svg" => 'width: calc({{SIZE}}{{UNIT}} + 1.3px)',
1086 ],
1087 ]
1088 );
1089
1090 $this->add_responsive_control(
1091 $base_control_key . '_height',
1092 [
1093 'label' => esc_html__( 'Height', 'elementor' ),
1094 'type' => Controls_Manager::SLIDER,
1095 'range' => [
1096 'px' => [
1097 'max' => 500,
1098 ],
1099 ],
1100 'condition' => [
1101 "shape_divider_$side!" => '',
1102 ],
1103 'selectors' => [
1104 "{{WRAPPER}} > .elementor-shape-$side svg, {{WRAPPER}} > .e-con-inner > .elementor-shape-$side svg" => 'height: {{SIZE}}{{UNIT}};',
1105 ],
1106 ]
1107 );
1108
1109 $this->add_control(
1110 $base_control_key . '_flip',
1111 [
1112 'label' => esc_html__( 'Flip', 'elementor' ),
1113 'type' => Controls_Manager::SWITCHER,
1114 'condition' => [
1115 "shape_divider_$side" => array_keys( Shapes::filter_shapes( 'has_flip' ) ),
1116 ],
1117 'selectors' => [
1118 "{{WRAPPER}} > .elementor-shape-$side svg, {{WRAPPER}} > .e-con-inner > .elementor-shape-$side svg" => 'transform: translateX(-50%) rotateY(180deg)',
1119 ],
1120 ]
1121 );
1122
1123 $this->add_control(
1124 $base_control_key . '_negative',
1125 [
1126 'label' => esc_html__( 'Invert', 'elementor' ),
1127 'type' => Controls_Manager::SWITCHER,
1128 'frontend_available' => true,
1129 'condition' => [
1130 "shape_divider_$side" => array_keys( Shapes::filter_shapes( 'has_negative' ) ),
1131 ],
1132 'render_type' => 'none',
1133 ]
1134 );
1135
1136 $this->add_control(
1137 $base_control_key . '_above_content',
1138 [
1139 'label' => esc_html__( 'Bring to Front', 'elementor' ),
1140 'type' => Controls_Manager::SWITCHER,
1141 'selectors' => [
1142 "{{WRAPPER}} > .elementor-shape-$side, {{WRAPPER}} > .e-con-inner > .elementor-shape-$side" => 'z-index: 2; pointer-events: none',
1143 ],
1144 'condition' => [
1145 "shape_divider_$side!" => '',
1146 ],
1147 ]
1148 );
1149
1150 $this->end_controls_tab();
1151 }
1152
1153 $this->end_controls_tabs();
1154
1155 $this->end_controls_section();
1156 }
1157 /**
1158 * Register the Container's style tab.
1159 *
1160 * @return void
1161 */
1162 protected function register_style_tab() {
1163 $this->register_background_controls();
1164
1165 $this->register_background_overlay_controls();
1166
1167 $this->register_border_controls();
1168
1169 $this->register_shape_dividers_controls();
1170 }
1171
1172 /**
1173 * Register the Container's advanced style controls.
1174 *
1175 * @return void
1176 */
1177 protected function register_advanced_controls() {
1178 $this->start_controls_section(
1179 'section_layout',
1180 [
1181 'label' => esc_html__( 'Layout', 'elementor' ),
1182 'tab' => Controls_Manager::TAB_ADVANCED,
1183 ]
1184 );
1185
1186 $this->add_responsive_control(
1187 'margin',
1188 [
1189 'label' => esc_html__( 'Margin', 'elementor' ),
1190 'type' => Controls_Manager::DIMENSIONS,
1191 'size_units' => [ 'px', 'em', '%', 'rem' ],
1192 'selectors' => [
1193 '{{WRAPPER}}' => '--margin-top: {{TOP}}{{UNIT}}; --margin-right: {{RIGHT}}{{UNIT}}; --margin-bottom: {{BOTTOM}}{{UNIT}}; --margin-left:{{LEFT}}{{UNIT}};',
1194 ],
1195 ]
1196 );
1197
1198 $this->add_responsive_control(
1199 'padding',
1200 [
1201 'label' => esc_html__( 'Padding', 'elementor' ),
1202 'type' => Controls_Manager::DIMENSIONS,
1203 'size_units' => [ 'px', 'em', '%', 'rem' ],
1204 'selectors' => [
1205 '{{WRAPPER}}' => '--padding-top: {{TOP}}{{UNIT}}; --padding-right: {{RIGHT}}{{UNIT}}; --padding-bottom: {{BOTTOM}}{{UNIT}}; --padding-left: {{LEFT}}{{UNIT}};',
1206 ],
1207 ]
1208 );
1209
1210 $this->add_group_control(
1211 Group_Control_Flex_Item::get_type(),
1212 [
1213 'name' => '_flex',
1214 'include' => [
1215 'align_self',
1216 'order',
1217 'order_custom',
1218 'size',
1219 'grow',
1220 'shrink',
1221 ],
1222 'selector' => '{{WRAPPER}}.e-con', // Hack to increase specificity.
1223 'separator' => 'before',
1224 ]
1225 );
1226
1227 $this->add_control(
1228 'position_description',
1229 [
1230 'raw' => '<strong>' . esc_html__( 'Please note!', 'elementor' ) . '</strong> ' . esc_html__( 'Custom positioning is not considered best practice for responsive web design and should not be used too frequently.', 'elementor' ),
1231 'type' => Controls_Manager::RAW_HTML,
1232 'content_classes' => 'elementor-panel-alert elementor-panel-alert-warning',
1233 'render_type' => 'ui',
1234 'condition' => [
1235 'position!' => '',
1236 ],
1237 ]
1238 );
1239
1240 // TODO: Copied from `common.php` - Extract to group control.
1241 $this->add_control(
1242 'position',
1243 [
1244 'label' => esc_html__( 'Position', 'elementor' ),
1245 'type' => Controls_Manager::SELECT,
1246 'default' => '',
1247 'options' => [
1248 '' => esc_html__( 'Default', 'elementor' ),
1249 'absolute' => esc_html__( 'Absolute', 'elementor' ),
1250 'fixed' => esc_html__( 'Fixed', 'elementor' ),
1251 ],
1252 'selectors' => [
1253 '{{WRAPPER}}' => '--position: {{VALUE}};',
1254 ],
1255 'frontend_available' => true,
1256 'separator' => 'before',
1257 ]
1258 );
1259
1260 $left = esc_html__( 'Left', 'elementor' );
1261 $right = esc_html__( 'Right', 'elementor' );
1262
1263 $start = is_rtl() ? $right : $left;
1264 $end = ! is_rtl() ? $right : $left;
1265
1266 $this->add_control(
1267 '_offset_orientation_h',
1268 [
1269 'label' => esc_html__( 'Horizontal Orientation', 'elementor' ),
1270 'type' => Controls_Manager::CHOOSE,
1271 'toggle' => false,
1272 'default' => 'start',
1273 'options' => [
1274 'start' => [
1275 'title' => $start,
1276 'icon' => 'eicon-h-align-left',
1277 ],
1278 'end' => [
1279 'title' => $end,
1280 'icon' => 'eicon-h-align-right',
1281 ],
1282 ],
1283 'classes' => 'elementor-control-start-end',
1284 'render_type' => 'ui',
1285 'condition' => [
1286 'position!' => '',
1287 ],
1288 ]
1289 );
1290
1291 $this->add_responsive_control(
1292 '_offset_x',
1293 [
1294 'label' => esc_html__( 'Offset', 'elementor' ),
1295 'type' => Controls_Manager::SLIDER,
1296 'range' => [
1297 'px' => [
1298 'min' => -1000,
1299 'max' => 1000,
1300 'step' => 1,
1301 ],
1302 '%' => [
1303 'min' => -200,
1304 'max' => 200,
1305 ],
1306 'vw' => [
1307 'min' => -200,
1308 'max' => 200,
1309 ],
1310 'vh' => [
1311 'min' => -200,
1312 'max' => 200,
1313 ],
1314 ],
1315 'default' => [
1316 'size' => '0',
1317 ],
1318 'size_units' => [ 'px', '%', 'vw', 'vh' ],
1319 'selectors' => [
1320 'body:not(.rtl) {{WRAPPER}}' => 'left: {{SIZE}}{{UNIT}}',
1321 'body.rtl {{WRAPPER}}' => 'right: {{SIZE}}{{UNIT}}',
1322 ],
1323 'condition' => [
1324 '_offset_orientation_h!' => 'end',
1325 'position!' => '',
1326 ],
1327 ]
1328 );
1329
1330 $this->add_responsive_control(
1331 '_offset_x_end',
1332 [
1333 'label' => esc_html__( 'Offset', 'elementor' ),
1334 'type' => Controls_Manager::SLIDER,
1335 'range' => [
1336 'px' => [
1337 'min' => -1000,
1338 'max' => 1000,
1339 'step' => 0.1,
1340 ],
1341 '%' => [
1342 'min' => -200,
1343 'max' => 200,
1344 ],
1345 'vw' => [
1346 'min' => -200,
1347 'max' => 200,
1348 ],
1349 'vh' => [
1350 'min' => -200,
1351 'max' => 200,
1352 ],
1353 ],
1354 'default' => [
1355 'size' => '0',
1356 ],
1357 'size_units' => [ 'px', '%', 'vw', 'vh' ],
1358 'selectors' => [
1359 'body:not(.rtl) {{WRAPPER}}' => 'right: {{SIZE}}{{UNIT}}',
1360 'body.rtl {{WRAPPER}}' => 'left: {{SIZE}}{{UNIT}}',
1361 ],
1362 'condition' => [
1363 '_offset_orientation_h' => 'end',
1364 'position!' => '',
1365 ],
1366 ]
1367 );
1368
1369 $this->add_control(
1370 '_offset_orientation_v',
1371 [
1372 'label' => esc_html__( 'Vertical Orientation', 'elementor' ),
1373 'type' => Controls_Manager::CHOOSE,
1374 'toggle' => false,
1375 'default' => 'start',
1376 'options' => [
1377 'start' => [
1378 'title' => esc_html__( 'Top', 'elementor' ),
1379 'icon' => 'eicon-v-align-top',
1380 ],
1381 'end' => [
1382 'title' => esc_html__( 'Bottom', 'elementor' ),
1383 'icon' => 'eicon-v-align-bottom',
1384 ],
1385 ],
1386 'render_type' => 'ui',
1387 'condition' => [
1388 'position!' => '',
1389 ],
1390 ]
1391 );
1392
1393 $this->add_responsive_control(
1394 '_offset_y',
1395 [
1396 'label' => esc_html__( 'Offset', 'elementor' ),
1397 'type' => Controls_Manager::SLIDER,
1398 'range' => [
1399 'px' => [
1400 'min' => -1000,
1401 'max' => 1000,
1402 'step' => 1,
1403 ],
1404 '%' => [
1405 'min' => -200,
1406 'max' => 200,
1407 ],
1408 'vh' => [
1409 'min' => -200,
1410 'max' => 200,
1411 ],
1412 'vw' => [
1413 'min' => -200,
1414 'max' => 200,
1415 ],
1416 ],
1417 'size_units' => [ 'px', '%', 'vh', 'vw' ],
1418 'default' => [
1419 'size' => '0',
1420 ],
1421 'selectors' => [
1422 '{{WRAPPER}}' => 'top: {{SIZE}}{{UNIT}}',
1423 ],
1424 'condition' => [
1425 '_offset_orientation_v!' => 'end',
1426 'position!' => '',
1427 ],
1428 ]
1429 );
1430
1431 $this->add_responsive_control(
1432 '_offset_y_end',
1433 [
1434 'label' => esc_html__( 'Offset', 'elementor' ),
1435 'type' => Controls_Manager::SLIDER,
1436 'range' => [
1437 'px' => [
1438 'min' => -1000,
1439 'max' => 1000,
1440 'step' => 1,
1441 ],
1442 '%' => [
1443 'min' => -200,
1444 'max' => 200,
1445 ],
1446 'vh' => [
1447 'min' => -200,
1448 'max' => 200,
1449 ],
1450 'vw' => [
1451 'min' => -200,
1452 'max' => 200,
1453 ],
1454 ],
1455 'size_units' => [ 'px', '%', 'vh', 'vw' ],
1456 'default' => [
1457 'size' => '0',
1458 ],
1459 'selectors' => [
1460 '{{WRAPPER}}' => 'bottom: {{SIZE}}{{UNIT}}',
1461 ],
1462 'condition' => [
1463 '_offset_orientation_v' => 'end',
1464 'position!' => '',
1465 ],
1466 ]
1467 );
1468
1469 $this->add_responsive_control(
1470 'z_index',
1471 [
1472 'label' => esc_html__( 'Z-Index', 'elementor' ),
1473 'type' => Controls_Manager::NUMBER,
1474 'min' => 0,
1475 'selectors' => [
1476 '{{WRAPPER}}' => '--z-index: {{VALUE}};',
1477 ],
1478 ]
1479 );
1480
1481 $this->add_control(
1482 '_element_id',
1483 [
1484 'label' => esc_html__( 'CSS ID', 'elementor' ),
1485 'type' => Controls_Manager::TEXT,
1486 'default' => '',
1487 'dynamic' => [
1488 'active' => true,
1489 ],
1490 'title' => esc_html__( 'Add your custom id WITHOUT the Pound key. e.g: my-id', 'elementor' ),
1491 'style_transfer' => false,
1492 'classes' => 'elementor-control-direction-ltr',
1493 ]
1494 );
1495
1496 $this->add_control(
1497 'css_classes',
1498 [
1499 'label' => esc_html__( 'CSS Classes', 'elementor' ),
1500 'type' => Controls_Manager::TEXT,
1501 'default' => '',
1502 'dynamic' => [
1503 'active' => true,
1504 ],
1505 'prefix_class' => '',
1506 'title' => esc_html__( 'Add your custom class WITHOUT the dot. e.g: my-class', 'elementor' ),
1507 'classes' => 'elementor-control-direction-ltr',
1508 ]
1509 );
1510
1511 $this->end_controls_section();
1512 }
1513
1514 /**
1515 * Register the Container's motion effects controls.
1516 *
1517 * @return void
1518 */
1519 protected function register_motion_effects_controls() {
1520 $this->start_controls_section(
1521 'section_effects',
1522 [
1523 'label' => esc_html__( 'Motion Effects', 'elementor' ),
1524 'tab' => Controls_Manager::TAB_ADVANCED,
1525 ]
1526 );
1527
1528 $this->add_responsive_control(
1529 'animation',
1530 [
1531 'label' => esc_html__( 'Entrance Animation', 'elementor' ),
1532 'type' => Controls_Manager::ANIMATION,
1533 'frontend_available' => true,
1534 ]
1535 );
1536
1537 $this->add_control(
1538 'animation_duration',
1539 [
1540 'label' => esc_html__( 'Animation Duration', 'elementor' ),
1541 'type' => Controls_Manager::SELECT,
1542 'default' => '',
1543 'options' => [
1544 'slow' => esc_html__( 'Slow', 'elementor' ),
1545 '' => esc_html__( 'Normal', 'elementor' ),
1546 'fast' => esc_html__( 'Fast', 'elementor' ),
1547 ],
1548 'prefix_class' => 'animated-',
1549 'condition' => [
1550 'animation!' => '',
1551 ],
1552 ]
1553 );
1554
1555 $this->add_control(
1556 'animation_delay',
1557 [
1558 'label' => esc_html__( 'Animation Delay', 'elementor' ) . ' (ms)',
1559 'type' => Controls_Manager::NUMBER,
1560 'default' => '',
1561 'min' => 0,
1562 'step' => 100,
1563 'condition' => [
1564 'animation!' => '',
1565 ],
1566 'render_type' => 'none',
1567 'frontend_available' => true,
1568 ]
1569 );
1570
1571 $this->end_controls_section();
1572 }
1573
1574 /**
1575 * Register the Container's responsive controls.
1576 *
1577 * @return void
1578 */
1579 protected function register_responsive_controls() {
1580 $this->start_controls_section(
1581 '_section_responsive',
1582 [
1583 'label' => esc_html__( 'Responsive', 'elementor' ),
1584 'tab' => Controls_Manager::TAB_ADVANCED,
1585 ]
1586 );
1587
1588 $this->add_control(
1589 'heading_visibility',
1590 [
1591 'label' => esc_html__( 'Visibility', 'elementor' ),
1592 'type' => Controls_Manager::HEADING,
1593 ]
1594 );
1595
1596 $this->add_control(
1597 'responsive_description',
1598 [
1599 'raw' => esc_html__( 'Responsive visibility will take effect only on preview or live page, and not while editing in Elementor.', 'elementor' ),
1600 'type' => Controls_Manager::RAW_HTML,
1601 'content_classes' => 'elementor-descriptor',
1602 ]
1603 );
1604
1605 $this->add_hidden_device_controls();
1606
1607 $this->end_controls_section();
1608 }
1609
1610 /**
1611 * Register the Container's advanced tab.
1612 *
1613 * @return void
1614 */
1615 protected function register_advanced_tab() {
1616 $this->register_advanced_controls();
1617
1618 $this->register_motion_effects_controls();
1619
1620 $this->register_responsive_controls();
1621
1622 Plugin::$instance->controls_manager->add_custom_attributes_controls( $this );
1623
1624 Plugin::$instance->controls_manager->add_custom_css_controls( $this );
1625 }
1626
1627 /**
1628 * Register the Container's controls.
1629 *
1630 * @return void
1631 */
1632 protected function register_controls() {
1633 $this->register_layout_tab();
1634 $this->register_style_tab();
1635 $this->register_advanced_tab();
1636 }
1637 }
1638