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

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