PluginProbe
Elementor Website Builder – more than just a page builder / 3.7.0
Elementor Website Builder – more than just a page builder v3.7.0
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.7.0, at includes/widgets/accordion.php

678 lines 18.6 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 'range' => [
248 'px' => [
249 'min' => 0,
250 'max' => 10,
251 ],
252 ],
253 'selectors' => [
254 '{{WRAPPER}} .elementor-accordion-item' => 'border-width: {{SIZE}}{{UNIT}};',
255 '{{WRAPPER}} .elementor-accordion-item .elementor-tab-content' => 'border-width: {{SIZE}}{{UNIT}};',
256 '{{WRAPPER}} .elementor-accordion-item .elementor-tab-title.elementor-active' => 'border-width: {{SIZE}}{{UNIT}};',
257 ],
258 ]
259 );
260
261 $this->add_control(
262 'border_color',
263 [
264 'label' => esc_html__( 'Border Color', 'elementor' ),
265 'type' => Controls_Manager::COLOR,
266 'selectors' => [
267 '{{WRAPPER}} .elementor-accordion-item' => 'border-color: {{VALUE}};',
268 '{{WRAPPER}} .elementor-accordion-item .elementor-tab-content' => 'border-top-color: {{VALUE}};',
269 '{{WRAPPER}} .elementor-accordion-item .elementor-tab-title.elementor-active' => 'border-bottom-color: {{VALUE}};',
270 ],
271 ]
272 );
273
274 $this->end_controls_section();
275
276 $this->start_controls_section(
277 'section_toggle_style_title',
278 [
279 'label' => esc_html__( 'Title', 'elementor' ),
280 'tab' => Controls_Manager::TAB_STYLE,
281 ]
282 );
283
284 $this->add_control(
285 'title_background',
286 [
287 'label' => esc_html__( 'Background', 'elementor' ),
288 'type' => Controls_Manager::COLOR,
289 'selectors' => [
290 '{{WRAPPER}} .elementor-tab-title' => 'background-color: {{VALUE}};',
291 ],
292 ]
293 );
294
295 $this->add_control(
296 'title_color',
297 [
298 'label' => esc_html__( 'Color', 'elementor' ),
299 'type' => Controls_Manager::COLOR,
300 'selectors' => [
301 '{{WRAPPER}} .elementor-accordion-icon, {{WRAPPER}} .elementor-accordion-title' => 'color: {{VALUE}};',
302 '{{WRAPPER}} .elementor-accordion-icon svg' => 'fill: {{VALUE}};',
303 ],
304 'global' => [
305 'default' => Global_Colors::COLOR_PRIMARY,
306 ],
307 ]
308 );
309
310 $this->add_control(
311 'tab_active_color',
312 [
313 'label' => esc_html__( 'Active Color', 'elementor' ),
314 'type' => Controls_Manager::COLOR,
315 'selectors' => [
316 '{{WRAPPER}} .elementor-active .elementor-accordion-icon, {{WRAPPER}} .elementor-active .elementor-accordion-title' => 'color: {{VALUE}};',
317 '{{WRAPPER}} .elementor-active .elementor-accordion-icon svg' => 'fill: {{VALUE}};',
318 ],
319 'global' => [
320 'default' => Global_Colors::COLOR_ACCENT,
321 ],
322 ]
323 );
324
325 $this->add_group_control(
326 Group_Control_Typography::get_type(),
327 [
328 'name' => 'title_typography',
329 'selector' => '{{WRAPPER}} .elementor-accordion-title',
330 'global' => [
331 'default' => Global_Typography::TYPOGRAPHY_PRIMARY,
332 ],
333 ]
334 );
335
336 $this->add_group_control(
337 Group_Control_Text_Stroke::get_type(),
338 [
339 'name' => 'text_stroke',
340 'selector' => '{{WRAPPER}} .elementor-accordion-title',
341 ]
342 );
343
344 $this->add_group_control(
345 Group_Control_Text_Shadow::get_type(),
346 [
347 'name' => 'title_shadow',
348 'selector' => '{{WRAPPER}} .elementor-accordion-title',
349 ]
350 );
351
352 $this->add_responsive_control(
353 'title_padding',
354 [
355 'label' => esc_html__( 'Padding', 'elementor' ),
356 'type' => Controls_Manager::DIMENSIONS,
357 'size_units' => [ 'px', 'em', '%' ],
358 'selectors' => [
359 '{{WRAPPER}} .elementor-tab-title' => 'padding: {{TOP}}{{UNIT}} {{RIGHT}}{{UNIT}} {{BOTTOM}}{{UNIT}} {{LEFT}}{{UNIT}};',
360 ],
361 ]
362 );
363
364 $this->end_controls_section();
365
366 $this->start_controls_section(
367 'section_toggle_style_icon',
368 [
369 'label' => esc_html__( 'Icon', 'elementor' ),
370 'tab' => Controls_Manager::TAB_STYLE,
371 'condition' => [
372 'selected_icon[value]!' => '',
373 ],
374 ]
375 );
376
377 $this->add_control(
378 'icon_align',
379 [
380 'label' => esc_html__( 'Alignment', 'elementor' ),
381 'type' => Controls_Manager::CHOOSE,
382 'options' => [
383 'left' => [
384 'title' => esc_html__( 'Start', 'elementor' ),
385 'icon' => 'eicon-h-align-left',
386 ],
387 'right' => [
388 'title' => esc_html__( 'End', 'elementor' ),
389 'icon' => 'eicon-h-align-right',
390 ],
391 ],
392 'default' => is_rtl() ? 'right' : 'left',
393 'toggle' => false,
394 ]
395 );
396
397 $this->add_control(
398 'icon_color',
399 [
400 'label' => esc_html__( 'Color', 'elementor' ),
401 'type' => Controls_Manager::COLOR,
402 'selectors' => [
403 '{{WRAPPER}} .elementor-tab-title .elementor-accordion-icon i:before' => 'color: {{VALUE}};',
404 '{{WRAPPER}} .elementor-tab-title .elementor-accordion-icon svg' => 'fill: {{VALUE}};',
405 ],
406 ]
407 );
408
409 $this->add_control(
410 'icon_active_color',
411 [
412 'label' => esc_html__( 'Active Color', 'elementor' ),
413 'type' => Controls_Manager::COLOR,
414 'selectors' => [
415 '{{WRAPPER}} .elementor-tab-title.elementor-active .elementor-accordion-icon i:before' => 'color: {{VALUE}};',
416 '{{WRAPPER}} .elementor-tab-title.elementor-active .elementor-accordion-icon svg' => 'fill: {{VALUE}};',
417 ],
418 ]
419 );
420
421 $this->add_responsive_control(
422 'icon_space',
423 [
424 'label' => esc_html__( 'Spacing', 'elementor' ),
425 'type' => Controls_Manager::SLIDER,
426 'range' => [
427 'px' => [
428 'min' => 0,
429 'max' => 100,
430 ],
431 ],
432 'selectors' => [
433 '{{WRAPPER}} .elementor-accordion-icon.elementor-accordion-icon-left' => 'margin-right: {{SIZE}}{{UNIT}};',
434 '{{WRAPPER}} .elementor-accordion-icon.elementor-accordion-icon-right' => 'margin-left: {{SIZE}}{{UNIT}};',
435 ],
436 ]
437 );
438
439 $this->end_controls_section();
440
441 $this->start_controls_section(
442 'section_toggle_style_content',
443 [
444 'label' => esc_html__( 'Content', 'elementor' ),
445 'tab' => Controls_Manager::TAB_STYLE,
446 ]
447 );
448
449 $this->add_control(
450 'content_background_color',
451 [
452 'label' => esc_html__( 'Background', 'elementor' ),
453 'type' => Controls_Manager::COLOR,
454 'selectors' => [
455 '{{WRAPPER}} .elementor-tab-content' => 'background-color: {{VALUE}};',
456 ],
457 ]
458 );
459
460 $this->add_control(
461 'content_color',
462 [
463 'label' => esc_html__( 'Color', 'elementor' ),
464 'type' => Controls_Manager::COLOR,
465 'selectors' => [
466 '{{WRAPPER}} .elementor-tab-content' => 'color: {{VALUE}};',
467 ],
468 'global' => [
469 'default' => Global_Colors::COLOR_TEXT,
470 ],
471 ]
472 );
473
474 $this->add_group_control(
475 Group_Control_Typography::get_type(),
476 [
477 'name' => 'content_typography',
478 'selector' => '{{WRAPPER}} .elementor-tab-content',
479 'global' => [
480 'default' => Global_Typography::TYPOGRAPHY_TEXT,
481 ],
482 ]
483 );
484
485 $this->add_group_control(
486 Group_Control_Text_Shadow::get_type(),
487 [
488 'name' => 'content_shadow',
489 'selector' => '{{WRAPPER}} .elementor-tab-content',
490 ]
491 );
492
493 $this->add_responsive_control(
494 'content_padding',
495 [
496 'label' => esc_html__( 'Padding', 'elementor' ),
497 'type' => Controls_Manager::DIMENSIONS,
498 'size_units' => [ 'px', 'em', '%' ],
499 'selectors' => [
500 '{{WRAPPER}} .elementor-tab-content' => 'padding: {{TOP}}{{UNIT}} {{RIGHT}}{{UNIT}} {{BOTTOM}}{{UNIT}} {{LEFT}}{{UNIT}};',
501 ],
502 ]
503 );
504
505 $this->end_controls_section();
506 }
507
508 /**
509 * Render accordion widget output on the frontend.
510 *
511 * Written in PHP and used to generate the final HTML.
512 *
513 * @since 1.0.0
514 * @access protected
515 */
516 protected function render() {
517 $settings = $this->get_settings_for_display();
518 $migrated = isset( $settings['__fa4_migrated']['selected_icon'] );
519
520 if ( ! isset( $settings['icon'] ) && ! Icons_Manager::is_migration_allowed() ) {
521 // @todo: remove when deprecated
522 // added as bc in 2.6
523 // add old default
524 $settings['icon'] = 'fa fa-plus';
525 $settings['icon_active'] = 'fa fa-minus';
526 $settings['icon_align'] = $this->get_settings( 'icon_align' );
527 }
528
529 $is_new = empty( $settings['icon'] ) && Icons_Manager::is_migration_allowed();
530 $has_icon = ( ! $is_new || ! empty( $settings['selected_icon']['value'] ) );
531 $id_int = substr( $this->get_id_int(), 0, 3 );
532 ?>
533 <div class="elementor-accordion" role="tablist">
534 <?php
535 foreach ( $settings['tabs'] as $index => $item ) :
536 $tab_count = $index + 1;
537
538 $tab_title_setting_key = $this->get_repeater_setting_key( 'tab_title', 'tabs', $index );
539
540 $tab_content_setting_key = $this->get_repeater_setting_key( 'tab_content', 'tabs', $index );
541
542 $this->add_render_attribute( $tab_title_setting_key, [
543 'id' => 'elementor-tab-title-' . $id_int . $tab_count,
544 'class' => [ 'elementor-tab-title' ],
545 'data-tab' => $tab_count,
546 'role' => 'tab',
547 'aria-controls' => 'elementor-tab-content-' . $id_int . $tab_count,
548 'aria-expanded' => 'false',
549 ] );
550
551 $this->add_render_attribute( $tab_content_setting_key, [
552 'id' => 'elementor-tab-content-' . $id_int . $tab_count,
553 'class' => [ 'elementor-tab-content', 'elementor-clearfix' ],
554 'data-tab' => $tab_count,
555 'role' => 'tabpanel',
556 'aria-labelledby' => 'elementor-tab-title-' . $id_int . $tab_count,
557 ] );
558
559 $this->add_inline_editing_attributes( $tab_content_setting_key, 'advanced' );
560 ?>
561 <div class="elementor-accordion-item">
562 <<?php Utils::print_validated_html_tag( $settings['title_html_tag'] ); ?> <?php $this->print_render_attribute_string( $tab_title_setting_key ); ?>>
563 <?php if ( $has_icon ) : ?>
564 <span class="elementor-accordion-icon elementor-accordion-icon-<?php echo esc_attr( $settings['icon_align'] ); ?>" aria-hidden="true">
565 <?php
566 if ( $is_new || $migrated ) { ?>
567 <span class="elementor-accordion-icon-closed"><?php Icons_Manager::render_icon( $settings['selected_icon'] ); ?></span>
568 <span class="elementor-accordion-icon-opened"><?php Icons_Manager::render_icon( $settings['selected_active_icon'] ); ?></span>
569 <?php } else { ?>
570 <i class="elementor-accordion-icon-closed <?php echo esc_attr( $settings['icon'] ); ?>"></i>
571 <i class="elementor-accordion-icon-opened <?php echo esc_attr( $settings['icon_active'] ); ?>"></i>
572 <?php } ?>
573 </span>
574 <?php endif; ?>
575 <a class="elementor-accordion-title" href=""><?php
576 $this->print_unescaped_setting( 'tab_title', 'tabs', $index );
577 ?></a>
578 </<?php Utils::print_validated_html_tag( $settings['title_html_tag'] ); ?>>
579 <div <?php $this->print_render_attribute_string( $tab_content_setting_key ); ?>><?php
580 $this->print_text_editor( $item['tab_content'] );
581 ?></div>
582 </div>
583 <?php endforeach; ?>
584 <?php
585 if ( isset( $settings['faq_schema'] ) && 'yes' === $settings['faq_schema'] ) {
586 $json = [
587 '@context' => 'https://schema.org',
588 '@type' => 'FAQPage',
589 'mainEntity' => [],
590 ];
591
592 foreach ( $settings['tabs'] as $index => $item ) {
593 $json['mainEntity'][] = [
594 '@type' => 'Question',
595 'name' => wp_strip_all_tags( $item['tab_title'] ),
596 'acceptedAnswer' => [
597 '@type' => 'Answer',
598 'text' => $this->parse_text_editor( $item['tab_content'] ),
599 ],
600 ];
601 }
602 ?>
603 <script type="application/ld+json"><?php echo wp_json_encode( $json ); ?></script>
604 <?php } ?>
605 </div>
606 <?php
607 }
608
609 /**
610 * Render accordion widget output in the editor.
611 *
612 * Written as a Backbone JavaScript template and used to generate the live preview.
613 *
614 * @since 2.9.0
615 * @access protected
616 */
617 protected function content_template() {
618 ?>
619 <div class="elementor-accordion" role="tablist">
620 <#
621 if ( settings.tabs ) {
622 var tabindex = view.getIDInt().toString().substr( 0, 3 ),
623 iconHTML = elementor.helpers.renderIcon( view, settings.selected_icon, {}, 'i' , 'object' ),
624 iconActiveHTML = elementor.helpers.renderIcon( view, settings.selected_active_icon, {}, 'i' , 'object' ),
625 migrated = elementor.helpers.isIconMigrated( settings, 'selected_icon' );
626
627 _.each( settings.tabs, function( item, index ) {
628 var tabCount = index + 1,
629 tabTitleKey = view.getRepeaterSettingKey( 'tab_title', 'tabs', index ),
630 tabContentKey = view.getRepeaterSettingKey( 'tab_content', 'tabs', index );
631
632 view.addRenderAttribute( tabTitleKey, {
633 'id': 'elementor-tab-title-' + tabindex + tabCount,
634 'class': [ 'elementor-tab-title' ],
635 'tabindex': tabindex + tabCount,
636 'data-tab': tabCount,
637 'role': 'tab',
638 'aria-controls': 'elementor-tab-content-' + tabindex + tabCount,
639 'aria-expanded': 'false',
640 } );
641
642 view.addRenderAttribute( tabContentKey, {
643 'id': 'elementor-tab-content-' + tabindex + tabCount,
644 'class': [ 'elementor-tab-content', 'elementor-clearfix' ],
645 'data-tab': tabCount,
646 'role': 'tabpanel',
647 'aria-labelledby': 'elementor-tab-title-' + tabindex + tabCount
648 } );
649
650 view.addInlineEditingAttributes( tabContentKey, 'advanced' );
651
652 var titleHTMLTag = elementor.helpers.validateHTMLTag( settings.title_html_tag );
653 #>
654 <div class="elementor-accordion-item">
655 <{{{ titleHTMLTag }}} {{{ view.getRenderAttributeString( tabTitleKey ) }}}>
656 <# if ( settings.icon || settings.selected_icon ) { #>
657 <span class="elementor-accordion-icon elementor-accordion-icon-{{ settings.icon_align }}" aria-hidden="true">
658 <# if ( iconHTML && iconHTML.rendered && ( ! settings.icon || migrated ) ) { #>
659 <span class="elementor-accordion-icon-closed">{{{ iconHTML.value }}}</span>
660 <span class="elementor-accordion-icon-opened">{{{ iconActiveHTML.value }}}</span>
661 <# } else { #>
662 <i class="elementor-accordion-icon-closed {{ settings.icon }}"></i>
663 <i class="elementor-accordion-icon-opened {{ settings.icon_active }}"></i>
664 <# } #>
665 </span>
666 <# } #>
667 <a class="elementor-accordion-title" href="">{{{ item.tab_title }}}</a>
668 </{{{ titleHTMLTag }}}>
669 <div {{{ view.getRenderAttributeString( tabContentKey ) }}}>{{{ item.tab_content }}}</div>
670 </div>
671 <#
672 } );
673 } #>
674 </div>
675 <?php
676 }
677 }
678