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

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