PluginProbe
Elementor Website Builder – more than just a page builder / 3.21.5
Elementor Website Builder – more than just a page builder v3.21.5
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 / section.php

section.php in Elementor Website Builder – more than just a page builder 3.21.5, at includes/elements/section.php

1,581 lines 38.1 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 namespace Elementor;
3
4 if ( ! defined( 'ABSPATH' ) ) {
5 exit; // Exit if accessed directly.
6 }
7
8 /**
9 * Elementor section element.
10 *
11 * Elementor section handler class is responsible for initializing the section
12 * element.
13 *
14 * @since 1.0.0
15 */
16 class Element_Section extends Element_Base {
17
18 /**
19 * Section predefined columns presets.
20 *
21 * Holds the predefined columns width for each columns count available by
22 * default by Elementor. Default is an empty array.
23 *
24 * Note that when the user creates a section he can define custom sizes for
25 * the columns. But Elementor sets default values for predefined columns.
26 *
27 * For example two columns 50% width each one, or three columns 33.33% each
28 * one. This property hold the data for those preset values.
29 *
30 * @since 1.0.0
31 * @access private
32 * @static
33 *
34 * @var array Section presets.
35 */
36 private static $presets = [];
37
38 /**
39 * Get element type.
40 *
41 * Retrieve the element type, in this case `section`.
42 *
43 * @since 2.1.0
44 * @access public
45 * @static
46 *
47 * @return string The type.
48 */
49 public static function get_type() {
50 return 'section';
51 }
52
53 /**
54 * Get section name.
55 *
56 * Retrieve the section name.
57 *
58 * @since 1.0.0
59 * @access public
60 *
61 * @return string Section name.
62 */
63 public function get_name() {
64 return 'section';
65 }
66
67 /**
68 * Get section title.
69 *
70 * Retrieve the section title.
71 *
72 * @since 1.0.0
73 * @access public
74 *
75 * @return string Section title.
76 */
77 public function get_title() {
78 return esc_html__( 'Section', 'elementor' );
79 }
80
81 /**
82 * Get section icon.
83 *
84 * Retrieve the section icon.
85 *
86 * @since 1.0.0
87 * @access public
88 *
89 * @return string Section icon.
90 */
91 public function get_icon() {
92 return 'eicon-columns';
93 }
94
95 /**
96 * Get presets.
97 *
98 * Retrieve a specific preset columns for a given columns count, or a list
99 * of all the preset if no parameters passed.
100 *
101 * @since 1.0.0
102 * @access public
103 * @static
104 *
105 * @param int $columns_count Optional. Columns count. Default is null.
106 * @param int $preset_index Optional. Preset index. Default is null.
107 *
108 * @return array Section presets.
109 */
110 public static function get_presets( $columns_count = null, $preset_index = null ) {
111 if ( ! self::$presets ) {
112 self::init_presets();
113 }
114
115 $presets = self::$presets;
116
117 if ( null !== $columns_count ) {
118 $presets = $presets[ $columns_count ];
119 }
120
121 if ( null !== $preset_index ) {
122 $presets = $presets[ $preset_index ];
123 }
124
125 return $presets;
126 }
127
128 /**
129 * Initialize presets.
130 *
131 * Initializing the section presets and set the number of columns the
132 * section can have by default. For example a column can have two columns
133 * 50% width each one, or three columns 33.33% each one.
134 *
135 * Note that Elementor sections have default section presets but the user
136 * can set custom number of columns and define custom sizes for each column.
137
138 * @since 1.0.0
139 * @access public
140 * @static
141 */
142 public static function init_presets() {
143 $additional_presets = [
144 2 => [
145 [
146 'preset' => [ 33, 66 ],
147 ],
148 [
149 'preset' => [ 66, 33 ],
150 ],
151 ],
152 3 => [
153 [
154 'preset' => [ 25, 25, 50 ],
155 ],
156 [
157 'preset' => [ 50, 25, 25 ],
158 ],
159 [
160 'preset' => [ 25, 50, 25 ],
161 ],
162 [
163 'preset' => [ 16, 66, 16 ],
164 ],
165 ],
166 ];
167
168 foreach ( range( 1, 10 ) as $columns_count ) {
169 self::$presets[ $columns_count ] = [
170 [
171 'preset' => [],
172 ],
173 ];
174
175 $preset_unit = floor( 1 / $columns_count * 100 );
176
177 for ( $i = 0; $i < $columns_count; $i++ ) {
178 self::$presets[ $columns_count ][0]['preset'][] = $preset_unit;
179 }
180
181 if ( ! empty( $additional_presets[ $columns_count ] ) ) {
182 self::$presets[ $columns_count ] = array_merge( self::$presets[ $columns_count ], $additional_presets[ $columns_count ] );
183 }
184
185 foreach ( self::$presets[ $columns_count ] as $preset_index => & $preset ) {
186 $preset['key'] = $columns_count . $preset_index;
187 }
188 }
189 }
190
191 /**
192 * Get initial config.
193 *
194 * Retrieve the current section initial configuration.
195 *
196 * Adds more configuration on top of the controls list, the tabs assigned to
197 * the control, element name, type, icon and more. This method also adds
198 * section presets.
199 *
200 * @since 2.9.0
201 * @access protected
202 *
203 * @return array The initial config.
204 */
205 protected function get_initial_config() {
206 $config = parent::get_initial_config();
207
208 $config['presets'] = self::get_presets();
209 $config['controls'] = $this->get_controls();
210 $config['tabs_controls'] = $this->get_tabs_controls();
211
212 return $config;
213 }
214
215 /**
216 * Register section controls.
217 *
218 * Used to add new controls to the section element.
219 *
220 * @since 3.1.0
221 * @access protected
222 */
223 protected function register_controls() {
224 $this->start_controls_section(
225 'section_layout',
226 [
227 'label' => esc_html__( 'Layout', 'elementor' ),
228 'tab' => Controls_Manager::TAB_LAYOUT,
229 ]
230 );
231
232 // Element Name for the Navigator
233 $this->add_control(
234 '_title',
235 [
236 'label' => esc_html__( 'Title', 'elementor' ),
237 'type' => Controls_Manager::HIDDEN,
238 'render_type' => 'none',
239 ]
240 );
241
242 $this->add_control(
243 'layout',
244 [
245 'label' => esc_html__( 'Content Width', 'elementor' ),
246 'type' => Controls_Manager::SELECT,
247 'default' => 'boxed',
248 'options' => [
249 'boxed' => esc_html__( 'Boxed', 'elementor' ),
250 'full_width' => esc_html__( 'Full Width', 'elementor' ),
251 ],
252 'prefix_class' => 'elementor-section-',
253 ]
254 );
255
256 $this->add_responsive_control(
257 'content_width',
258 [
259 'label' => esc_html__( 'Width', 'elementor' ),
260 'type' => Controls_Manager::SLIDER,
261 'range' => [
262 'px' => [
263 'min' => 500,
264 'max' => 1600,
265 ],
266 ],
267 'selectors' => [
268 '{{WRAPPER}} > .elementor-container' => 'max-width: {{SIZE}}{{UNIT}};',
269 ],
270 'condition' => [
271 'layout' => [ 'boxed' ],
272 ],
273 ]
274 );
275
276 $this->add_control(
277 'gap',
278 [
279 'label' => esc_html__( 'Columns Gap', 'elementor' ),
280 'type' => Controls_Manager::SELECT,
281 'default' => 'default',
282 'options' => [
283 'default' => esc_html__( 'Default', 'elementor' ),
284 'no' => esc_html__( 'No Gap', 'elementor' ),
285 'narrow' => esc_html__( 'Narrow', 'elementor' ),
286 'extended' => esc_html__( 'Extended', 'elementor' ),
287 'wide' => esc_html__( 'Wide', 'elementor' ),
288 'wider' => esc_html__( 'Wider', 'elementor' ),
289 'custom' => esc_html__( 'Custom', 'elementor' ),
290 ],
291 ]
292 );
293
294 $this->add_responsive_control(
295 'gap_columns_custom',
296 [
297 'label' => esc_html__( 'Custom Columns Gap', 'elementor' ),
298 'type' => Controls_Manager::SLIDER,
299 'range' => [
300 'px' => [
301 'max' => 500,
302 ],
303 ],
304 'size_units' => [ 'px', '%', 'em', 'rem', 'vh', 'vw', 'custom' ],
305 'selectors' => [
306 '{{WRAPPER}} .elementor-column-gap-custom .elementor-column > .elementor-element-populated' => 'padding: {{SIZE}}{{UNIT}};',
307 ],
308 'condition' => [
309 'gap' => 'custom',
310 ],
311 ]
312 );
313
314 $this->add_control(
315 'height',
316 [
317 'label' => esc_html__( 'Height', 'elementor' ),
318 'type' => Controls_Manager::SELECT,
319 'default' => 'default',
320 'options' => [
321 'default' => esc_html__( 'Default', 'elementor' ),
322 'full' => esc_html__( 'Fit To Screen', 'elementor' ),
323 'min-height' => esc_html__( 'Min Height', 'elementor' ),
324 ],
325 'prefix_class' => 'elementor-section-height-',
326 'hide_in_inner' => true,
327 ]
328 );
329
330 $this->add_responsive_control(
331 'custom_height',
332 [
333 'label' => esc_html__( 'Minimum Height', 'elementor' ),
334 'type' => Controls_Manager::SLIDER,
335 'default' => [
336 'size' => 400,
337 ],
338 'range' => [
339 'px' => [
340 'max' => 1440,
341 ],
342 ],
343 'size_units' => [ 'px', 'em', 'rem', 'vh', 'vw', 'custom' ],
344 'selectors' => [
345 '{{WRAPPER}} > .elementor-container' => 'min-height: {{SIZE}}{{UNIT}};',
346 ],
347 'condition' => [
348 'height' => [ 'min-height' ],
349 ],
350 'hide_in_inner' => true,
351 ]
352 );
353
354 $this->add_control(
355 'height_inner',
356 [
357 'label' => esc_html__( 'Height', 'elementor' ),
358 'type' => Controls_Manager::SELECT,
359 'default' => 'default',
360 'options' => [
361 'default' => esc_html__( 'Default', 'elementor' ),
362 'full' => esc_html__( 'Fit To Screen', 'elementor' ),
363 'min-height' => esc_html__( 'Min Height', 'elementor' ),
364 ],
365 'prefix_class' => 'elementor-section-height-',
366 'hide_in_top' => true,
367 ]
368 );
369
370 $this->add_responsive_control(
371 'custom_height_inner',
372 [
373 'label' => esc_html__( 'Minimum Height', 'elementor' ),
374 'type' => Controls_Manager::SLIDER,
375 'default' => [
376 'size' => 400,
377 ],
378 'range' => [
379 'px' => [
380 'max' => 1440,
381 ],
382 ],
383 'selectors' => [
384 '{{WRAPPER}} > .elementor-container' => 'min-height: {{SIZE}}{{UNIT}};',
385 ],
386 'condition' => [
387 'height_inner' => [ 'min-height' ],
388 ],
389 'size_units' => [ 'px', 'em', 'rem', 'vh', 'vw', 'custom' ],
390 'hide_in_top' => true,
391 ]
392 );
393
394 $this->add_control(
395 'column_position',
396 [
397 'label' => esc_html__( 'Column Position', 'elementor' ),
398 'type' => Controls_Manager::SELECT,
399 'default' => 'middle',
400 'options' => [
401 'stretch' => esc_html__( 'Stretch', 'elementor' ),
402 'top' => esc_html__( 'Top', 'elementor' ),
403 'middle' => esc_html__( 'Middle', 'elementor' ),
404 'bottom' => esc_html__( 'Bottom', 'elementor' ),
405 ],
406 'prefix_class' => 'elementor-section-items-',
407 'condition' => [
408 'height' => [ 'full', 'min-height' ],
409 ],
410 ]
411 );
412
413 $this->add_control(
414 'content_position',
415 [
416 'label' => esc_html__( 'Vertical Align', 'elementor' ),
417 'type' => Controls_Manager::SELECT,
418 'default' => '',
419 'options' => [
420 '' => esc_html__( 'Default', 'elementor' ),
421 'top' => esc_html__( 'Top', 'elementor' ),
422 'middle' => esc_html__( 'Middle', 'elementor' ),
423 'bottom' => esc_html__( 'Bottom', 'elementor' ),
424 'space-between' => esc_html__( 'Space Between', 'elementor' ),
425 'space-around' => esc_html__( 'Space Around', 'elementor' ),
426 'space-evenly' => esc_html__( 'Space Evenly', 'elementor' ),
427 ],
428 'selectors_dictionary' => [
429 'top' => 'flex-start',
430 'middle' => 'center',
431 'bottom' => 'flex-end',
432 ],
433 'selectors' => [
434 '{{WRAPPER}} > .elementor-container > .elementor-column > .elementor-widget-wrap' => 'align-content: {{VALUE}}; align-items: {{VALUE}};',
435 ],
436 // TODO: The following line is for BC since 2.7.0
437 'prefix_class' => 'elementor-section-content-',
438 ]
439 );
440
441 $this->add_control(
442 'overflow',
443 [
444 'label' => esc_html__( 'Overflow', 'elementor' ),
445 'type' => Controls_Manager::SELECT,
446 'default' => '',
447 'options' => [
448 '' => esc_html__( 'Default', 'elementor' ),
449 'hidden' => esc_html__( 'Hidden', 'elementor' ),
450 ],
451 'selectors' => [
452 '{{WRAPPER}}' => 'overflow: {{VALUE}}',
453 ],
454 ]
455 );
456
457 $this->add_control(
458 'stretch_section',
459 [
460 'label' => esc_html__( 'Stretch Section', 'elementor' ),
461 'type' => Controls_Manager::SWITCHER,
462 'default' => '',
463 'return_value' => 'section-stretched',
464 'prefix_class' => 'elementor-',
465 'hide_in_inner' => true,
466 'description' => sprintf(
467 '%1$s <a href="https://go.elementor.com/stretch-section/" target="_blank">%2$s</a>',
468 esc_html__( 'Stretch the section to the full width of the page using JS.', 'elementor' ),
469 esc_html__( 'Learn more', 'elementor' )
470 ),
471 'render_type' => 'none',
472 'frontend_available' => true,
473 ]
474 );
475
476 $possible_tags = [
477 'div',
478 'header',
479 'footer',
480 'main',
481 'article',
482 'section',
483 'aside',
484 'nav',
485 ];
486
487 $options = [
488 '' => esc_html__( 'Default', 'elementor' ),
489 ] + array_combine( $possible_tags, $possible_tags );
490
491 $this->add_control(
492 'html_tag',
493 [
494 'label' => esc_html__( 'HTML Tag', 'elementor' ),
495 'type' => Controls_Manager::SELECT,
496 'options' => $options,
497 'separator' => 'before',
498 ]
499 );
500
501 $this->end_controls_section();
502
503 // Section Structure
504 $this->start_controls_section(
505 'section_structure',
506 [
507 'label' => esc_html__( 'Structure', 'elementor' ),
508 'tab' => Controls_Manager::TAB_LAYOUT,
509 ]
510 );
511
512 $this->add_control(
513 'structure',
514 [
515 'label' => esc_html__( 'Structure', 'elementor' ),
516 'type' => Controls_Manager::STRUCTURE,
517 'default' => '10',
518 'render_type' => 'none',
519 'style_transfer' => false,
520 ]
521 );
522
523 $this->end_controls_section();
524
525 // Section background
526 $this->start_controls_section(
527 'section_background',
528 [
529 'label' => esc_html__( 'Background', 'elementor' ),
530 'tab' => Controls_Manager::TAB_STYLE,
531 ]
532 );
533
534 $this->start_controls_tabs( 'tabs_background' );
535
536 $this->start_controls_tab(
537 'tab_background_normal',
538 [
539 'label' => esc_html__( 'Normal', 'elementor' ),
540 ]
541 );
542
543 $this->add_group_control(
544 Group_Control_Background::get_type(),
545 [
546 'name' => 'background',
547 'types' => [ 'classic', 'gradient', 'video', 'slideshow' ],
548 'fields_options' => [
549 'background' => [
550 'frontend_available' => true,
551 ],
552 ],
553 ]
554 );
555
556 $this->end_controls_tab();
557
558 $this->start_controls_tab(
559 'tab_background_hover',
560 [
561 'label' => esc_html__( 'Hover', 'elementor' ),
562 ]
563 );
564
565 $this->add_group_control(
566 Group_Control_Background::get_type(),
567 [
568 'name' => 'background_hover',
569 'selector' => '{{WRAPPER}}:hover',
570 ]
571 );
572
573 $this->add_control(
574 'background_hover_transition',
575 [
576 'label' => esc_html__( 'Transition Duration', 'elementor' ) . ' (s)',
577 'type' => Controls_Manager::SLIDER,
578 'default' => [
579 'size' => 0.3,
580 ],
581 'range' => [
582 'px' => [
583 'min' => 0,
584 'max' => 3,
585 'step' => 0.1,
586 ],
587 ],
588 'render_type' => 'ui',
589 'separator' => 'before',
590 ]
591 );
592
593 $this->end_controls_tab();
594
595 $this->end_controls_tabs();
596
597 $this->end_controls_section();
598
599 // Background Overlay
600 $this->start_controls_section(
601 'section_background_overlay',
602 [
603 'label' => esc_html__( 'Background Overlay', 'elementor' ),
604 'tab' => Controls_Manager::TAB_STYLE,
605 ]
606 );
607
608 $this->start_controls_tabs( 'tabs_background_overlay' );
609
610 $this->start_controls_tab(
611 'tab_background_overlay_normal',
612 [
613 'label' => esc_html__( 'Normal', 'elementor' ),
614 ]
615 );
616
617 $this->add_group_control(
618 Group_Control_Background::get_type(),
619 [
620 'name' => 'background_overlay',
621 'selector' => '{{WRAPPER}} > .elementor-background-overlay',
622 ]
623 );
624
625 $this->add_responsive_control(
626 'background_overlay_opacity',
627 [
628 'label' => esc_html__( 'Opacity', 'elementor' ),
629 'type' => Controls_Manager::SLIDER,
630 'default' => [
631 'size' => .5,
632 ],
633 'range' => [
634 'px' => [
635 'max' => 1,
636 'step' => 0.01,
637 ],
638 ],
639 'selectors' => [
640 '{{WRAPPER}} > .elementor-background-overlay' => 'opacity: {{SIZE}};',
641 ],
642 'condition' => [
643 'background_overlay_background' => [ 'classic', 'gradient' ],
644 ],
645 ]
646 );
647
648 $this->add_group_control(
649 Group_Control_Css_Filter::get_type(),
650 [
651 'name' => 'css_filters',
652 'selector' => '{{WRAPPER}} .elementor-background-overlay',
653 'conditions' => [
654 'relation' => 'or',
655 'terms' => [
656 [
657 'name' => 'background_overlay_image[url]',
658 'operator' => '!==',
659 'value' => '',
660 ],
661 [
662 'name' => 'background_overlay_color',
663 'operator' => '!==',
664 'value' => '',
665 ],
666 ],
667 ],
668 ]
669 );
670
671 $this->add_control(
672 'overlay_blend_mode',
673 [
674 'label' => esc_html__( 'Blend Mode', 'elementor' ),
675 'type' => Controls_Manager::SELECT,
676 'options' => [
677 '' => esc_html__( 'Normal', 'elementor' ),
678 'multiply' => esc_html__( 'Multiply', 'elementor' ),
679 'screen' => esc_html__( 'Screen', 'elementor' ),
680 'overlay' => esc_html__( 'Overlay', 'elementor' ),
681 'darken' => esc_html__( 'Darken', 'elementor' ),
682 'lighten' => esc_html__( 'Lighten', 'elementor' ),
683 'color-dodge' => esc_html__( 'Color Dodge', 'elementor' ),
684 'saturation' => esc_html__( 'Saturation', 'elementor' ),
685 'color' => esc_html__( 'Color', 'elementor' ),
686 'luminosity' => esc_html__( 'Luminosity', 'elementor' ),
687 'difference' => esc_html__( 'Difference', 'elementor' ),
688 'exclusion' => esc_html__( 'Exclusion', 'elementor' ),
689 'hue' => esc_html__( 'Hue', 'elementor' ),
690 ],
691 'selectors' => [
692 '{{WRAPPER}} > .elementor-background-overlay' => 'mix-blend-mode: {{VALUE}}',
693 ],
694 'conditions' => [
695 'relation' => 'or',
696 'terms' => [
697 [
698 'name' => 'background_overlay_image[url]',
699 'operator' => '!==',
700 'value' => '',
701 ],
702 [
703 'name' => 'background_overlay_color',
704 'operator' => '!==',
705 'value' => '',
706 ],
707 ],
708 ],
709 ]
710 );
711
712 $this->end_controls_tab();
713
714 $this->start_controls_tab(
715 'tab_background_overlay_hover',
716 [
717 'label' => esc_html__( 'Hover', 'elementor' ),
718 ]
719 );
720
721 $this->add_group_control(
722 Group_Control_Background::get_type(),
723 [
724 'name' => 'background_overlay_hover',
725 'selector' => '{{WRAPPER}}:hover > .elementor-background-overlay',
726 ]
727 );
728
729 $this->add_responsive_control(
730 'background_overlay_hover_opacity',
731 [
732 'label' => esc_html__( 'Opacity', 'elementor' ),
733 'type' => Controls_Manager::SLIDER,
734 'default' => [
735 'size' => .5,
736 ],
737 'range' => [
738 'px' => [
739 'max' => 1,
740 'step' => 0.01,
741 ],
742 ],
743 'selectors' => [
744 '{{WRAPPER}}:hover > .elementor-background-overlay' => 'opacity: {{SIZE}};',
745 ],
746 'condition' => [
747 'background_overlay_hover_background' => [ 'classic', 'gradient' ],
748 ],
749 ]
750 );
751
752 $this->add_group_control(
753 Group_Control_Css_Filter::get_type(),
754 [
755 'name' => 'css_filters_hover',
756 'selector' => '{{WRAPPER}}:hover > .elementor-background-overlay',
757 ]
758 );
759
760 $this->add_control(
761 'background_overlay_hover_transition',
762 [
763 'label' => esc_html__( 'Transition Duration', 'elementor' ) . ' (s)',
764 'type' => Controls_Manager::SLIDER,
765 'default' => [
766 'size' => 0.3,
767 ],
768 'range' => [
769 'px' => [
770 'min' => 0,
771 'max' => 3,
772 'step' => 0.1,
773 ],
774 ],
775 'render_type' => 'ui',
776 'separator' => 'before',
777 ]
778 );
779
780 $this->end_controls_tab();
781
782 $this->end_controls_tabs();
783
784 $this->end_controls_section();
785
786 // Section border
787 $this->start_controls_section(
788 'section_border',
789 [
790 'label' => esc_html__( 'Border', 'elementor' ),
791 'tab' => Controls_Manager::TAB_STYLE,
792 ]
793 );
794
795 $this->start_controls_tabs( 'tabs_border' );
796
797 $this->start_controls_tab(
798 'tab_border_normal',
799 [
800 'label' => esc_html__( 'Normal', 'elementor' ),
801 ]
802 );
803
804 $this->add_group_control(
805 Group_Control_Border::get_type(),
806 [
807 'name' => 'border',
808 ]
809 );
810
811 $this->add_responsive_control(
812 'border_radius',
813 [
814 'label' => esc_html__( 'Border Radius', 'elementor' ),
815 'type' => Controls_Manager::DIMENSIONS,
816 'size_units' => [ 'px', '%', 'em', 'rem', 'custom' ],
817 'selectors' => [
818 '{{WRAPPER}}, {{WRAPPER}} > .elementor-background-overlay' => 'border-radius: {{TOP}}{{UNIT}} {{RIGHT}}{{UNIT}} {{BOTTOM}}{{UNIT}} {{LEFT}}{{UNIT}};',
819 ],
820 ]
821 );
822
823 $this->add_group_control(
824 Group_Control_Box_Shadow::get_type(),
825 [
826 'name' => 'box_shadow',
827 ]
828 );
829
830 $this->end_controls_tab();
831
832 $this->start_controls_tab(
833 'tab_border_hover',
834 [
835 'label' => esc_html__( 'Hover', 'elementor' ),
836 ]
837 );
838
839 $this->add_group_control(
840 Group_Control_Border::get_type(),
841 [
842 'name' => 'border_hover',
843 'selector' => '{{WRAPPER}}:hover',
844 ]
845 );
846
847 $this->add_responsive_control(
848 'border_radius_hover',
849 [
850 'label' => esc_html__( 'Border Radius', 'elementor' ),
851 'type' => Controls_Manager::DIMENSIONS,
852 'size_units' => [ 'px', '%', 'em', 'rem', 'custom' ],
853 'selectors' => [
854 '{{WRAPPER}}:hover, {{WRAPPER}}:hover > .elementor-background-overlay' => 'border-radius: {{TOP}}{{UNIT}} {{RIGHT}}{{UNIT}} {{BOTTOM}}{{UNIT}} {{LEFT}}{{UNIT}};',
855 ],
856 ]
857 );
858
859 $this->add_group_control(
860 Group_Control_Box_Shadow::get_type(),
861 [
862 'name' => 'box_shadow_hover',
863 'selector' => '{{WRAPPER}}:hover',
864 ]
865 );
866
867 $this->add_control(
868 'border_hover_transition',
869 [
870 'label' => esc_html__( 'Transition Duration', 'elementor' ) . ' (s)',
871 'type' => Controls_Manager::SLIDER,
872 'separator' => 'before',
873 'default' => [
874 'size' => 0.3,
875 ],
876 'range' => [
877 'px' => [
878 'min' => 0,
879 'max' => 3,
880 'step' => 0.1,
881 ],
882 ],
883 'conditions' => [
884 'relation' => 'or',
885 'terms' => [
886 [
887 'name' => 'background_background',
888 'operator' => '!==',
889 'value' => '',
890 ],
891 [
892 'name' => 'border_border',
893 'operator' => '!==',
894 'value' => '',
895 ],
896 ],
897 ],
898 'selectors' => [
899 '{{WRAPPER}}' => 'transition: background {{background_hover_transition.SIZE}}s, border {{SIZE}}s, border-radius {{SIZE}}s, box-shadow {{SIZE}}s',
900 '{{WRAPPER}} > .elementor-background-overlay' => 'transition: background {{background_overlay_hover_transition.SIZE}}s, border-radius {{SIZE}}s, opacity {{background_overlay_hover_transition.SIZE}}s',
901 ],
902 ]
903 );
904
905 $this->end_controls_tab();
906
907 $this->end_controls_tabs();
908
909 $this->end_controls_section();
910
911 // Section Shape Divider
912 $this->start_controls_section(
913 'section_shape_divider',
914 [
915 'label' => esc_html__( 'Shape Divider', 'elementor' ),
916 'tab' => Controls_Manager::TAB_STYLE,
917 ]
918 );
919
920 $this->start_controls_tabs( 'tabs_shape_dividers' );
921
922 $shapes_options = [
923 '' => esc_html__( 'None', 'elementor' ),
924 ];
925
926 foreach ( Shapes::get_shapes() as $shape_name => $shape_props ) {
927 $shapes_options[ $shape_name ] = $shape_props['title'];
928 }
929
930 foreach ( [
931 'top' => esc_html__( 'Top', 'elementor' ),
932 'bottom' => esc_html__( 'Bottom', 'elementor' ),
933 ] as $side => $side_label ) {
934 $base_control_key = "shape_divider_$side";
935
936 $this->start_controls_tab(
937 "tab_$base_control_key",
938 [
939 'label' => $side_label,
940 ]
941 );
942
943 $this->add_control(
944 $base_control_key,
945 [
946 'label' => esc_html__( 'Type', 'elementor' ),
947 'type' => Controls_Manager::SELECT,
948 'options' => $shapes_options,
949 'render_type' => 'none',
950 'frontend_available' => true,
951 ]
952 );
953
954 $this->add_control(
955 $base_control_key . '_color',
956 [
957 'label' => esc_html__( 'Color', 'elementor' ),
958 'type' => Controls_Manager::COLOR,
959 'condition' => [
960 "shape_divider_$side!" => '',
961 ],
962 'selectors' => [
963 "{{WRAPPER}} > .elementor-shape-$side .elementor-shape-fill" => 'fill: {{UNIT}};',
964 ],
965 ]
966 );
967
968 $this->add_responsive_control(
969 $base_control_key . '_width',
970 [
971 'label' => esc_html__( 'Width', 'elementor' ),
972 'type' => Controls_Manager::SLIDER,
973 'size_units' => [ '%', 'vw', 'custom' ],
974 'default' => [
975 'unit' => '%',
976 ],
977 'tablet_default' => [
978 'unit' => '%',
979 ],
980 'mobile_default' => [
981 'unit' => '%',
982 ],
983 'range' => [
984 '%' => [
985 'min' => 100,
986 'max' => 300,
987 ],
988 'vw' => [
989 'min' => 100,
990 'max' => 300,
991 ],
992 ],
993 'condition' => [
994 "shape_divider_$side" => array_keys( Shapes::filter_shapes( 'height_only', Shapes::FILTER_EXCLUDE ) ),
995 ],
996 'selectors' => [
997 "{{WRAPPER}} > .elementor-shape-$side svg" => 'width: calc({{SIZE}}{{UNIT}} + 1.3px)',
998 ],
999 ]
1000 );
1001
1002 $this->add_responsive_control(
1003 $base_control_key . '_height',
1004 [
1005 'label' => esc_html__( 'Height', 'elementor' ),
1006 'type' => Controls_Manager::SLIDER,
1007 'size_units' => [ 'px', 'em', 'rem', 'custom' ],
1008 'range' => [
1009 'px' => [
1010 'max' => 500,
1011 ],
1012 'em' => [
1013 'max' => 50,
1014 ],
1015 'rem' => [
1016 'max' => 50,
1017 ],
1018 ],
1019 'condition' => [
1020 "shape_divider_$side!" => '',
1021 ],
1022 'selectors' => [
1023 "{{WRAPPER}} > .elementor-shape-$side svg" => 'height: {{SIZE}}{{UNIT}};',
1024 ],
1025 ]
1026 );
1027
1028 $this->add_control(
1029 $base_control_key . '_flip',
1030 [
1031 'label' => esc_html__( 'Flip', 'elementor' ),
1032 'type' => Controls_Manager::SWITCHER,
1033 'condition' => [
1034 "shape_divider_$side" => array_keys( Shapes::filter_shapes( 'has_flip' ) ),
1035 ],
1036 'selectors' => [
1037 "{{WRAPPER}} > .elementor-shape-$side svg" => 'transform: translateX(-50%) rotateY(180deg)',
1038 ],
1039 ]
1040 );
1041
1042 $this->add_control(
1043 $base_control_key . '_negative',
1044 [
1045 'label' => esc_html__( 'Invert', 'elementor' ),
1046 'type' => Controls_Manager::SWITCHER,
1047 'frontend_available' => true,
1048 'condition' => [
1049 "shape_divider_$side" => array_keys( Shapes::filter_shapes( 'has_negative' ) ),
1050 ],
1051 'render_type' => 'none',
1052 ]
1053 );
1054
1055 $this->add_control(
1056 $base_control_key . '_above_content',
1057 [
1058 'label' => esc_html__( 'Bring to Front', 'elementor' ),
1059 'type' => Controls_Manager::SWITCHER,
1060 'selectors' => [
1061 "{{WRAPPER}} > .elementor-shape-$side" => 'z-index: 2; pointer-events: none',
1062 ],
1063 'condition' => [
1064 "shape_divider_$side!" => '',
1065 ],
1066 ]
1067 );
1068
1069 $this->end_controls_tab();
1070 }
1071
1072 $this->end_controls_tabs();
1073
1074 $this->end_controls_section();
1075
1076 // Section Typography
1077 $this->start_controls_section(
1078 'section_typo',
1079 [
1080 'label' => esc_html__( 'Typography', 'elementor' ),
1081 'tab' => Controls_Manager::TAB_STYLE,
1082 ]
1083 );
1084
1085 $this->add_control(
1086 'heading_color',
1087 [
1088 'label' => esc_html__( 'Heading Color', 'elementor' ),
1089 'type' => Controls_Manager::COLOR,
1090 'default' => '',
1091 'selectors' => [
1092 '{{WRAPPER}} .elementor-heading-title' => 'color: {{VALUE}};',
1093 ],
1094 ]
1095 );
1096
1097 $this->add_control(
1098 'color_text',
1099 [
1100 'label' => esc_html__( 'Text Color', 'elementor' ),
1101 'type' => Controls_Manager::COLOR,
1102 'default' => '',
1103 'selectors' => [
1104 '{{WRAPPER}}' => 'color: {{VALUE}};',
1105 ],
1106 ]
1107 );
1108
1109 $this->add_control(
1110 'color_link',
1111 [
1112 'label' => esc_html__( 'Link Color', 'elementor' ),
1113 'type' => Controls_Manager::COLOR,
1114 'default' => '',
1115 'selectors' => [
1116 '{{WRAPPER}} a' => 'color: {{VALUE}};',
1117 ],
1118 ]
1119 );
1120
1121 $this->add_control(
1122 'color_link_hover',
1123 [
1124 'label' => esc_html__( 'Link Hover Color', 'elementor' ),
1125 'type' => Controls_Manager::COLOR,
1126 'default' => '',
1127 'selectors' => [
1128 '{{WRAPPER}} a:hover' => 'color: {{VALUE}};',
1129 ],
1130 ]
1131 );
1132
1133 $this->add_responsive_control(
1134 'text_align',
1135 [
1136 'label' => esc_html__( 'Text Align', 'elementor' ),
1137 'type' => Controls_Manager::CHOOSE,
1138 'options' => [
1139 'left' => [
1140 'title' => esc_html__( 'Left', 'elementor' ),
1141 'icon' => 'eicon-text-align-left',
1142 ],
1143 'center' => [
1144 'title' => esc_html__( 'Center', 'elementor' ),
1145 'icon' => 'eicon-text-align-center',
1146 ],
1147 'right' => [
1148 'title' => esc_html__( 'Right', 'elementor' ),
1149 'icon' => 'eicon-text-align-right',
1150 ],
1151 'justify' => [
1152 'title' => esc_html__( 'Justified', 'elementor' ),
1153 'icon' => 'eicon-text-align-justify',
1154 ],
1155 ],
1156 'selectors' => [
1157 '{{WRAPPER}} > .elementor-container' => 'text-align: {{VALUE}};',
1158 ],
1159 ]
1160 );
1161
1162 $this->end_controls_section();
1163
1164 // Section Advanced
1165 $this->start_controls_section(
1166 'section_advanced',
1167 [
1168 'label' => esc_html__( 'Advanced', 'elementor' ),
1169 'tab' => Controls_Manager::TAB_ADVANCED,
1170 ]
1171 );
1172
1173 $this->add_responsive_control(
1174 'margin',
1175 [
1176 'label' => esc_html__( 'Margin', 'elementor' ),
1177 'type' => Controls_Manager::DIMENSIONS,
1178 'size_units' => [ 'px', '%', 'em', 'rem', 'vw', 'custom' ],
1179 'allowed_dimensions' => 'vertical',
1180 'placeholder' => [
1181 'top' => '',
1182 'right' => 'auto',
1183 'bottom' => '',
1184 'left' => 'auto',
1185 ],
1186 'selectors' => [
1187 '{{WRAPPER}}' => 'margin-top: {{TOP}}{{UNIT}}; margin-bottom: {{BOTTOM}}{{UNIT}};',
1188 ],
1189 ]
1190 );
1191
1192 $this->add_responsive_control(
1193 'padding',
1194 [
1195 'label' => esc_html__( 'Padding', 'elementor' ),
1196 'type' => Controls_Manager::DIMENSIONS,
1197 'size_units' => [ 'px', '%', 'em', 'rem', 'vw', 'custom' ],
1198 'selectors' => [
1199 '{{WRAPPER}}' => 'padding: {{TOP}}{{UNIT}} {{RIGHT}}{{UNIT}} {{BOTTOM}}{{UNIT}} {{LEFT}}{{UNIT}};',
1200 ],
1201 ]
1202 );
1203
1204 $this->add_responsive_control(
1205 'z_index',
1206 [
1207 'label' => esc_html__( 'Z-Index', 'elementor' ),
1208 'type' => Controls_Manager::NUMBER,
1209 'min' => 0,
1210 'selectors' => [
1211 '{{WRAPPER}}' => 'z-index: {{VALUE}};',
1212 ],
1213 ]
1214 );
1215
1216 $this->add_control(
1217 '_element_id',
1218 [
1219 'label' => esc_html__( 'CSS ID', 'elementor' ),
1220 'type' => Controls_Manager::TEXT,
1221 'default' => '',
1222 'ai' => [
1223 'active' => false,
1224 ],
1225 'dynamic' => [
1226 'active' => true,
1227 ],
1228 'title' => esc_html__( 'Add your custom id WITHOUT the Pound key. e.g: my-id', 'elementor' ),
1229 'style_transfer' => false,
1230 'classes' => 'elementor-control-direction-ltr',
1231 ]
1232 );
1233
1234 $this->add_control(
1235 'css_classes',
1236 [
1237 'label' => esc_html__( 'CSS Classes', 'elementor' ),
1238 'type' => Controls_Manager::TEXT,
1239 'default' => '',
1240 'ai' => [
1241 'active' => false,
1242 ],
1243 'dynamic' => [
1244 'active' => true,
1245 ],
1246 'prefix_class' => '',
1247 'title' => esc_html__( 'Add your custom class WITHOUT the dot. e.g: my-class', 'elementor' ),
1248 'classes' => 'elementor-control-direction-ltr',
1249 ]
1250 );
1251
1252 Plugin::$instance->controls_manager->add_display_conditions_controls( $this );
1253
1254 $this->end_controls_section();
1255
1256 $this->start_controls_section(
1257 'section_effects',
1258 [
1259 'label' => esc_html__( 'Motion Effects', 'elementor' ),
1260 'tab' => Controls_Manager::TAB_ADVANCED,
1261 ]
1262 );
1263
1264 Plugin::$instance->controls_manager->add_motion_effects_promotion_control( $this );
1265
1266 $this->add_responsive_control(
1267 'animation',
1268 [
1269 'label' => esc_html__( 'Entrance Animation', 'elementor' ),
1270 'type' => Controls_Manager::ANIMATION,
1271 'frontend_available' => true,
1272 ]
1273 );
1274
1275 $this->add_control(
1276 'animation_duration',
1277 [
1278 'label' => esc_html__( 'Animation Duration', 'elementor' ),
1279 'type' => Controls_Manager::SELECT,
1280 'default' => '',
1281 'options' => [
1282 'slow' => esc_html__( 'Slow', 'elementor' ),
1283 '' => esc_html__( 'Normal', 'elementor' ),
1284 'fast' => esc_html__( 'Fast', 'elementor' ),
1285 ],
1286 'prefix_class' => 'animated-',
1287 'condition' => [
1288 'animation!' => '',
1289 ],
1290 ]
1291 );
1292
1293 $this->add_control(
1294 'animation_delay',
1295 [
1296 'label' => esc_html__( 'Animation Delay', 'elementor' ) . ' (ms)',
1297 'type' => Controls_Manager::NUMBER,
1298 'default' => '',
1299 'min' => 0,
1300 'step' => 100,
1301 'condition' => [
1302 'animation!' => '',
1303 ],
1304 'render_type' => 'none',
1305 'frontend_available' => true,
1306 ]
1307 );
1308
1309 $this->end_controls_section();
1310
1311 // Section Responsive
1312 $this->start_controls_section(
1313 '_section_responsive',
1314 [
1315 'label' => esc_html__( 'Responsive', 'elementor' ),
1316 'tab' => Controls_Manager::TAB_ADVANCED,
1317 ]
1318 );
1319
1320 // The controls should be displayed from largest to smallest breakpoint, so we reverse the array.
1321 $active_breakpoints = array_reverse( Plugin::$instance->breakpoints->get_active_breakpoints() );
1322
1323 foreach ( $active_breakpoints as $breakpoint_key => $breakpoint ) {
1324 $this->add_control(
1325 'reverse_order_' . $breakpoint_key,
1326 [
1327 'label' => esc_html__( 'Reverse Columns', 'elementor' ) . ' (' . $breakpoint->get_label() . ')',
1328 'type' => Controls_Manager::SWITCHER,
1329 'default' => '',
1330 'prefix_class' => 'elementor-',
1331 'return_value' => 'reverse-' . $breakpoint_key,
1332 ]
1333 );
1334 }
1335
1336 $this->add_control(
1337 'heading_visibility',
1338 [
1339 'label' => esc_html__( 'Visibility', 'elementor' ),
1340 'type' => Controls_Manager::HEADING,
1341 'separator' => 'before',
1342 ]
1343 );
1344
1345 $this->add_control(
1346 'responsive_description',
1347 [
1348 'raw' => sprintf(
1349 /* translators: 1: Link open tag, 2: Link close tag. */
1350 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' ),
1351 '<a href="javascript: $e.run( \'panel/close\' )">',
1352 '</a>'
1353 ),
1354 'type' => Controls_Manager::RAW_HTML,
1355 'content_classes' => 'elementor-descriptor',
1356 ]
1357 );
1358
1359 $this->add_hidden_device_controls();
1360
1361 $this->end_controls_section();
1362
1363 Plugin::$instance->controls_manager->add_custom_attributes_controls( $this );
1364
1365 Plugin::$instance->controls_manager->add_custom_css_controls( $this );
1366 }
1367
1368 /**
1369 * Render section output in the editor.
1370 *
1371 * Used to generate the live preview, using a Backbone JavaScript template.
1372 *
1373 * @since 2.9.0
1374 * @access protected
1375 */
1376 protected function content_template() {
1377 ?>
1378 <#
1379 if ( settings.background_video_link ) {
1380 let videoAttributes = 'autoplay muted playsinline';
1381
1382 if ( ! settings.background_play_once ) {
1383 videoAttributes += ' loop';
1384 }
1385
1386 view.addRenderAttribute( 'background-video-container', 'class', 'elementor-background-video-container' );
1387
1388 if ( ! settings.background_play_on_mobile ) {
1389 view.addRenderAttribute( 'background-video-container', 'class', 'elementor-hidden-mobile' );
1390 }
1391 #>
1392 <div {{{ view.getRenderAttributeString( 'background-video-container' ) }}}>
1393 <div class="elementor-background-video-embed"></div>
1394 <video class="elementor-background-video-hosted elementor-html5-video" {{ videoAttributes }}></video>
1395 </div>
1396 <# } #>
1397 <div class="elementor-background-overlay"></div>
1398 <div class="elementor-shape elementor-shape-top"></div>
1399 <div class="elementor-shape elementor-shape-bottom"></div>
1400 <div class="elementor-container elementor-column-gap-{{ settings.gap }}"></div>
1401 <?php
1402 }
1403
1404 /**
1405 * Before section rendering.
1406 *
1407 * Used to add stuff before the section element.
1408 *
1409 * @since 1.0.0
1410 * @access public
1411 */
1412 public function before_render() {
1413 $settings = $this->get_settings_for_display();
1414 ?>
1415 <<?php
1416 // PHPCS - the method get_html_tag is safe.
1417 echo $this->get_html_tag(); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
1418 ?> <?php $this->print_render_attribute_string( '_wrapper' ); ?>>
1419 <?php
1420 if ( 'video' === $settings['background_background'] ) :
1421 if ( $settings['background_video_link'] ) :
1422 $video_properties = Embed::get_video_properties( $settings['background_video_link'] );
1423
1424 $this->add_render_attribute( 'background-video-container', 'class', 'elementor-background-video-container' );
1425
1426 if ( ! $settings['background_play_on_mobile'] ) {
1427 $this->add_render_attribute( 'background-video-container', 'class', 'elementor-hidden-phone' );
1428 }
1429 ?>
1430 <div <?php $this->print_render_attribute_string( 'background-video-container' ); ?>>
1431 <?php if ( $video_properties ) : ?>
1432 <div class="elementor-background-video-embed"></div>
1433 <?php
1434 else :
1435 $video_tag_attributes = 'autoplay muted playsinline';
1436 if ( 'yes' !== $settings['background_play_once'] ) :
1437 $video_tag_attributes .= ' loop';
1438 endif;
1439 ?>
1440 <video class="elementor-background-video-hosted elementor-html5-video" <?php
1441 // PHPCS - the variable $video_tag_attributes is a plain string.
1442 echo $video_tag_attributes; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
1443 ?>></video>
1444 <?php endif; ?>
1445 </div>
1446 <?php
1447 endif;
1448 endif;
1449
1450 $overlay_background = $settings['background_overlay_background'] ?? '';
1451 $overlay_hover_background = $settings['background_overlay_hover_background'] ?? '';
1452
1453 $has_background_overlay = in_array( $overlay_background, [ 'classic', 'gradient' ], true ) ||
1454 in_array( $overlay_hover_background, [ 'classic', 'gradient' ], true );
1455
1456 if ( $has_background_overlay ) :
1457 ?>
1458 <div class="elementor-background-overlay"></div>
1459 <?php
1460 endif;
1461
1462 if ( $settings['shape_divider_top'] ) {
1463 $this->print_shape_divider( 'top' );
1464 }
1465
1466 if ( $settings['shape_divider_bottom'] ) {
1467 $this->print_shape_divider( 'bottom' );
1468 }
1469 ?>
1470 <div class="elementor-container elementor-column-gap-<?php echo esc_attr( $settings['gap'] ); ?>">
1471 <?php
1472 }
1473
1474 /**
1475 * After section rendering.
1476 *
1477 * Used to add stuff after the section element.
1478 *
1479 * @since 1.0.0
1480 * @access public
1481 */
1482 public function after_render() {
1483 ?>
1484 </div>
1485 </<?php
1486 // PHPCS - the method get_html_tag is safe.
1487 echo $this->get_html_tag(); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
1488 ?>>
1489 <?php
1490 }
1491
1492 /**
1493 * Add section render attributes.
1494 *
1495 * Used to add attributes to the current section wrapper HTML tag.
1496 *
1497 * @since 1.3.0
1498 * @access protected
1499 */
1500 protected function add_render_attributes() {
1501
1502 $section_type = $this->get_data( 'isInner' ) ? 'inner' : 'top';
1503
1504 $this->add_render_attribute(
1505 '_wrapper', 'class', [
1506 'elementor-section',
1507 'elementor-' . $section_type . '-section',
1508 ]
1509 );
1510
1511 parent::add_render_attributes();
1512 }
1513
1514 /**
1515 * Get default child type.
1516 *
1517 * Retrieve the section child type based on element data.
1518 *
1519 * @since 1.0.0
1520 * @access protected
1521 *
1522 * @param array $element_data Element ID.
1523 *
1524 * @return Element_Base Section default child type.
1525 */
1526 protected function _get_default_child_type( array $element_data ) {
1527 return Plugin::$instance->elements_manager->get_element_types( 'column' );
1528 }
1529
1530 /**
1531 * Get HTML tag.
1532 *
1533 * Retrieve the section element HTML tag.
1534 *
1535 * @since 1.5.3
1536 * @access private
1537 *
1538 * @return string Section HTML tag.
1539 */
1540 protected function get_html_tag() {
1541 $html_tag = $this->get_settings( 'html_tag' );
1542
1543 if ( empty( $html_tag ) ) {
1544 $html_tag = 'section';
1545 }
1546
1547 return Utils::validate_html_tag( $html_tag );
1548 }
1549
1550 /**
1551 * Print section shape divider.
1552 *
1553 * Used to generate the shape dividers HTML.
1554 *
1555 * @since 1.3.0
1556 * @access private
1557 *
1558 * @param string $side Shape divider side, used to set the shape key.
1559 */
1560 protected function print_shape_divider( $side ) {
1561 $settings = $this->get_active_settings();
1562 $base_setting_key = "shape_divider_$side";
1563 $negative = ! empty( $settings[ $base_setting_key . '_negative' ] );
1564 $shape_path = Shapes::get_shape_path( $settings[ $base_setting_key ], $negative );
1565 if ( ! is_file( $shape_path ) || ! is_readable( $shape_path ) ) {
1566 return;
1567 }
1568
1569 ?>
1570 <div class="elementor-shape elementor-shape-<?php echo esc_attr( $side ); ?>" data-negative="<?php
1571 Utils::print_unescaped_internal_string( $negative ? 'true' : 'false' );
1572 ?>">
1573 <?php
1574 // PHPCS - The file content is being read from a strict file path structure.
1575 echo Utils::file_get_contents( $shape_path ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
1576 ?>
1577 </div>
1578 <?php
1579 }
1580 }
1581