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

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