Diff: STRATO-apps/wordpress_03/app/wp-content/plugins/elementor/includes/elements/container.php

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