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

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