PluginProbe
Elementor Website Builder – more than just a page builder / 3.1.3
Elementor Website Builder – more than just a page builder v3.1.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.1.3, at includes/elements/section.php

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