PluginProbe
Elementor Website Builder – more than just a page builder / 3.16.0-dev1
Elementor Website Builder – more than just a page builder v3.16.0-dev1
4.3.0-beta2 4.3.0-beta1 4.2.4 4.2.3 4.2.2 4.2.1 4.2.0 4.1.5 4.2.0-beta2 4.2.0-dev2 4.2.0-beta1 4.1.4 4.1.3 4.1.2 4.1.1 4.1.0 4.1.0-beta3 4.1.0-dev3 4.0.9 4.1.0-beta2 4.1.0-dev2 4.0.8 4.1.0-beta1 4.1.0-dev1 4.0.7 All 451 releases
elementor / includes / elements / container.php

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

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