PluginProbe
Elementor Website Builder – more than just a page builder / 3.34.2
Elementor Website Builder – more than just a page builder v3.34.2
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.34.2, at includes/elements/container.php

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