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

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