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

section.php in Elementor Website Builder – more than just a page builder 3.20.3, 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 'image' => [
553 'background_lazyload' => [
554 'active' => true,
555 'keys' => [ 'background_image', 'url' ],
556 ],
557 ],
558 ],
559 ]
560 );
561
562 $this->end_controls_tab();
563
564 $this->start_controls_tab(
565 'tab_background_hover',
566 [
567 'label' => esc_html__( 'Hover', 'elementor' ),
568 ]
569 );
570
571 $this->add_group_control(
572 Group_Control_Background::get_type(),
573 [
574 'name' => 'background_hover',
575 'selector' => '{{WRAPPER}}:hover',
576 ]
577 );
578
579 $this->add_control(
580 'background_hover_transition',
581 [
582 'label' => esc_html__( 'Transition Duration', 'elementor' ) . ' (s)',
583 'type' => Controls_Manager::SLIDER,
584 'default' => [
585 'size' => 0.3,
586 ],
587 'range' => [
588 'px' => [
589 'min' => 0,
590 'max' => 3,
591 'step' => 0.1,
592 ],
593 ],
594 'render_type' => 'ui',
595 'separator' => 'before',
596 ]
597 );
598
599 $this->end_controls_tab();
600
601 $this->end_controls_tabs();
602
603 $this->end_controls_section();
604
605 // Background Overlay
606 $this->start_controls_section(
607 'section_background_overlay',
608 [
609 'label' => esc_html__( 'Background Overlay', 'elementor' ),
610 'tab' => Controls_Manager::TAB_STYLE,
611 ]
612 );
613
614 $this->start_controls_tabs( 'tabs_background_overlay' );
615
616 $this->start_controls_tab(
617 'tab_background_overlay_normal',
618 [
619 'label' => esc_html__( 'Normal', 'elementor' ),
620 ]
621 );
622
623 $this->add_group_control(
624 Group_Control_Background::get_type(),
625 [
626 'name' => 'background_overlay',
627 'selector' => '{{WRAPPER}} > .elementor-background-overlay',
628 'fields_options' => [
629 'image' => [
630 'background_lazyload' => [
631 'active' => true,
632 'keys' => [ 'background_overlay_image', 'url' ],
633 'selector' => '.elementor-background-overlay',
634 ],
635 ],
636 ],
637 ]
638 );
639
640 $this->add_responsive_control(
641 'background_overlay_opacity',
642 [
643 'label' => esc_html__( 'Opacity', 'elementor' ),
644 'type' => Controls_Manager::SLIDER,
645 'default' => [
646 'size' => .5,
647 ],
648 'range' => [
649 'px' => [
650 'max' => 1,
651 'step' => 0.01,
652 ],
653 ],
654 'selectors' => [
655 '{{WRAPPER}} > .elementor-background-overlay' => 'opacity: {{SIZE}};',
656 ],
657 'condition' => [
658 'background_overlay_background' => [ 'classic', 'gradient' ],
659 ],
660 ]
661 );
662
663 $this->add_group_control(
664 Group_Control_Css_Filter::get_type(),
665 [
666 'name' => 'css_filters',
667 'selector' => '{{WRAPPER}} .elementor-background-overlay',
668 'conditions' => [
669 'relation' => 'or',
670 'terms' => [
671 [
672 'name' => 'background_overlay_image[url]',
673 'operator' => '!==',
674 'value' => '',
675 ],
676 [
677 'name' => 'background_overlay_color',
678 'operator' => '!==',
679 'value' => '',
680 ],
681 ],
682 ],
683 ]
684 );
685
686 $this->add_control(
687 'overlay_blend_mode',
688 [
689 'label' => esc_html__( 'Blend Mode', 'elementor' ),
690 'type' => Controls_Manager::SELECT,
691 'options' => [
692 '' => esc_html__( 'Normal', 'elementor' ),
693 'multiply' => esc_html__( 'Multiply', 'elementor' ),
694 'screen' => esc_html__( 'Screen', 'elementor' ),
695 'overlay' => esc_html__( 'Overlay', 'elementor' ),
696 'darken' => esc_html__( 'Darken', 'elementor' ),
697 'lighten' => esc_html__( 'Lighten', 'elementor' ),
698 'color-dodge' => esc_html__( 'Color Dodge', 'elementor' ),
699 'saturation' => esc_html__( 'Saturation', 'elementor' ),
700 'color' => esc_html__( 'Color', 'elementor' ),
701 'luminosity' => esc_html__( 'Luminosity', 'elementor' ),
702 'difference' => esc_html__( 'Difference', 'elementor' ),
703 'exclusion' => esc_html__( 'Exclusion', 'elementor' ),
704 'hue' => esc_html__( 'Hue', 'elementor' ),
705 ],
706 'selectors' => [
707 '{{WRAPPER}} > .elementor-background-overlay' => 'mix-blend-mode: {{VALUE}}',
708 ],
709 'conditions' => [
710 'relation' => 'or',
711 'terms' => [
712 [
713 'name' => 'background_overlay_image[url]',
714 'operator' => '!==',
715 'value' => '',
716 ],
717 [
718 'name' => 'background_overlay_color',
719 'operator' => '!==',
720 'value' => '',
721 ],
722 ],
723 ],
724 ]
725 );
726
727 $this->end_controls_tab();
728
729 $this->start_controls_tab(
730 'tab_background_overlay_hover',
731 [
732 'label' => esc_html__( 'Hover', 'elementor' ),
733 ]
734 );
735
736 $this->add_group_control(
737 Group_Control_Background::get_type(),
738 [
739 'name' => 'background_overlay_hover',
740 'selector' => '{{WRAPPER}}:hover > .elementor-background-overlay',
741 ]
742 );
743
744 $this->add_responsive_control(
745 'background_overlay_hover_opacity',
746 [
747 'label' => esc_html__( 'Opacity', 'elementor' ),
748 'type' => Controls_Manager::SLIDER,
749 'default' => [
750 'size' => .5,
751 ],
752 'range' => [
753 'px' => [
754 'max' => 1,
755 'step' => 0.01,
756 ],
757 ],
758 'selectors' => [
759 '{{WRAPPER}}:hover > .elementor-background-overlay' => 'opacity: {{SIZE}};',
760 ],
761 'condition' => [
762 'background_overlay_hover_background' => [ 'classic', 'gradient' ],
763 ],
764 ]
765 );
766
767 $this->add_group_control(
768 Group_Control_Css_Filter::get_type(),
769 [
770 'name' => 'css_filters_hover',
771 'selector' => '{{WRAPPER}}:hover > .elementor-background-overlay',
772 ]
773 );
774
775 $this->add_control(
776 'background_overlay_hover_transition',
777 [
778 'label' => esc_html__( 'Transition Duration', 'elementor' ) . ' (s)',
779 'type' => Controls_Manager::SLIDER,
780 'default' => [
781 'size' => 0.3,
782 ],
783 'range' => [
784 'px' => [
785 'min' => 0,
786 'max' => 3,
787 'step' => 0.1,
788 ],
789 ],
790 'render_type' => 'ui',
791 'separator' => 'before',
792 ]
793 );
794
795 $this->end_controls_tab();
796
797 $this->end_controls_tabs();
798
799 $this->end_controls_section();
800
801 // Section border
802 $this->start_controls_section(
803 'section_border',
804 [
805 'label' => esc_html__( 'Border', 'elementor' ),
806 'tab' => Controls_Manager::TAB_STYLE,
807 ]
808 );
809
810 $this->start_controls_tabs( 'tabs_border' );
811
812 $this->start_controls_tab(
813 'tab_border_normal',
814 [
815 'label' => esc_html__( 'Normal', 'elementor' ),
816 ]
817 );
818
819 $this->add_group_control(
820 Group_Control_Border::get_type(),
821 [
822 'name' => 'border',
823 ]
824 );
825
826 $this->add_responsive_control(
827 'border_radius',
828 [
829 'label' => esc_html__( 'Border Radius', 'elementor' ),
830 'type' => Controls_Manager::DIMENSIONS,
831 'size_units' => [ 'px', '%', 'em', 'rem', 'custom' ],
832 'selectors' => [
833 '{{WRAPPER}}, {{WRAPPER}} > .elementor-background-overlay' => 'border-radius: {{TOP}}{{UNIT}} {{RIGHT}}{{UNIT}} {{BOTTOM}}{{UNIT}} {{LEFT}}{{UNIT}};',
834 ],
835 ]
836 );
837
838 $this->add_group_control(
839 Group_Control_Box_Shadow::get_type(),
840 [
841 'name' => 'box_shadow',
842 ]
843 );
844
845 $this->end_controls_tab();
846
847 $this->start_controls_tab(
848 'tab_border_hover',
849 [
850 'label' => esc_html__( 'Hover', 'elementor' ),
851 ]
852 );
853
854 $this->add_group_control(
855 Group_Control_Border::get_type(),
856 [
857 'name' => 'border_hover',
858 'selector' => '{{WRAPPER}}:hover',
859 ]
860 );
861
862 $this->add_responsive_control(
863 'border_radius_hover',
864 [
865 'label' => esc_html__( 'Border Radius', 'elementor' ),
866 'type' => Controls_Manager::DIMENSIONS,
867 'size_units' => [ 'px', '%', 'em', 'rem', 'custom' ],
868 'selectors' => [
869 '{{WRAPPER}}:hover, {{WRAPPER}}:hover > .elementor-background-overlay' => 'border-radius: {{TOP}}{{UNIT}} {{RIGHT}}{{UNIT}} {{BOTTOM}}{{UNIT}} {{LEFT}}{{UNIT}};',
870 ],
871 ]
872 );
873
874 $this->add_group_control(
875 Group_Control_Box_Shadow::get_type(),
876 [
877 'name' => 'box_shadow_hover',
878 'selector' => '{{WRAPPER}}:hover',
879 ]
880 );
881
882 $this->add_control(
883 'border_hover_transition',
884 [
885 'label' => esc_html__( 'Transition Duration', 'elementor' ) . ' (s)',
886 'type' => Controls_Manager::SLIDER,
887 'separator' => 'before',
888 'default' => [
889 'size' => 0.3,
890 ],
891 'range' => [
892 'px' => [
893 'min' => 0,
894 'max' => 3,
895 'step' => 0.1,
896 ],
897 ],
898 'conditions' => [
899 'relation' => 'or',
900 'terms' => [
901 [
902 'name' => 'background_background',
903 'operator' => '!==',
904 'value' => '',
905 ],
906 [
907 'name' => 'border_border',
908 'operator' => '!==',
909 'value' => '',
910 ],
911 ],
912 ],
913 'selectors' => [
914 '{{WRAPPER}}' => 'transition: background {{background_hover_transition.SIZE}}s, border {{SIZE}}s, border-radius {{SIZE}}s, box-shadow {{SIZE}}s',
915 '{{WRAPPER}} > .elementor-background-overlay' => 'transition: background {{background_overlay_hover_transition.SIZE}}s, border-radius {{SIZE}}s, opacity {{background_overlay_hover_transition.SIZE}}s',
916 ],
917 ]
918 );
919
920 $this->end_controls_tab();
921
922 $this->end_controls_tabs();
923
924 $this->end_controls_section();
925
926 // Section Shape Divider
927 $this->start_controls_section(
928 'section_shape_divider',
929 [
930 'label' => esc_html__( 'Shape Divider', 'elementor' ),
931 'tab' => Controls_Manager::TAB_STYLE,
932 ]
933 );
934
935 $this->start_controls_tabs( 'tabs_shape_dividers' );
936
937 $shapes_options = [
938 '' => esc_html__( 'None', 'elementor' ),
939 ];
940
941 foreach ( Shapes::get_shapes() as $shape_name => $shape_props ) {
942 $shapes_options[ $shape_name ] = $shape_props['title'];
943 }
944
945 foreach ( [
946 'top' => esc_html__( 'Top', 'elementor' ),
947 'bottom' => esc_html__( 'Bottom', 'elementor' ),
948 ] as $side => $side_label ) {
949 $base_control_key = "shape_divider_$side";
950
951 $this->start_controls_tab(
952 "tab_$base_control_key",
953 [
954 'label' => $side_label,
955 ]
956 );
957
958 $this->add_control(
959 $base_control_key,
960 [
961 'label' => esc_html__( 'Type', 'elementor' ),
962 'type' => Controls_Manager::SELECT,
963 'options' => $shapes_options,
964 'render_type' => 'none',
965 'frontend_available' => true,
966 ]
967 );
968
969 $this->add_control(
970 $base_control_key . '_color',
971 [
972 'label' => esc_html__( 'Color', 'elementor' ),
973 'type' => Controls_Manager::COLOR,
974 'condition' => [
975 "shape_divider_$side!" => '',
976 ],
977 'selectors' => [
978 "{{WRAPPER}} > .elementor-shape-$side .elementor-shape-fill" => 'fill: {{UNIT}};',
979 ],
980 ]
981 );
982
983 $this->add_responsive_control(
984 $base_control_key . '_width',
985 [
986 'label' => esc_html__( 'Width', 'elementor' ) . ' (%)',
987 'type' => Controls_Manager::SLIDER,
988 'default' => [
989 'unit' => '%',
990 ],
991 'tablet_default' => [
992 'unit' => '%',
993 ],
994 'mobile_default' => [
995 'unit' => '%',
996 ],
997 'range' => [
998 '%' => [
999 'min' => 100,
1000 'max' => 300,
1001 ],
1002 ],
1003 'condition' => [
1004 "shape_divider_$side" => array_keys( Shapes::filter_shapes( 'height_only', Shapes::FILTER_EXCLUDE ) ),
1005 ],
1006 'selectors' => [
1007 "{{WRAPPER}} > .elementor-shape-$side svg" => 'width: calc({{SIZE}}{{UNIT}} + 1.3px)',
1008 ],
1009 ]
1010 );
1011
1012 $this->add_responsive_control(
1013 $base_control_key . '_height',
1014 [
1015 'label' => esc_html__( 'Height', 'elementor' ),
1016 'type' => Controls_Manager::SLIDER,
1017 'range' => [
1018 'px' => [
1019 'max' => 500,
1020 ],
1021 ],
1022 'condition' => [
1023 "shape_divider_$side!" => '',
1024 ],
1025 'selectors' => [
1026 "{{WRAPPER}} > .elementor-shape-$side svg" => 'height: {{SIZE}}{{UNIT}};',
1027 ],
1028 ]
1029 );
1030
1031 $this->add_control(
1032 $base_control_key . '_flip',
1033 [
1034 'label' => esc_html__( 'Flip', 'elementor' ),
1035 'type' => Controls_Manager::SWITCHER,
1036 'condition' => [
1037 "shape_divider_$side" => array_keys( Shapes::filter_shapes( 'has_flip' ) ),
1038 ],
1039 'selectors' => [
1040 "{{WRAPPER}} > .elementor-shape-$side svg" => 'transform: translateX(-50%) rotateY(180deg)',
1041 ],
1042 ]
1043 );
1044
1045 $this->add_control(
1046 $base_control_key . '_negative',
1047 [
1048 'label' => esc_html__( 'Invert', 'elementor' ),
1049 'type' => Controls_Manager::SWITCHER,
1050 'frontend_available' => true,
1051 'condition' => [
1052 "shape_divider_$side" => array_keys( Shapes::filter_shapes( 'has_negative' ) ),
1053 ],
1054 'render_type' => 'none',
1055 ]
1056 );
1057
1058 $this->add_control(
1059 $base_control_key . '_above_content',
1060 [
1061 'label' => esc_html__( 'Bring to Front', 'elementor' ),
1062 'type' => Controls_Manager::SWITCHER,
1063 'selectors' => [
1064 "{{WRAPPER}} > .elementor-shape-$side" => 'z-index: 2; pointer-events: none',
1065 ],
1066 'condition' => [
1067 "shape_divider_$side!" => '',
1068 ],
1069 ]
1070 );
1071
1072 $this->end_controls_tab();
1073 }
1074
1075 $this->end_controls_tabs();
1076
1077 $this->end_controls_section();
1078
1079 // Section Typography
1080 $this->start_controls_section(
1081 'section_typo',
1082 [
1083 'label' => esc_html__( 'Typography', 'elementor' ),
1084 'tab' => Controls_Manager::TAB_STYLE,
1085 ]
1086 );
1087
1088 $this->add_control(
1089 'heading_color',
1090 [
1091 'label' => esc_html__( 'Heading Color', 'elementor' ),
1092 'type' => Controls_Manager::COLOR,
1093 'default' => '',
1094 'selectors' => [
1095 '{{WRAPPER}} .elementor-heading-title' => 'color: {{VALUE}};',
1096 ],
1097 ]
1098 );
1099
1100 $this->add_control(
1101 'color_text',
1102 [
1103 'label' => esc_html__( 'Text Color', 'elementor' ),
1104 'type' => Controls_Manager::COLOR,
1105 'default' => '',
1106 'selectors' => [
1107 '{{WRAPPER}}' => 'color: {{VALUE}};',
1108 ],
1109 ]
1110 );
1111
1112 $this->add_control(
1113 'color_link',
1114 [
1115 'label' => esc_html__( 'Link Color', 'elementor' ),
1116 'type' => Controls_Manager::COLOR,
1117 'default' => '',
1118 'selectors' => [
1119 '{{WRAPPER}} a' => 'color: {{VALUE}};',
1120 ],
1121 ]
1122 );
1123
1124 $this->add_control(
1125 'color_link_hover',
1126 [
1127 'label' => esc_html__( 'Link Hover Color', 'elementor' ),
1128 'type' => Controls_Manager::COLOR,
1129 'default' => '',
1130 'selectors' => [
1131 '{{WRAPPER}} a:hover' => 'color: {{VALUE}};',
1132 ],
1133 ]
1134 );
1135
1136 $this->add_responsive_control(
1137 'text_align',
1138 [
1139 'label' => esc_html__( 'Text Align', 'elementor' ),
1140 'type' => Controls_Manager::CHOOSE,
1141 'options' => [
1142 'left' => [
1143 'title' => esc_html__( 'Left', 'elementor' ),
1144 'icon' => 'eicon-text-align-left',
1145 ],
1146 'center' => [
1147 'title' => esc_html__( 'Center', 'elementor' ),
1148 'icon' => 'eicon-text-align-center',
1149 ],
1150 'right' => [
1151 'title' => esc_html__( 'Right', 'elementor' ),
1152 'icon' => 'eicon-text-align-right',
1153 ],
1154 'justify' => [
1155 'title' => esc_html__( 'Justified', 'elementor' ),
1156 'icon' => 'eicon-text-align-justify',
1157 ],
1158 ],
1159 'selectors' => [
1160 '{{WRAPPER}} > .elementor-container' => 'text-align: {{VALUE}};',
1161 ],
1162 ]
1163 );
1164
1165 $this->end_controls_section();
1166
1167 // Section Advanced
1168 $this->start_controls_section(
1169 'section_advanced',
1170 [
1171 'label' => esc_html__( 'Advanced', 'elementor' ),
1172 'tab' => Controls_Manager::TAB_ADVANCED,
1173 ]
1174 );
1175
1176 $this->add_responsive_control(
1177 'margin',
1178 [
1179 'label' => esc_html__( 'Margin', 'elementor' ),
1180 'type' => Controls_Manager::DIMENSIONS,
1181 'size_units' => [ 'px', '%', 'em', 'rem', 'vw', 'custom' ],
1182 'allowed_dimensions' => 'vertical',
1183 'placeholder' => [
1184 'top' => '',
1185 'right' => 'auto',
1186 'bottom' => '',
1187 'left' => 'auto',
1188 ],
1189 'selectors' => [
1190 '{{WRAPPER}}' => 'margin-top: {{TOP}}{{UNIT}}; margin-bottom: {{BOTTOM}}{{UNIT}};',
1191 ],
1192 ]
1193 );
1194
1195 $this->add_responsive_control(
1196 'padding',
1197 [
1198 'label' => esc_html__( 'Padding', 'elementor' ),
1199 'type' => Controls_Manager::DIMENSIONS,
1200 'size_units' => [ 'px', '%', 'em', 'rem', 'vw', 'custom' ],
1201 'selectors' => [
1202 '{{WRAPPER}}' => 'padding: {{TOP}}{{UNIT}} {{RIGHT}}{{UNIT}} {{BOTTOM}}{{UNIT}} {{LEFT}}{{UNIT}};',
1203 ],
1204 ]
1205 );
1206
1207 $this->add_responsive_control(
1208 'z_index',
1209 [
1210 'label' => esc_html__( 'Z-Index', 'elementor' ),
1211 'type' => Controls_Manager::NUMBER,
1212 'min' => 0,
1213 'selectors' => [
1214 '{{WRAPPER}}' => 'z-index: {{VALUE}};',
1215 ],
1216 ]
1217 );
1218
1219 $this->add_control(
1220 '_element_id',
1221 [
1222 'label' => esc_html__( 'CSS ID', 'elementor' ),
1223 'type' => Controls_Manager::TEXT,
1224 'default' => '',
1225 'ai' => [
1226 'active' => false,
1227 ],
1228 'dynamic' => [
1229 'active' => true,
1230 ],
1231 'title' => esc_html__( 'Add your custom id WITHOUT the Pound key. e.g: my-id', 'elementor' ),
1232 'style_transfer' => false,
1233 'classes' => 'elementor-control-direction-ltr',
1234 ]
1235 );
1236
1237 $this->add_control(
1238 'css_classes',
1239 [
1240 'label' => esc_html__( 'CSS Classes', 'elementor' ),
1241 'type' => Controls_Manager::TEXT,
1242 'default' => '',
1243 'ai' => [
1244 'active' => false,
1245 ],
1246 'dynamic' => [
1247 'active' => true,
1248 ],
1249 'prefix_class' => '',
1250 'title' => esc_html__( 'Add your custom class WITHOUT the dot. e.g: my-class', 'elementor' ),
1251 'classes' => 'elementor-control-direction-ltr',
1252 ]
1253 );
1254
1255 Plugin::$instance->controls_manager->add_display_conditions_controls( $this );
1256
1257 $this->end_controls_section();
1258
1259 $this->start_controls_section(
1260 'section_effects',
1261 [
1262 'label' => esc_html__( 'Motion Effects', 'elementor' ),
1263 'tab' => Controls_Manager::TAB_ADVANCED,
1264 ]
1265 );
1266
1267 Plugin::$instance->controls_manager->add_motion_effects_promotion_control( $this );
1268
1269 $this->add_responsive_control(
1270 'animation',
1271 [
1272 'label' => esc_html__( 'Entrance Animation', 'elementor' ),
1273 'type' => Controls_Manager::ANIMATION,
1274 'frontend_available' => true,
1275 ]
1276 );
1277
1278 $this->add_control(
1279 'animation_duration',
1280 [
1281 'label' => esc_html__( 'Animation Duration', 'elementor' ),
1282 'type' => Controls_Manager::SELECT,
1283 'default' => '',
1284 'options' => [
1285 'slow' => esc_html__( 'Slow', 'elementor' ),
1286 '' => esc_html__( 'Normal', 'elementor' ),
1287 'fast' => esc_html__( 'Fast', 'elementor' ),
1288 ],
1289 'prefix_class' => 'animated-',
1290 'condition' => [
1291 'animation!' => '',
1292 ],
1293 ]
1294 );
1295
1296 $this->add_control(
1297 'animation_delay',
1298 [
1299 'label' => esc_html__( 'Animation Delay', 'elementor' ) . ' (ms)',
1300 'type' => Controls_Manager::NUMBER,
1301 'default' => '',
1302 'min' => 0,
1303 'step' => 100,
1304 'condition' => [
1305 'animation!' => '',
1306 ],
1307 'render_type' => 'none',
1308 'frontend_available' => true,
1309 ]
1310 );
1311
1312 $this->end_controls_section();
1313
1314 // Section Responsive
1315 $this->start_controls_section(
1316 '_section_responsive',
1317 [
1318 'label' => esc_html__( 'Responsive', 'elementor' ),
1319 'tab' => Controls_Manager::TAB_ADVANCED,
1320 ]
1321 );
1322
1323 // The controls should be displayed from largest to smallest breakpoint, so we reverse the array.
1324 $active_breakpoints = array_reverse( Plugin::$instance->breakpoints->get_active_breakpoints() );
1325
1326 foreach ( $active_breakpoints as $breakpoint_key => $breakpoint ) {
1327 $this->add_control(
1328 'reverse_order_' . $breakpoint_key,
1329 [
1330 'label' => esc_html__( 'Reverse Columns', 'elementor' ) . ' (' . $breakpoint->get_label() . ')',
1331 'type' => Controls_Manager::SWITCHER,
1332 'default' => '',
1333 'prefix_class' => 'elementor-',
1334 'return_value' => 'reverse-' . $breakpoint_key,
1335 ]
1336 );
1337 }
1338
1339 $this->add_control(
1340 'heading_visibility',
1341 [
1342 'label' => esc_html__( 'Visibility', 'elementor' ),
1343 'type' => Controls_Manager::HEADING,
1344 'separator' => 'before',
1345 ]
1346 );
1347
1348 $this->add_control(
1349 'responsive_description',
1350 [
1351 'raw' => sprintf(
1352 /* translators: 1: Link open tag, 2: Link close tag. */
1353 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' ),
1354 '<a href="javascript: $e.run( \'panel/close\' )">',
1355 '</a>'
1356 ),
1357 'type' => Controls_Manager::RAW_HTML,
1358 'content_classes' => 'elementor-descriptor',
1359 ]
1360 );
1361
1362 $this->add_hidden_device_controls();
1363
1364 $this->end_controls_section();
1365
1366 Plugin::$instance->controls_manager->add_custom_attributes_controls( $this );
1367
1368 Plugin::$instance->controls_manager->add_custom_css_controls( $this );
1369 }
1370
1371 /**
1372 * Render section output in the editor.
1373 *
1374 * Used to generate the live preview, using a Backbone JavaScript template.
1375 *
1376 * @since 2.9.0
1377 * @access protected
1378 */
1379 protected function content_template() {
1380 ?>
1381 <#
1382 if ( settings.background_video_link ) {
1383 let videoAttributes = 'autoplay muted playsinline';
1384
1385 if ( ! settings.background_play_once ) {
1386 videoAttributes += ' loop';
1387 }
1388
1389 view.addRenderAttribute( 'background-video-container', 'class', 'elementor-background-video-container' );
1390
1391 if ( ! settings.background_play_on_mobile ) {
1392 view.addRenderAttribute( 'background-video-container', 'class', 'elementor-hidden-mobile' );
1393 }
1394 #>
1395 <div {{{ view.getRenderAttributeString( 'background-video-container' ) }}}>
1396 <div class="elementor-background-video-embed"></div>
1397 <video class="elementor-background-video-hosted elementor-html5-video" {{ videoAttributes }}></video>
1398 </div>
1399 <# } #>
1400 <div class="elementor-background-overlay"></div>
1401 <div class="elementor-shape elementor-shape-top"></div>
1402 <div class="elementor-shape elementor-shape-bottom"></div>
1403 <div class="elementor-container elementor-column-gap-{{ settings.gap }}"></div>
1404 <?php
1405 }
1406
1407 /**
1408 * Before section rendering.
1409 *
1410 * Used to add stuff before the section element.
1411 *
1412 * @since 1.0.0
1413 * @access public
1414 */
1415 public function before_render() {
1416 $settings = $this->get_settings_for_display();
1417 ?>
1418 <<?php
1419 // PHPCS - the method get_html_tag is safe.
1420 echo $this->get_html_tag(); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
1421 ?> <?php $this->print_render_attribute_string( '_wrapper' ); ?>>
1422 <?php
1423 if ( 'video' === $settings['background_background'] ) :
1424 if ( $settings['background_video_link'] ) :
1425 $video_properties = Embed::get_video_properties( $settings['background_video_link'] );
1426
1427 $this->add_render_attribute( 'background-video-container', 'class', 'elementor-background-video-container' );
1428
1429 if ( ! $settings['background_play_on_mobile'] ) {
1430 $this->add_render_attribute( 'background-video-container', 'class', 'elementor-hidden-phone' );
1431 }
1432 ?>
1433 <div <?php $this->print_render_attribute_string( 'background-video-container' ); ?>>
1434 <?php if ( $video_properties ) : ?>
1435 <div class="elementor-background-video-embed"></div>
1436 <?php
1437 else :
1438 $video_tag_attributes = 'autoplay muted playsinline';
1439 if ( 'yes' !== $settings['background_play_once'] ) :
1440 $video_tag_attributes .= ' loop';
1441 endif;
1442 ?>
1443 <video class="elementor-background-video-hosted elementor-html5-video" <?php
1444 // PHPCS - the variable $video_tag_attributes is a plain string.
1445 echo $video_tag_attributes; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
1446 ?>></video>
1447 <?php endif; ?>
1448 </div>
1449 <?php
1450 endif;
1451 endif;
1452
1453 $has_background_overlay = in_array( $settings['background_overlay_background'], [ 'classic', 'gradient' ], true ) ||
1454 in_array( $settings['background_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