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

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