PluginProbe
Elementor Website Builder – more than just a page builder / 3.11.2
Elementor Website Builder – more than just a page builder v3.11.2
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 / widgets / accordion.php

accordion.php in Elementor Website Builder – more than just a page builder 3.11.2, at includes/widgets/accordion.php

681 lines 18.7 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 use Elementor\Core\Kits\Documents\Tabs\Global_Colors;
9 use Elementor\Core\Kits\Documents\Tabs\Global_Typography;
10 /**
11 * Elementor accordion widget.
12 *
13 * Elementor widget that displays a collapsible display of content in an
14 * accordion style, showing only one item at a time.
15 *
16 * @since 1.0.0
17 */
18 class Widget_Accordion extends Widget_Base {
19
20 /**
21 * Get widget name.
22 *
23 * Retrieve accordion widget name.
24 *
25 * @since 1.0.0
26 * @access public
27 *
28 * @return string Widget name.
29 */
30 public function get_name() {
31 return 'accordion';
32 }
33
34 /**
35 * Get widget title.
36 *
37 * Retrieve accordion widget title.
38 *
39 * @since 1.0.0
40 * @access public
41 *
42 * @return string Widget title.
43 */
44 public function get_title() {
45 return esc_html__( 'Accordion', 'elementor' );
46 }
47
48 /**
49 * Get widget icon.
50 *
51 * Retrieve accordion widget icon.
52 *
53 * @since 1.0.0
54 * @access public
55 *
56 * @return string Widget icon.
57 */
58 public function get_icon() {
59 return 'eicon-accordion';
60 }
61
62 /**
63 * Get widget keywords.
64 *
65 * Retrieve the list of keywords the widget belongs to.
66 *
67 * @since 2.1.0
68 * @access public
69 *
70 * @return array Widget keywords.
71 */
72 public function get_keywords() {
73 return [ 'accordion', 'tabs', 'toggle' ];
74 }
75
76 /**
77 * Register accordion widget controls.
78 *
79 * Adds different input fields to allow the user to change and customize the widget settings.
80 *
81 * @since 3.1.0
82 * @access protected
83 */
84 protected function register_controls() {
85 $this->start_controls_section(
86 'section_title',
87 [
88 'label' => esc_html__( 'Accordion', 'elementor' ),
89 ]
90 );
91
92 $repeater = new Repeater();
93
94 $repeater->add_control(
95 'tab_title',
96 [
97 'label' => esc_html__( 'Title & Description', 'elementor' ),
98 'type' => Controls_Manager::TEXT,
99 'default' => esc_html__( 'Accordion Title', 'elementor' ),
100 'dynamic' => [
101 'active' => true,
102 ],
103 'label_block' => true,
104 ]
105 );
106
107 $repeater->add_control(
108 'tab_content',
109 [
110 'label' => esc_html__( 'Content', 'elementor' ),
111 'type' => Controls_Manager::WYSIWYG,
112 'default' => esc_html__( 'Accordion Content', 'elementor' ),
113 'show_label' => false,
114 ]
115 );
116
117 $this->add_control(
118 'tabs',
119 [
120 'label' => esc_html__( 'Accordion Items', 'elementor' ),
121 'type' => Controls_Manager::REPEATER,
122 'fields' => $repeater->get_controls(),
123 'default' => [
124 [
125 'tab_title' => esc_html__( 'Accordion #1', 'elementor' ),
126 'tab_content' => esc_html__( 'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Ut elit tellus, luctus nec ullamcorper mattis, pulvinar dapibus leo.', 'elementor' ),
127 ],
128 [
129 'tab_title' => esc_html__( 'Accordion #2', 'elementor' ),
130 'tab_content' => esc_html__( 'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Ut elit tellus, luctus nec ullamcorper mattis, pulvinar dapibus leo.', 'elementor' ),
131 ],
132 ],
133 'title_field' => '{{{ tab_title }}}',
134 ]
135 );
136
137 $this->add_control(
138 'view',
139 [
140 'label' => esc_html__( 'View', 'elementor' ),
141 'type' => Controls_Manager::HIDDEN,
142 'default' => 'traditional',
143 ]
144 );
145
146 $this->add_control(
147 'selected_icon',
148 [
149 'label' => esc_html__( 'Icon', 'elementor' ),
150 'type' => Controls_Manager::ICONS,
151 'separator' => 'before',
152 'fa4compatibility' => 'icon',
153 'default' => [
154 'value' => 'fas fa-plus',
155 'library' => 'fa-solid',
156 ],
157 'recommended' => [
158 'fa-solid' => [
159 'chevron-down',
160 'angle-down',
161 'angle-double-down',
162 'caret-down',
163 'caret-square-down',
164 ],
165 'fa-regular' => [
166 'caret-square-down',
167 ],
168 ],
169 'skin' => 'inline',
170 'label_block' => false,
171 ]
172 );
173
174 $this->add_control(
175 'selected_active_icon',
176 [
177 'label' => esc_html__( 'Active Icon', 'elementor' ),
178 'type' => Controls_Manager::ICONS,
179 'fa4compatibility' => 'icon_active',
180 'default' => [
181 'value' => 'fas fa-minus',
182 'library' => 'fa-solid',
183 ],
184 'recommended' => [
185 'fa-solid' => [
186 'chevron-up',
187 'angle-up',
188 'angle-double-up',
189 'caret-up',
190 'caret-square-up',
191 ],
192 'fa-regular' => [
193 'caret-square-up',
194 ],
195 ],
196 'skin' => 'inline',
197 'label_block' => false,
198 'condition' => [
199 'selected_icon[value]!' => '',
200 ],
201 ]
202 );
203
204 $this->add_control(
205 'title_html_tag',
206 [
207 'label' => esc_html__( 'Title HTML Tag', 'elementor' ),
208 'type' => Controls_Manager::SELECT,
209 'options' => [
210 'h1' => 'H1',
211 'h2' => 'H2',
212 'h3' => 'H3',
213 'h4' => 'H4',
214 'h5' => 'H5',
215 'h6' => 'H6',
216 'div' => 'div',
217 ],
218 'default' => 'div',
219 'separator' => 'before',
220 ]
221 );
222
223 $this->add_control(
224 'faq_schema',
225 [
226 'label' => esc_html__( 'FAQ Schema', 'elementor' ),
227 'type' => Controls_Manager::SWITCHER,
228 'separator' => 'before',
229 ]
230 );
231
232 $this->end_controls_section();
233
234 $this->start_controls_section(
235 'section_title_style',
236 [
237 'label' => esc_html__( 'Accordion', 'elementor' ),
238 'tab' => Controls_Manager::TAB_STYLE,
239 ]
240 );
241
242 $this->add_control(
243 'border_width',
244 [
245 'label' => esc_html__( 'Border Width', 'elementor' ),
246 'type' => Controls_Manager::SLIDER,
247 'size_units' => [ 'px', '%', 'em' ],
248 'range' => [
249 'px' => [
250 'max' => 20,
251 ],
252 'em' => [
253 'max' => 2,
254 ],
255 ],
256 'selectors' => [
257 '{{WRAPPER}} .elementor-accordion-item' => 'border-width: {{SIZE}}{{UNIT}};',
258 '{{WRAPPER}} .elementor-accordion-item .elementor-tab-content' => 'border-width: {{SIZE}}{{UNIT}};',
259 '{{WRAPPER}} .elementor-accordion-item .elementor-tab-title.elementor-active' => 'border-width: {{SIZE}}{{UNIT}};',
260 ],
261 ]
262 );
263
264 $this->add_control(
265 'border_color',
266 [
267 'label' => esc_html__( 'Border Color', 'elementor' ),
268 'type' => Controls_Manager::COLOR,
269 'selectors' => [
270 '{{WRAPPER}} .elementor-accordion-item' => 'border-color: {{VALUE}};',
271 '{{WRAPPER}} .elementor-accordion-item .elementor-tab-content' => 'border-top-color: {{VALUE}};',
272 '{{WRAPPER}} .elementor-accordion-item .elementor-tab-title.elementor-active' => 'border-bottom-color: {{VALUE}};',
273 ],
274 ]
275 );
276
277 $this->end_controls_section();
278
279 $this->start_controls_section(
280 'section_toggle_style_title',
281 [
282 'label' => esc_html__( 'Title', 'elementor' ),
283 'tab' => Controls_Manager::TAB_STYLE,
284 ]
285 );
286
287 $this->add_control(
288 'title_background',
289 [
290 'label' => esc_html__( 'Background', 'elementor' ),
291 'type' => Controls_Manager::COLOR,
292 'selectors' => [
293 '{{WRAPPER}} .elementor-tab-title' => 'background-color: {{VALUE}};',
294 ],
295 ]
296 );
297
298 $this->add_control(
299 'title_color',
300 [
301 'label' => esc_html__( 'Color', 'elementor' ),
302 'type' => Controls_Manager::COLOR,
303 'selectors' => [
304 '{{WRAPPER}} .elementor-accordion-icon, {{WRAPPER}} .elementor-accordion-title' => 'color: {{VALUE}};',
305 '{{WRAPPER}} .elementor-accordion-icon svg' => 'fill: {{VALUE}};',
306 ],
307 'global' => [
308 'default' => Global_Colors::COLOR_PRIMARY,
309 ],
310 ]
311 );
312
313 $this->add_control(
314 'tab_active_color',
315 [
316 'label' => esc_html__( 'Active Color', 'elementor' ),
317 'type' => Controls_Manager::COLOR,
318 'selectors' => [
319 '{{WRAPPER}} .elementor-active .elementor-accordion-icon, {{WRAPPER}} .elementor-active .elementor-accordion-title' => 'color: {{VALUE}};',
320 '{{WRAPPER}} .elementor-active .elementor-accordion-icon svg' => 'fill: {{VALUE}};',
321 ],
322 'global' => [
323 'default' => Global_Colors::COLOR_ACCENT,
324 ],
325 ]
326 );
327
328 $this->add_group_control(
329 Group_Control_Typography::get_type(),
330 [
331 'name' => 'title_typography',
332 'selector' => '{{WRAPPER}} .elementor-accordion-title',
333 'global' => [
334 'default' => Global_Typography::TYPOGRAPHY_PRIMARY,
335 ],
336 ]
337 );
338
339 $this->add_group_control(
340 Group_Control_Text_Stroke::get_type(),
341 [
342 'name' => 'text_stroke',
343 'selector' => '{{WRAPPER}} .elementor-accordion-title',
344 ]
345 );
346
347 $this->add_group_control(
348 Group_Control_Text_Shadow::get_type(),
349 [
350 'name' => 'title_shadow',
351 'selector' => '{{WRAPPER}} .elementor-accordion-title',
352 ]
353 );
354
355 $this->add_responsive_control(
356 'title_padding',
357 [
358 'label' => esc_html__( 'Padding', 'elementor' ),
359 'type' => Controls_Manager::DIMENSIONS,
360 'size_units' => [ 'px', 'em', '%' ],
361 'selectors' => [
362 '{{WRAPPER}} .elementor-tab-title' => 'padding: {{TOP}}{{UNIT}} {{RIGHT}}{{UNIT}} {{BOTTOM}}{{UNIT}} {{LEFT}}{{UNIT}};',
363 ],
364 ]
365 );
366
367 $this->end_controls_section();
368
369 $this->start_controls_section(
370 'section_toggle_style_icon',
371 [
372 'label' => esc_html__( 'Icon', 'elementor' ),
373 'tab' => Controls_Manager::TAB_STYLE,
374 'condition' => [
375 'selected_icon[value]!' => '',
376 ],
377 ]
378 );
379
380 $this->add_control(
381 'icon_align',
382 [
383 'label' => esc_html__( 'Alignment', 'elementor' ),
384 'type' => Controls_Manager::CHOOSE,
385 'options' => [
386 'left' => [
387 'title' => esc_html__( 'Start', 'elementor' ),
388 'icon' => 'eicon-h-align-left',
389 ],
390 'right' => [
391 'title' => esc_html__( 'End', 'elementor' ),
392 'icon' => 'eicon-h-align-right',
393 ],
394 ],
395 'default' => is_rtl() ? 'right' : 'left',
396 'toggle' => false,
397 ]
398 );
399
400 $this->add_control(
401 'icon_color',
402 [
403 'label' => esc_html__( 'Color', 'elementor' ),
404 'type' => Controls_Manager::COLOR,
405 'selectors' => [
406 '{{WRAPPER}} .elementor-tab-title .elementor-accordion-icon i:before' => 'color: {{VALUE}};',
407 '{{WRAPPER}} .elementor-tab-title .elementor-accordion-icon svg' => 'fill: {{VALUE}};',
408 ],
409 ]
410 );
411
412 $this->add_control(
413 'icon_active_color',
414 [
415 'label' => esc_html__( 'Active Color', 'elementor' ),
416 'type' => Controls_Manager::COLOR,
417 'selectors' => [
418 '{{WRAPPER}} .elementor-tab-title.elementor-active .elementor-accordion-icon i:before' => 'color: {{VALUE}};',
419 '{{WRAPPER}} .elementor-tab-title.elementor-active .elementor-accordion-icon svg' => 'fill: {{VALUE}};',
420 ],
421 ]
422 );
423
424 $this->add_responsive_control(
425 'icon_space',
426 [
427 'label' => esc_html__( 'Spacing', 'elementor' ),
428 'type' => Controls_Manager::SLIDER,
429 'range' => [
430 'px' => [
431 'min' => 0,
432 'max' => 100,
433 ],
434 ],
435 'selectors' => [
436 '{{WRAPPER}} .elementor-accordion-icon.elementor-accordion-icon-left' => 'margin-right: {{SIZE}}{{UNIT}};',
437 '{{WRAPPER}} .elementor-accordion-icon.elementor-accordion-icon-right' => 'margin-left: {{SIZE}}{{UNIT}};',
438 ],
439 ]
440 );
441
442 $this->end_controls_section();
443
444 $this->start_controls_section(
445 'section_toggle_style_content',
446 [
447 'label' => esc_html__( 'Content', 'elementor' ),
448 'tab' => Controls_Manager::TAB_STYLE,
449 ]
450 );
451
452 $this->add_control(
453 'content_background_color',
454 [
455 'label' => esc_html__( 'Background', 'elementor' ),
456 'type' => Controls_Manager::COLOR,
457 'selectors' => [
458 '{{WRAPPER}} .elementor-tab-content' => 'background-color: {{VALUE}};',
459 ],
460 ]
461 );
462
463 $this->add_control(
464 'content_color',
465 [
466 'label' => esc_html__( 'Color', 'elementor' ),
467 'type' => Controls_Manager::COLOR,
468 'selectors' => [
469 '{{WRAPPER}} .elementor-tab-content' => 'color: {{VALUE}};',
470 ],
471 'global' => [
472 'default' => Global_Colors::COLOR_TEXT,
473 ],
474 ]
475 );
476
477 $this->add_group_control(
478 Group_Control_Typography::get_type(),
479 [
480 'name' => 'content_typography',
481 'selector' => '{{WRAPPER}} .elementor-tab-content',
482 'global' => [
483 'default' => Global_Typography::TYPOGRAPHY_TEXT,
484 ],
485 ]
486 );
487
488 $this->add_group_control(
489 Group_Control_Text_Shadow::get_type(),
490 [
491 'name' => 'content_shadow',
492 'selector' => '{{WRAPPER}} .elementor-tab-content',
493 ]
494 );
495
496 $this->add_responsive_control(
497 'content_padding',
498 [
499 'label' => esc_html__( 'Padding', 'elementor' ),
500 'type' => Controls_Manager::DIMENSIONS,
501 'size_units' => [ 'px', 'em', '%' ],
502 'selectors' => [
503 '{{WRAPPER}} .elementor-tab-content' => 'padding: {{TOP}}{{UNIT}} {{RIGHT}}{{UNIT}} {{BOTTOM}}{{UNIT}} {{LEFT}}{{UNIT}};',
504 ],
505 ]
506 );
507
508 $this->end_controls_section();
509 }
510
511 /**
512 * Render accordion widget output on the frontend.
513 *
514 * Written in PHP and used to generate the final HTML.
515 *
516 * @since 1.0.0
517 * @access protected
518 */
519 protected function render() {
520 $settings = $this->get_settings_for_display();
521 $migrated = isset( $settings['__fa4_migrated']['selected_icon'] );
522
523 if ( ! isset( $settings['icon'] ) && ! Icons_Manager::is_migration_allowed() ) {
524 // @todo: remove when deprecated
525 // added as bc in 2.6
526 // add old default
527 $settings['icon'] = 'fa fa-plus';
528 $settings['icon_active'] = 'fa fa-minus';
529 $settings['icon_align'] = $this->get_settings( 'icon_align' );
530 }
531
532 $is_new = empty( $settings['icon'] ) && Icons_Manager::is_migration_allowed();
533 $has_icon = ( ! $is_new || ! empty( $settings['selected_icon']['value'] ) );
534 $id_int = substr( $this->get_id_int(), 0, 3 );
535 ?>
536 <div class="elementor-accordion" role="tablist">
537 <?php
538 foreach ( $settings['tabs'] as $index => $item ) :
539 $tab_count = $index + 1;
540
541 $tab_title_setting_key = $this->get_repeater_setting_key( 'tab_title', 'tabs', $index );
542
543 $tab_content_setting_key = $this->get_repeater_setting_key( 'tab_content', 'tabs', $index );
544
545 $this->add_render_attribute( $tab_title_setting_key, [
546 'id' => 'elementor-tab-title-' . $id_int . $tab_count,
547 'class' => [ 'elementor-tab-title' ],
548 'data-tab' => $tab_count,
549 'role' => 'tab',
550 'aria-controls' => 'elementor-tab-content-' . $id_int . $tab_count,
551 'aria-expanded' => 'false',
552 ] );
553
554 $this->add_render_attribute( $tab_content_setting_key, [
555 'id' => 'elementor-tab-content-' . $id_int . $tab_count,
556 'class' => [ 'elementor-tab-content', 'elementor-clearfix' ],
557 'data-tab' => $tab_count,
558 'role' => 'tabpanel',
559 'aria-labelledby' => 'elementor-tab-title-' . $id_int . $tab_count,
560 ] );
561
562 $this->add_inline_editing_attributes( $tab_content_setting_key, 'advanced' );
563 ?>
564 <div class="elementor-accordion-item">
565 <<?php Utils::print_validated_html_tag( $settings['title_html_tag'] ); ?> <?php $this->print_render_attribute_string( $tab_title_setting_key ); ?>>
566 <?php if ( $has_icon ) : ?>
567 <span class="elementor-accordion-icon elementor-accordion-icon-<?php echo esc_attr( $settings['icon_align'] ); ?>" aria-hidden="true">
568 <?php
569 if ( $is_new || $migrated ) { ?>
570 <span class="elementor-accordion-icon-closed"><?php Icons_Manager::render_icon( $settings['selected_icon'] ); ?></span>
571 <span class="elementor-accordion-icon-opened"><?php Icons_Manager::render_icon( $settings['selected_active_icon'] ); ?></span>
572 <?php } else { ?>
573 <i class="elementor-accordion-icon-closed <?php echo esc_attr( $settings['icon'] ); ?>"></i>
574 <i class="elementor-accordion-icon-opened <?php echo esc_attr( $settings['icon_active'] ); ?>"></i>
575 <?php } ?>
576 </span>
577 <?php endif; ?>
578 <a class="elementor-accordion-title" href=""><?php
579 $this->print_unescaped_setting( 'tab_title', 'tabs', $index );
580 ?></a>
581 </<?php Utils::print_validated_html_tag( $settings['title_html_tag'] ); ?>>
582 <div <?php $this->print_render_attribute_string( $tab_content_setting_key ); ?>><?php
583 $this->print_text_editor( $item['tab_content'] );
584 ?></div>
585 </div>
586 <?php endforeach; ?>
587 <?php
588 if ( isset( $settings['faq_schema'] ) && 'yes' === $settings['faq_schema'] ) {
589 $json = [
590 '@context' => 'https://schema.org',
591 '@type' => 'FAQPage',
592 'mainEntity' => [],
593 ];
594
595 foreach ( $settings['tabs'] as $index => $item ) {
596 $json['mainEntity'][] = [
597 '@type' => 'Question',
598 'name' => wp_strip_all_tags( $item['tab_title'] ),
599 'acceptedAnswer' => [
600 '@type' => 'Answer',
601 'text' => $this->parse_text_editor( $item['tab_content'] ),
602 ],
603 ];
604 }
605 ?>
606 <script type="application/ld+json"><?php echo wp_json_encode( $json ); ?></script>
607 <?php } ?>
608 </div>
609 <?php
610 }
611
612 /**
613 * Render accordion widget output in the editor.
614 *
615 * Written as a Backbone JavaScript template and used to generate the live preview.
616 *
617 * @since 2.9.0
618 * @access protected
619 */
620 protected function content_template() {
621 ?>
622 <div class="elementor-accordion" role="tablist">
623 <#
624 if ( settings.tabs ) {
625 var tabindex = view.getIDInt().toString().substr( 0, 3 ),
626 iconHTML = elementor.helpers.renderIcon( view, settings.selected_icon, {}, 'i' , 'object' ),
627 iconActiveHTML = elementor.helpers.renderIcon( view, settings.selected_active_icon, {}, 'i' , 'object' ),
628 migrated = elementor.helpers.isIconMigrated( settings, 'selected_icon' );
629
630 _.each( settings.tabs, function( item, index ) {
631 var tabCount = index + 1,
632 tabTitleKey = view.getRepeaterSettingKey( 'tab_title', 'tabs', index ),
633 tabContentKey = view.getRepeaterSettingKey( 'tab_content', 'tabs', index );
634
635 view.addRenderAttribute( tabTitleKey, {
636 'id': 'elementor-tab-title-' + tabindex + tabCount,
637 'class': [ 'elementor-tab-title' ],
638 'tabindex': tabindex + tabCount,
639 'data-tab': tabCount,
640 'role': 'tab',
641 'aria-controls': 'elementor-tab-content-' + tabindex + tabCount,
642 'aria-expanded': 'false',
643 } );
644
645 view.addRenderAttribute( tabContentKey, {
646 'id': 'elementor-tab-content-' + tabindex + tabCount,
647 'class': [ 'elementor-tab-content', 'elementor-clearfix' ],
648 'data-tab': tabCount,
649 'role': 'tabpanel',
650 'aria-labelledby': 'elementor-tab-title-' + tabindex + tabCount
651 } );
652
653 view.addInlineEditingAttributes( tabContentKey, 'advanced' );
654
655 var titleHTMLTag = elementor.helpers.validateHTMLTag( settings.title_html_tag );
656 #>
657 <div class="elementor-accordion-item">
658 <{{{ titleHTMLTag }}} {{{ view.getRenderAttributeString( tabTitleKey ) }}}>
659 <# if ( settings.icon || settings.selected_icon ) { #>
660 <span class="elementor-accordion-icon elementor-accordion-icon-{{ settings.icon_align }}" aria-hidden="true">
661 <# if ( iconHTML && iconHTML.rendered && ( ! settings.icon || migrated ) ) { #>
662 <span class="elementor-accordion-icon-closed">{{{ iconHTML.value }}}</span>
663 <span class="elementor-accordion-icon-opened">{{{ iconActiveHTML.value }}}</span>
664 <# } else { #>
665 <i class="elementor-accordion-icon-closed {{ settings.icon }}"></i>
666 <i class="elementor-accordion-icon-opened {{ settings.icon_active }}"></i>
667 <# } #>
668 </span>
669 <# } #>
670 <a class="elementor-accordion-title" href="">{{{ item.tab_title }}}</a>
671 </{{{ titleHTMLTag }}}>
672 <div {{{ view.getRenderAttributeString( tabContentKey ) }}}>{{{ item.tab_content }}}</div>
673 </div>
674 <#
675 } );
676 } #>
677 </div>
678 <?php
679 }
680 }
681