PluginProbe
Elementor Website Builder – more than just a page builder / 3.16.2
Elementor Website Builder – more than just a page builder v3.16.2
4.3.0 4.3.0-beta3 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 All 453 releases
elementor / modules / nested-accordion / widgets / nested-accordion.php

nested-accordion.php in Elementor Website Builder – more than just a page builder 3.16.2, at modules/nested-accordion/widgets/nested-accordion.php

875 lines 24.4 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 namespace Elementor\Modules\NestedAccordion\Widgets;
3
4 use Elementor\Controls_Manager;
5 use Elementor\Group_Control_Background;
6 use Elementor\Group_Control_Border;
7 use Elementor\Group_Control_Text_Shadow;
8 use Elementor\Group_Control_Typography;
9 use Elementor\Icons_Manager;
10 use Elementor\Modules\NestedElements\Base\Widget_Nested_Base;
11 use Elementor\Modules\NestedElements\Controls\Control_Nested_Repeater;
12 use Elementor\Plugin;
13 use Elementor\Repeater;
14 use Elementor\Utils;
15 use Elementor\Group_Control_Text_Stroke;
16
17 if ( ! defined( 'ABSPATH' ) ) {
18 exit; // Exit if accessed directly
19 }
20
21 /**
22 * Elementor Nested Accordion widget.
23 *
24 * Elementor widget that displays a collapsible display of content in an
25 * accordion style.
26 *
27 * @since 3.15.0
28 */
29 class Nested_Accordion extends Widget_Nested_Base {
30
31 public function get_name() {
32 return 'nested-accordion';
33 }
34
35 public function get_title() {
36 return esc_html__( 'Accordion', 'elementor' );
37 }
38
39 public function get_icon() {
40 return 'eicon-accordion';
41 }
42
43 public function get_keywords() {
44 return [ 'nested', 'tabs', 'accordion', 'toggle' ];
45 }
46
47 public function show_in_panel(): bool {
48 return Plugin::$instance->experiments->is_feature_active( 'nested-elements' );
49 }
50
51 protected function item_content_container( int $index ) {
52 return [
53 'elType' => 'container',
54 'settings' => [
55 '_title' => sprintf( __( 'item #%s', 'elementor' ), $index ),
56 'content_width' => 'full',
57 ],
58 ];
59 }
60
61 protected function get_default_children_elements() {
62 return [
63 $this->item_content_container( 1 ),
64 $this->item_content_container( 2 ),
65 $this->item_content_container( 3 ),
66 ];
67 }
68
69 protected function get_default_repeater_title_setting_key() {
70 return 'item_title';
71 }
72
73 protected function get_default_children_title() {
74 return esc_html__( 'Item #%d', 'elementor' );
75 }
76
77 protected function get_default_children_placeholder_selector() {
78 return '.e-n-accordion';
79 }
80
81 protected function get_html_wrapper_class() {
82 return 'elementor-widget-n-accordion';
83 }
84
85 protected function register_controls() {
86 $this->start_controls_section( 'section_items', [
87 'label' => esc_html__( 'Layout', 'elementor' ),
88 ] );
89
90 $repeater = new Repeater();
91
92 $repeater->add_control(
93 'item_title',
94 [
95 'label' => esc_html__( 'Title', 'elementor' ),
96 'type' => Controls_Manager::TEXT,
97 'default' => esc_html__( 'Item Title', 'elementor' ),
98 'placeholder' => esc_html__( 'Item Title', 'elementor' ),
99 'label_block' => true,
100 'dynamic' => [
101 'active' => true,
102 ],
103 ]
104 );
105
106 $repeater->add_control(
107 'element_css_id',
108 [
109 'label' => esc_html__( 'CSS ID', 'elementor' ),
110 'type' => Controls_Manager::TEXT,
111 'default' => '',
112 'dynamic' => [
113 'active' => true,
114 ],
115 'title' => esc_html__( 'Add your custom id WITHOUT the Pound key. e.g: my-id', 'elementor' ),
116 'style_transfer' => false,
117 ]
118 );
119
120 $this->add_control(
121 'items',
122 [
123 'label' => esc_html__( 'Items', 'elementor' ),
124 'type' => Control_Nested_Repeater::CONTROL_TYPE,
125 'fields' => $repeater->get_controls(),
126 'default' => [
127 [
128 'item_title' => esc_html__( 'Item #1', 'elementor' ),
129 ],
130 [
131 'item_title' => esc_html__( 'Item #2', 'elementor' ),
132 ],
133 [
134 'item_title' => esc_html__( 'Item #3', 'elementor' ),
135 ],
136 ],
137 'title_field' => '{{{ item_title }}}',
138 'button_text' => 'Add Item',
139 ]
140 );
141
142 $this->add_responsive_control(
143 'accordion_item_title_position_horizontal',
144 [
145 'label' => esc_html__( 'Item Position', 'elementor' ),
146 'type' => Controls_Manager::CHOOSE,
147 'separator' => 'before',
148 'options' => [
149 'start' => [
150 'title' => esc_html__( 'Start', 'elementor' ),
151 'icon' => 'eicon-flex eicon-align-start-h',
152 ],
153 'center' => [
154 'title' => esc_html__( 'Center', 'elementor' ),
155 'icon' => 'eicon-h-align-center',
156 ],
157 'end' => [
158 'title' => esc_html__( 'End', 'elementor' ),
159 'icon' => 'eicon-flex eicon-align-end-h',
160 ],
161 'stretch' => [
162 'title' => esc_html__( 'Stretch', 'elementor' ),
163 'icon' => 'eicon-h-align-stretch',
164 ],
165 ],
166 'selectors_dictionary' => [
167 'start' => '--n-accordion-title-justify-content: initial; --n-accordion-title-flex-grow: initial;',
168 'center' => '--n-accordion-title-justify-content: center; --n-accordion-title-flex-grow: initial;',
169 'end' => '--n-accordion-title-justify-content: flex-end; --n-accordion-title-flex-grow: initial;',
170 'stretch' => '--n-accordion-title-justify-content: space-between; --n-accordion-title-flex-grow: 1;',
171 ],
172 'selectors' => [
173 '{{WRAPPER}}' => '{{VALUE}}',
174 ],
175 ]
176 );
177
178 $this->add_control(
179 'heading_accordion_item_title_icon',
180 [
181 'type' => Controls_Manager::HEADING,
182 'label' => esc_html__( 'Icon', 'elementor' ),
183 'separator' => 'before',
184 ]
185 );
186
187 $this->add_responsive_control(
188 'accordion_item_title_icon_position',
189 [
190 'label' => esc_html__( 'Position', 'elementor' ),
191 'type' => Controls_Manager::CHOOSE,
192 'options' => [
193 'start' => [
194 'title' => esc_html__( 'Start', 'elementor' ),
195 'icon' => 'eicon-h-align-left',
196 ],
197 'end' => [
198 'title' => esc_html__( 'End', 'elementor' ),
199 'icon' => 'eicon-h-align-right',
200 ],
201 ],
202 'selectors_dictionary' => [
203 'start' => '--n-accordion-title-icon-order: -1;',
204 'end' => '--n-accordion-title-icon-order: initial;',
205 ],
206 'selectors' => [
207 '{{WRAPPER}}' => '{{VALUE}}',
208 ],
209 ]
210 );
211
212 $this->add_control(
213 'accordion_item_title_icon',
214 [
215 'label' => esc_html__( 'Expand', 'elementor' ),
216 'type' => Controls_Manager::ICONS,
217 'default' => [
218 'value' => 'fas fa-plus',
219 'library' => 'fa-solid',
220 ],
221 'skin' => 'inline',
222 'label_block' => false,
223 ]
224 );
225
226 $this->add_control(
227 'accordion_item_title_icon_active',
228 [
229 'label' => esc_html__( 'Collapse', 'elementor' ),
230 'type' => Controls_Manager::ICONS,
231 'fa4compatibility' => 'icon_active',
232 'default' => [
233 'value' => 'fas fa-minus',
234 'library' => 'fa-solid',
235 ],
236 'condition' => [
237 'accordion_item_title_icon[value]!' => '',
238 ],
239 'skin' => 'inline',
240 'label_block' => false,
241 ]
242 );
243
244 $this->add_control(
245 'title_tag',
246 [
247 'label' => esc_html__( 'Title HTML Tag', 'elementor' ),
248 'type' => Controls_Manager::SELECT,
249 'options' => [
250 'h1' => 'H1',
251 'h2' => 'H2',
252 'h3' => 'H3',
253 'h4' => 'H4',
254 'h5' => 'H5',
255 'h6' => 'H6',
256 'div' => 'div',
257 'span' => 'span',
258 'p' => 'p',
259 ],
260 'selectors_dictionary' => [
261 'h1' => '--n-accordion-title-font-size: 2.5rem;',
262 'h2' => '--n-accordion-title-font-size: 2rem;',
263 'h3' => '--n-accordion-title-font-size: 1,75rem;',
264 'h4' => '--n-accordion-title-font-size: 1.5rem;',
265 'h5' => '--n-accordion-title-font-size: 1rem;',
266 'h6' => '--n-accordion-title-font-size: 1rem; ',
267 'div' => '--n-accordion-title-font-size: 1rem;',
268 'span' => '--n-accordion-title-font-size: 1rem; ',
269 'p' => '--n-accordion-title-font-size: 1rem;',
270 ],
271 'selectors' => [
272 '{{WRAPPER}}' => '{{VALUE}}',
273 ],
274 'default' => 'div',
275 'separator' => 'before',
276 'render_type' => 'template',
277
278 ]
279 );
280 $this->end_controls_section();
281
282 $this->start_controls_section(
283 'section_interactions',
284 [
285 'label' => esc_html__( 'Interactions', 'elementor' ),
286 ]
287 );
288
289 $this->add_control(
290 'default_state',
291 [
292 'label' => esc_html__( 'Default State', 'elementor' ),
293 'type' => Controls_Manager::SELECT,
294 'options' => [
295 'expanded' => esc_html__( 'First expanded', 'elementor' ),
296 'all_collapsed' => esc_html__( 'All collapsed', 'elementor' ),
297 ],
298 'default' => 'expanded',
299 'frontend_available' => true,
300 ]
301 );
302
303 $this->add_control(
304 'max_items_expended',
305 [
306 'label' => esc_html__( 'Max Items Expanded', 'elementor' ),
307 'type' => Controls_Manager::SELECT,
308 'options' => [
309 'one' => esc_html__( 'One', 'elementor' ),
310 'multiple' => esc_html__( 'Multiple', 'elementor' ),
311 ],
312 'default' => 'one',
313 'frontend_available' => true,
314 ]
315 );
316
317 $this->add_control(
318 'n_accordion_animation_duration',
319 [
320 'label' => esc_html__( 'Animation Duration', 'elementor' ),
321 'type' => Controls_Manager::SLIDER,
322 'size_units' => [ 's', 'ms' ],
323 'default' => [
324 'unit' => 'ms',
325 'size' => 400,
326 ],
327 'frontend_available' => true,
328 ]
329 );
330
331 $this->end_controls_section();
332
333 $this->add_style_tab();
334 }
335
336 private function add_style_tab() {
337 $this->add_accordion_style_section();
338 $this->add_header_style_section();
339 $this->add_content_style_section();
340 }
341
342 private function add_accordion_style_section() {
343 $this->start_controls_section(
344 'section_accordion_style',
345 [
346 'label' => esc_html__( 'Accordion', 'elementor' ),
347 'tab' => Controls_Manager::TAB_STYLE,
348 ]
349 );
350
351 $this->add_responsive_control(
352 'accordion_item_title_space_between',
353 [
354 'label' => esc_html__( 'Space between Items', 'elementor' ),
355 'type' => Controls_Manager::SLIDER,
356 'size_units' => [ 'px' ],
357 'range' => [
358 'px' => [
359 'min' => 0,
360 'max' => 200,
361 ],
362 ],
363 'default' => [
364 'size' => 0,
365 ],
366 'selectors' => [
367 '{{WRAPPER}}' => '--n-accordion-item-title-space-between: {{SIZE}}{{UNIT}}',
368 ],
369 ]
370 );
371
372 $this->add_responsive_control(
373 'accordion_item_title_distance_from_content',
374 [
375 'label' => esc_html__( 'Distance from content', 'elementor' ),
376 'type' => Controls_Manager::SLIDER,
377 'size_units' => [ 'px' ],
378 'range' => [
379 'px' => [
380 'min' => 0,
381 'max' => 200,
382 ],
383 ],
384 'default' => [
385 'size' => 0,
386 ],
387 'selectors' => [
388 '{{WRAPPER}}' => '--n-accordion-item-title-distance-from-content: {{SIZE}}{{UNIT}}',
389 ],
390 ]
391 );
392
393 $this->start_controls_tabs( 'accordion_border_and_background' );
394
395 foreach ( [ 'normal', 'hover', 'active' ] as $state ) {
396 $this->add_border_and_radius_style( $state );
397 }
398
399 $this->end_controls_tabs();
400
401 $this->add_responsive_control(
402 'accordion_border_radius',
403 [
404 'label' => esc_html__( 'Border Radius', 'elementor' ),
405 'type' => Controls_Manager::DIMENSIONS,
406 'size_units' => [ 'px', '%', 'em', 'rem', 'vw', 'custom' ],
407 'selectors' => [
408 '{{WRAPPER}}' => '--n-accordion-border-radius: {{TOP}}{{UNIT}} {{RIGHT}}{{UNIT}} {{BOTTOM}}{{UNIT}} {{LEFT}}{{UNIT}};',
409 ],
410 'separator' => 'before',
411 ]
412 );
413
414 $this->add_responsive_control(
415 'accordion_padding',
416 [
417 'label' => esc_html__( 'Padding', 'elementor' ),
418 'type' => Controls_Manager::DIMENSIONS,
419 'size_units' => [ 'px', '%', 'em', 'rem', 'custom' ],
420 'selectors' => [
421 '{{WRAPPER}} ' => '--n-accordion-padding: {{TOP}}{{UNIT}} {{RIGHT}}{{UNIT}} {{BOTTOM}}{{UNIT}} {{LEFT}}{{UNIT}};',
422 ],
423 ]
424 );
425
426 $this->end_controls_section();
427 }
428
429 private function add_content_style_section() {
430
431 $low_specificity_accordion_item_selector = ':where( {{WRAPPER}} > .elementor-widget-container > .e-n-accordion > .e-n-accordion-item ) > .e-con';
432
433 $this->start_controls_section(
434 'section_content_style',
435 [
436 'label' => esc_html__( 'Content', 'elementor' ),
437 'tab' => Controls_Manager::TAB_STYLE,
438 ]
439 );
440
441 $this->add_group_control(
442 Group_Control_Background::get_type(),
443 [
444 'name' => 'content_background',
445 'types' => [ 'classic', 'gradient' ],
446 'exclude' => [ 'image' ],
447 'selector' => $low_specificity_accordion_item_selector,
448 ]
449 );
450
451 $this->add_group_control(
452 Group_Control_Border::get_type(),
453 [
454 'name' => 'content_border',
455 'selector' => $low_specificity_accordion_item_selector,
456 'fields_options' => [
457 'color' => [
458 'label' => esc_html__( 'Border Color', 'elementor' ),
459 ],
460 'width' => [
461 'label' => esc_html__( 'Border Width', 'elementor' ),
462 ],
463 ],
464 ]
465 );
466
467 $this->add_responsive_control(
468 'content_border_radius',
469 [
470 'label' => esc_html__( 'Border Radius', 'elementor' ),
471 'type' => Controls_Manager::DIMENSIONS,
472 'size_units' => [ 'px', '%', 'em', 'rem', 'vw', 'custom' ],
473 'selectors' => [
474 $low_specificity_accordion_item_selector => '--border-radius: {{TOP}}{{UNIT}} {{RIGHT}}{{UNIT}} {{BOTTOM}}{{UNIT}} {{LEFT}}{{UNIT}};',
475 ],
476 ]
477 );
478
479 $logical_dimensions_inline_start = is_rtl() ? '{{RIGHT}}{{UNIT}}' : '{{LEFT}}{{UNIT}}';
480 $logical_dimensions_inline_end = is_rtl() ? '{{LEFT}}{{UNIT}}' : '{{RIGHT}}{{UNIT}}';
481
482 $this->add_responsive_control(
483 'content_padding',
484 [
485 'label' => esc_html__( 'Padding', 'elementor' ),
486 'type' => Controls_Manager::DIMENSIONS,
487 'size_units' => [ 'px', '%', 'em', 'rem', 'custom' ],
488 'selectors' => [
489 $low_specificity_accordion_item_selector => "--padding-block-start: {{TOP}}{{UNIT}}; --padding-inline-end: $logical_dimensions_inline_end; --padding-block-end: {{BOTTOM}}{{UNIT}}; --padding-inline-start: $logical_dimensions_inline_start;",
490 ],
491 ]
492 );
493
494 $this->end_controls_section();
495 }
496
497 private function add_header_style_section() {
498 $this->start_controls_section(
499 'section_header_style',
500 [
501 'label' => esc_html__( 'Header', 'elementor' ),
502 'tab' => Controls_Manager::TAB_STYLE,
503 ]
504 );
505
506 $this->add_control(
507 'heading_header_style_title',
508 [
509 'type' => Controls_Manager::HEADING,
510 'label' => esc_html__( 'Title', 'elementor' ),
511
512 ]
513 );
514
515 $this->add_group_control(
516 Group_Control_Typography::get_type(),
517 [
518 'name' => 'title_typography',
519 'selector' => ':where( {{WRAPPER}} > .elementor-widget-container > .e-n-accordion > .e-n-accordion-item > .e-n-accordion-item-title > .e-n-accordion-item-title-header ) > .e-n-accordion-item-title-text',
520 'fields_options' => [
521 'font_size' => [
522 'selectors' => [
523 '{{WRAPPER}}' => '--n-accordion-title-font-size: {{SIZE}}{{UNIT}}',
524 ],
525 ],
526 ],
527 ]
528 );
529
530 $this->start_controls_tabs( 'header_title_color_style' );
531
532 foreach ( [ 'normal', 'hover', 'active' ] as $state ) {
533 $this->add_header_style( $state, 'title' );
534 }
535
536 $this->end_controls_tabs();
537
538 $this->add_control(
539 'header_section_divider',
540 [
541 'type' => Controls_Manager::DIVIDER,
542 ]
543 );
544
545 $this->add_control(
546 'heading_icon_style_title',
547 [
548 'type' => Controls_Manager::HEADING,
549 'label' => esc_html__( 'Icon', 'elementor' ),
550
551 ]
552 );
553
554 $this->add_responsive_control(
555 'icon_size',
556 [
557 'label' => esc_html__( 'Size', 'elementor' ),
558 'type' => Controls_Manager::SLIDER,
559 'range' => [
560 'em' => [
561 'min' => 0,
562 'max' => 10,
563 'step' => 0.1,
564 ],
565 'rem' => [
566 'min' => 0,
567 'max' => 10,
568 'step' => 0.1,
569 ],
570 ],
571 'default' => [
572 'unit' => 'px',
573 'size' => 15,
574 ],
575 'size_units' => [ 'px', '%', 'em', 'rem', 'vw', 'custom' ],
576 'selectors' => [
577 '{{WRAPPER}}' => '--n-accordion-icon-size: {{SIZE}}{{UNIT}}',
578 ],
579 ]
580 );
581
582 $this->add_responsive_control(
583 'icon_spacing',
584 [
585 'label' => esc_html__( 'Spacing', 'elementor' ),
586 'type' => Controls_Manager::SLIDER,
587 'range' => [
588 'px' => [
589 'min' => 0,
590 'max' => 400,
591 ],
592 'vw' => [
593 'min' => 0,
594 'max' => 50,
595 'step' => 0.1,
596 ],
597 ],
598 'size_units' => [ 'px', '%', 'em', 'rem', 'vw', 'custom' ],
599 'selectors' => [
600 '{{WRAPPER}}' => '--n-accordion-icon-gap: {{SIZE}}{{UNIT}}',
601 ],
602 'condition' => [
603 'accordion_item_title_position_horizontal!' => 'stretch',
604 ],
605 ]
606 );
607
608 $this->start_controls_tabs( 'header_icon_color_style' );
609
610 foreach ( [ 'normal', 'hover', 'active' ] as $state ) {
611 $this->add_header_style( $state, 'icon' );
612 }
613
614 $this->end_controls_tabs();
615 $this->end_controls_section();
616 }
617
618 private function add_header_style( $state, $context ) {
619 $variable = '--n-accordion-' . $context . '-' . $state . '-color';
620
621 switch ( $state ) {
622 case 'hover':
623 $translated_tab_text = esc_html__( 'Hover', 'elementor' );
624 $translated_tab_css_selector = ':where( {{WRAPPER}} > .elementor-widget-container > .e-n-accordion > .e-n-accordion-item:not([open]) > .e-n-accordion-item-title:hover > .e-n-accordion-item-title-header ) > .e-n-accordion-item-title-text';
625 break;
626 case 'active':
627 $translated_tab_text = esc_html__( 'Active', 'elementor' );
628 $translated_tab_css_selector = ':where( {{WRAPPER}} > .elementor-widget-container > .e-n-accordion > .e-n-accordion-item[open] > .e-n-accordion-item-title > .e-n-accordion-item-title-header ) > .e-n-accordion-item-title-text';
629 break;
630 default:
631 $translated_tab_text = esc_html__( 'Normal', 'elementor' );
632 $translated_tab_css_selector = ':where( {{WRAPPER}} > .elementor-widget-container > .e-n-accordion > .e-n-accordion-item:not([open]) > .e-n-accordion-item-title:not(hover) > .e-n-accordion-item-title-header ) > .e-n-accordion-item-title-text';
633 break;
634 }
635
636 $this->start_controls_tab(
637 'header_' . $state . '_' . $context,
638 [
639 'label' => $translated_tab_text,
640 ]
641 );
642
643 $this->add_control(
644 $state . '_' . $context . '_color',
645 [
646 'label' => esc_html__( 'Color', 'elementor' ),
647 'type' => Controls_Manager::COLOR,
648 'selectors' => [
649 '{{WRAPPER}}' => $variable . ': {{VALUE}};',
650 ],
651 ]
652 );
653
654 if ( 'title' === $context ) {
655 $this->add_group_control(
656 Group_Control_Text_Shadow::get_type(),
657 [
658 'name' => $context . '_' . $state . '_text_shadow',
659 'selector' => '{{WRAPPER}} ' . $translated_tab_css_selector,
660 'fields_options' => [
661 'text_shadow_type' => [
662 'label' => esc_html_x( 'Shadow', 'Text Shadow Control', 'elementor' ),
663 ],
664 ],
665 ]
666 );
667
668 $this->add_group_control(
669 Group_Control_Text_Stroke::get_type(),
670 [
671 'name' => $context . '_' . $state . '_stroke',
672 'selector' => '{{WRAPPER}} ' . $translated_tab_css_selector,
673 ]
674 );
675 }
676
677 $this->end_controls_tab();
678 }
679
680 /**
681 * @string $state
682 */
683 private function add_border_and_radius_style( $state ) {
684 $selector = '{{WRAPPER}} > .elementor-widget-container > .e-n-accordion > .e-n-accordion-item > .e-n-accordion-item-title';
685 $translated_tab_text = esc_html__( 'Normal', 'elementor' );
686
687 switch ( $state ) {
688 case 'hover':
689 $selector .= ':hover';
690 $translated_tab_text = esc_html__( 'Hover', 'elementor' );
691 break;
692 case 'active':
693 $selector = '{{WRAPPER}} > .elementor-widget-container > .e-n-accordion > .e-n-accordion-item[open] > .e-n-accordion-item-title';
694 $translated_tab_text = esc_html__( 'Active', 'elementor' );
695 break;
696 }
697
698 $this->start_controls_tab(
699 'accordion_' . $state . '_border_and_background',
700 [
701 'label' => $translated_tab_text,
702 ]
703 );
704
705 $this->add_group_control(
706 Group_Control_Background::get_type(),
707 [
708 'name' => 'accordion_background_' . $state,
709 'types' => [ 'classic', 'gradient' ],
710 'exclude' => [ 'image' ],
711 'fields_options' => [
712 'color' => [
713 'label' => esc_html__( 'Color', 'elementor' ),
714 ],
715 ],
716 'selector' => $selector,
717 ]
718 );
719
720 $this->add_group_control(
721 Group_Control_Border::get_type(),
722 [
723 'name' => 'accordion_border_' . $state,
724 'selector' => $selector,
725 ]
726 );
727
728 $this->end_controls_tab();
729 }
730
731 private function is_active_icon_exist( $settings ):bool {
732 return array_key_exists( 'accordion_item_title_icon_active', $settings ) && ! empty( $settings['accordion_item_title_icon_active'] ) && ! empty( $settings['accordion_item_title_icon_active']['value'] );
733 }
734
735 private function render_accordion_icons( $settings ) {
736 $icon_html = Icons_Manager::try_get_icon_html( $settings['accordion_item_title_icon'], [ 'aria-hidden' => 'true' ] );
737 $icon_active_html = $this->is_active_icon_exist( $settings )
738 ? Icons_Manager::try_get_icon_html( $settings['accordion_item_title_icon_active'], [ 'aria-hidden' => 'true' ] )
739 : $icon_html;
740
741 ob_start();
742 ?>
743 <span class='e-n-accordion-item-title-icon'>
744 <span class='e-opened' ><?php echo $icon_active_html; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped ?></span>
745 <span class='e-closed'><?php echo $icon_html; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped ?></span>
746 </span>
747
748 <?php
749 return ob_get_clean();
750 }
751
752 protected function render() {
753 $settings = $this->get_settings_for_display();
754 $items = $settings['items'];
755 $id_int = substr( $this->get_id_int(), 0, 3 );
756 $items_title_html = '';
757 $icons_content = $this->render_accordion_icons( $settings );
758 $this->add_render_attribute( 'elementor-accordion', 'class', 'e-n-accordion' );
759 $default_state = $settings['default_state'];
760 $title_html_tag = Utils::validate_html_tag( $settings['title_tag'] );
761
762 foreach ( $items as $index => $item ) {
763 $item_setting_key = $this->get_repeater_setting_key( 'item_title', 'items', $index );
764 $item_classes = [ 'e-n-accordion-item', 'e-normal' ];
765 $item_id = empty( $item['element_css_id'] ) ? 'e-n-accordion-item-' . $id_int . $index : $item['element_css_id'];
766 $item_title = $item['item_title'];
767 $is_open = 'expanded' === $default_state && 0 === $index ? 'open' : '';
768
769 $this->add_render_attribute( $item_setting_key, [
770 'id' => $item_id,
771 'class' => $item_classes,
772 ] );
773
774 $title_render_attributes = $this->get_render_attribute_string( $item_setting_key );
775 $title_render_attributes = $title_render_attributes . ' ' . $is_open;
776
777 // items content.
778 ob_start();
779 $this->print_child( $index );
780 $item_content = ob_get_clean();
781
782 ob_start();
783 ?>
784 <details <?php echo wp_kses_post( $title_render_attributes ); ?>>
785 <summary class='e-n-accordion-item-title'>
786 <span class='e-n-accordion-item-title-header'><?php echo wp_kses_post( "<$title_html_tag class=\"e-n-accordion-item-title-text\"> $item_title </$title_html_tag>" ); ?></span>
787 <?php if ( ! empty( $settings['accordion_item_title_icon']['value'] ) ) {
788 echo $icons_content; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
789 } ?>
790 </summary>
791 <?php echo $item_content; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped ?>
792 </details>
793 <?php
794 $items_title_html .= ob_get_clean();
795 }
796
797 ?>
798 <div <?php $this->print_render_attribute_string( 'elementor-accordion' ); ?>>
799 <?php echo $items_title_html; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped ?>
800 </div>
801 <?php
802 }
803
804 protected function content_template() {
805 ?>
806 <div class="e-n-accordion" role="tablist" aria-orientation="vertical">
807 <# if ( settings['items'] ) {
808 const elementUid = view.getIDInt().toString().substring( 0, 3 ),
809 titleHTMLTag = elementor.helpers.validateHTMLTag( settings.title_tag ),
810 itemTitleText = 'item-title-text-' + elementUid,
811 defaultState = settings.default_state,
812 itemTitleIcon = elementor.helpers.renderIcon( view, settings['accordion_item_title_icon'], { 'aria-hidden': true }, 'i', 'object' ) ?? '',
813 itemTitleIconActive = '' === settings.accordion_item_title_icon_active.value
814 ? itemTitleIcon
815 : elementor.helpers.renderIcon( view, settings['accordion_item_title_icon_active'], { 'aria-hidden': true }, 'i', 'object' );
816 #>
817
818 <# _.each( settings['items'], function( item, index ) {
819 const itemCount = index + 1,
820 itemUid = elementUid + itemCount,
821 itemWrapperKey = itemUid,
822 itemTitleKey = 'item-' + itemUid;
823
824 if ( '' !== item.element_css_id ) {
825 itemId = item.element_css_id;
826 } else {
827 itemId = 'e-n-accordion-item-' + itemUid;
828 }
829
830 const itemWrapperAttributes = {
831 'id': itemId,
832 'class': [ 'e-n-accordion-item', 'e-normal' ],
833 };
834
835 if ( defaultState === 'expanded' && index === 0) {
836 itemWrapperAttributes['open'] = true;
837 }
838
839 view.addRenderAttribute( itemWrapperKey, itemWrapperAttributes );
840
841 view.addRenderAttribute( itemTitleKey, {
842 'class': ['e-n-accordion-item-title'],
843 });
844
845 view.addRenderAttribute( itemTitleText, {
846 'class': ['e-n-accordion-item-title-text'],
847 'data-binding-type': 'repeater-item',
848 'data-binding-repeater-name': 'items',
849 'data-binding-setting': ['item_title'],
850 'data-binding-index': itemCount,
851 });
852 #>
853
854 <details {{{ view.getRenderAttributeString( itemWrapperKey ) }}}>
855 <summary {{{ view.getRenderAttributeString( itemTitleKey ) }}}>
856 <span class="e-n-accordion-item-title-header">
857 <{{{ titleHTMLTag }}} {{{ view.getRenderAttributeString( itemTitleText ) }}}>
858 {{{ item.item_title }}}
859 </{{{ titleHTMLTag }}}>
860 </span>
861 <# if (settings.accordion_item_title_icon.value) { #>
862 <span class="e-n-accordion-item-title-icon">
863 <span class="e-opened">{{{ itemTitleIconActive.value }}}</span>
864 <span class="e-closed">{{{ itemTitleIcon.value }}}</span>
865 </span>
866 <# } #>
867 </summary>
868 </details>
869 <# } ); #>
870 <# } #>
871 </div>
872 <?php
873 }
874 }
875