PluginProbe
Elementor Website Builder – more than just a page builder / 3.24.4
Elementor Website Builder – more than just a page builder v3.24.4
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 / tabs.php

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

626 lines 16.5 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 /**
12 * Elementor tabs widget.
13 *
14 * Elementor widget that displays vertical or horizontal tabs with different
15 * pieces of content.
16 *
17 * @since 1.0.0
18 */
19 class Widget_Tabs extends Widget_Base {
20
21 /**
22 * Get widget name.
23 *
24 * Retrieve tabs widget name.
25 *
26 * @since 1.0.0
27 * @access public
28 *
29 * @return string Widget name.
30 */
31 public function get_name() {
32 return 'tabs';
33 }
34
35 /**
36 * Get widget title.
37 *
38 * Retrieve tabs widget title.
39 *
40 * @since 1.0.0
41 * @access public
42 *
43 * @return string Widget title.
44 */
45 public function get_title() {
46 return esc_html__( 'Tabs', 'elementor' );
47 }
48
49 /**
50 * Get widget icon.
51 *
52 * Retrieve tabs widget icon.
53 *
54 * @since 1.0.0
55 * @access public
56 *
57 * @return string Widget icon.
58 */
59 public function get_icon() {
60 return 'eicon-tabs';
61 }
62
63 /**
64 * Get widget keywords.
65 *
66 * Retrieve the list of keywords the widget belongs to.
67 *
68 * @since 2.1.0
69 * @access public
70 *
71 * @return array Widget keywords.
72 */
73 public function get_keywords() {
74 return [ 'tabs', 'accordion', 'toggle' ];
75 }
76
77 protected function is_dynamic_content(): bool {
78 return false;
79 }
80
81 /**
82 * Get style dependencies.
83 *
84 * Retrieve the list of style dependencies the widget requires.
85 *
86 * @since 3.24.0
87 * @access public
88 *
89 * @return array Widget style dependencies.
90 */
91 public function get_style_depends(): array {
92 return [ 'widget-tabs' ];
93 }
94
95 public function show_in_panel(): bool {
96 return ! Plugin::$instance->experiments->is_feature_active( 'nested-elements' );
97 }
98
99 /**
100 * Register tabs widget controls.
101 *
102 * Adds different input fields to allow the user to change and customize the widget settings.
103 *
104 * @since 3.1.0
105 * @access protected
106 */
107 protected function register_controls() {
108 $start = is_rtl() ? 'end' : 'start';
109 $end = is_rtl() ? 'start' : 'end';
110
111 $this->start_controls_section(
112 'section_tabs',
113 [
114 'label' => esc_html__( 'Tabs', 'elementor' ),
115 ]
116 );
117
118 $repeater = new Repeater();
119
120 $repeater->add_control(
121 'tab_title',
122 [
123 'label' => esc_html__( 'Title', 'elementor' ),
124 'type' => Controls_Manager::TEXT,
125 'default' => esc_html__( 'Tab Title', 'elementor' ),
126 'placeholder' => esc_html__( 'Tab Title', 'elementor' ),
127 'label_block' => true,
128 'dynamic' => [
129 'active' => true,
130 ],
131 ]
132 );
133
134 $repeater->add_control(
135 'tab_content',
136 [
137 'label' => esc_html__( 'Content', 'elementor' ),
138 'default' => esc_html__( 'Tab Content', 'elementor' ),
139 'placeholder' => esc_html__( 'Tab Content', 'elementor' ),
140 'type' => Controls_Manager::WYSIWYG,
141 ]
142 );
143
144 $is_nested_tabs_active = Plugin::$instance->widgets_manager->get_widget_types( 'nested-tabs' );
145
146 if ( $is_nested_tabs_active ) {
147 $this->add_deprecation_message(
148 '3.8.0',
149 esc_html__(
150 'You are currently editing a Tabs Widget in its old version. Any new tabs widget dragged into the canvas will be the new Tab widget, with the improved Nested capabilities.',
151 'elementor'
152 ),
153 'nested-tabs'
154 );
155 }
156
157 $this->add_control(
158 'tabs',
159 [
160 'label' => esc_html__( 'Tabs Items', 'elementor' ),
161 'type' => Controls_Manager::REPEATER,
162 'fields' => $repeater->get_controls(),
163 'default' => [
164 [
165 'tab_title' => esc_html__( 'Tab #1', 'elementor' ),
166 'tab_content' => esc_html__( 'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Ut elit tellus, luctus nec ullamcorper mattis, pulvinar dapibus leo.', 'elementor' ),
167 ],
168 [
169 'tab_title' => esc_html__( 'Tab #2', 'elementor' ),
170 'tab_content' => esc_html__( 'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Ut elit tellus, luctus nec ullamcorper mattis, pulvinar dapibus leo.', 'elementor' ),
171 ],
172 ],
173 'title_field' => '{{{ tab_title }}}',
174 ]
175 );
176
177 $this->add_control(
178 'type',
179 [
180 'label' => esc_html__( 'Position', 'elementor' ),
181 'type' => Controls_Manager::CHOOSE,
182 'default' => 'horizontal',
183 'options' => [
184 'vertical' => [
185 'title' => esc_html__( 'Vertical', 'elementor' ),
186 'icon' => 'eicon-h-align-' . ( is_rtl() ? 'right' : 'left' ),
187 ],
188 'horizontal' => [
189 'title' => esc_html__( 'Horizontal', 'elementor' ),
190 'icon' => 'eicon-v-align-top',
191 ],
192 ],
193 'prefix_class' => 'elementor-tabs-view-',
194 'separator' => 'before',
195 ]
196 );
197
198 $this->add_control(
199 'tabs_align_horizontal',
200 [
201 'label' => esc_html__( 'Alignment', 'elementor' ),
202 'type' => Controls_Manager::CHOOSE,
203 'options' => [
204 '' => [
205 'title' => esc_html__( 'Start', 'elementor' ),
206 'icon' => "eicon-align-$start-h",
207 ],
208 'center' => [
209 'title' => esc_html__( 'Center', 'elementor' ),
210 'icon' => 'eicon-align-center-h',
211 ],
212 'end' => [
213 'title' => esc_html__( 'End', 'elementor' ),
214 'icon' => "eicon-align-$end-h",
215 ],
216 'stretch' => [
217 'title' => esc_html__( 'Stretch', 'elementor' ),
218 'icon' => 'eicon-align-stretch-h',
219 ],
220 ],
221 'prefix_class' => 'elementor-tabs-alignment-',
222 'condition' => [
223 'type' => 'horizontal',
224 ],
225 ]
226 );
227
228 $this->add_control(
229 'tabs_align_vertical',
230 [
231 'label' => esc_html__( 'Alignment', 'elementor' ),
232 'type' => Controls_Manager::CHOOSE,
233 'options' => [
234 '' => [
235 'title' => esc_html__( 'Start', 'elementor' ),
236 'icon' => 'eicon-align-start-v',
237 ],
238 'center' => [
239 'title' => esc_html__( 'Center', 'elementor' ),
240 'icon' => 'eicon-align-center-v',
241 ],
242 'end' => [
243 'title' => esc_html__( 'End', 'elementor' ),
244 'icon' => 'eicon-align-end-v',
245 ],
246 'stretch' => [
247 'title' => esc_html__( 'Stretch', 'elementor' ),
248 'icon' => 'eicon-align-stretch-v',
249 ],
250 ],
251 'prefix_class' => 'elementor-tabs-alignment-',
252 'condition' => [
253 'type' => 'vertical',
254 ],
255 ]
256 );
257
258 $this->end_controls_section();
259
260 $this->start_controls_section(
261 'section_tabs_style',
262 [
263 'label' => esc_html__( 'Tabs', 'elementor' ),
264 'tab' => Controls_Manager::TAB_STYLE,
265 ]
266 );
267
268 $this->add_control(
269 'navigation_width',
270 [
271 'label' => esc_html__( 'Navigation Width', 'elementor' ),
272 'type' => Controls_Manager::SLIDER,
273 'size_units' => [ 'px', '%', 'em', 'rem', 'custom' ],
274 'default' => [
275 'unit' => '%',
276 ],
277 'range' => [
278 'px' => [
279 'min' => 10,
280 'max' => 500,
281 ],
282 '%' => [
283 'min' => 10,
284 'max' => 50,
285 ],
286 'em' => [
287 'min' => 1,
288 'max' => 50,
289 ],
290 'rem' => [
291 'min' => 1,
292 'max' => 50,
293 ],
294 ],
295 'selectors' => [
296 '{{WRAPPER}} .elementor-tabs-wrapper' => 'width: {{SIZE}}{{UNIT}}',
297 ],
298 'condition' => [
299 'type' => 'vertical',
300 ],
301 ]
302 );
303
304 $this->add_control(
305 'border_width',
306 [
307 'label' => esc_html__( 'Border Width', 'elementor' ),
308 'type' => Controls_Manager::SLIDER,
309 'size_units' => [ 'px', '%', 'em', 'rem', 'vw', 'custom' ],
310 'default' => [
311 'size' => 1,
312 ],
313 'range' => [
314 'px' => [
315 'max' => 20,
316 ],
317 'em' => [
318 'max' => 2,
319 ],
320 ],
321 'selectors' => [
322 '{{WRAPPER}} .elementor-tab-title, {{WRAPPER}} .elementor-tab-title:before, {{WRAPPER}} .elementor-tab-title:after, {{WRAPPER}} .elementor-tab-content, {{WRAPPER}} .elementor-tabs-content-wrapper' => 'border-width: {{SIZE}}{{UNIT}};',
323 ],
324 ]
325 );
326
327 $this->add_control(
328 'border_color',
329 [
330 'label' => esc_html__( 'Border Color', 'elementor' ),
331 'type' => Controls_Manager::COLOR,
332 'selectors' => [
333 '{{WRAPPER}} .elementor-tab-mobile-title, {{WRAPPER}} .elementor-tab-desktop-title.elementor-active, {{WRAPPER}} .elementor-tab-title:before, {{WRAPPER}} .elementor-tab-title:after, {{WRAPPER}} .elementor-tab-content, {{WRAPPER}} .elementor-tabs-content-wrapper' => 'border-color: {{VALUE}};',
334 ],
335 ]
336 );
337
338 $this->add_control(
339 'background_color',
340 [
341 'label' => esc_html__( 'Background Color', 'elementor' ),
342 'type' => Controls_Manager::COLOR,
343 'selectors' => [
344 '{{WRAPPER}} .elementor-tab-desktop-title.elementor-active' => 'background-color: {{VALUE}};',
345 '{{WRAPPER}} .elementor-tabs-content-wrapper' => 'background-color: {{VALUE}};',
346 ],
347 ]
348 );
349
350 $this->add_control(
351 'heading_title',
352 [
353 'label' => esc_html__( 'Title', 'elementor' ),
354 'type' => Controls_Manager::HEADING,
355 'separator' => 'before',
356 ]
357 );
358
359 $this->add_control(
360 'tab_color',
361 [
362 'label' => esc_html__( 'Color', 'elementor' ),
363 'type' => Controls_Manager::COLOR,
364 'selectors' => [
365 '{{WRAPPER}} .elementor-tab-title, {{WRAPPER}} .elementor-tab-title a' => 'color: {{VALUE}}',
366 ],
367 'global' => [
368 'default' => Global_Colors::COLOR_PRIMARY,
369 ],
370 ]
371 );
372
373 $this->add_control(
374 'tab_active_color',
375 [
376 'label' => esc_html__( 'Active Color', 'elementor' ),
377 'type' => Controls_Manager::COLOR,
378 'selectors' => [
379 '{{WRAPPER}} .elementor-tab-title.elementor-active,
380 {{WRAPPER}} .elementor-tab-title.elementor-active a' => 'color: {{VALUE}}',
381 ],
382 'global' => [
383 'default' => Global_Colors::COLOR_ACCENT,
384 ],
385 ]
386 );
387
388 $this->add_group_control(
389 Group_Control_Typography::get_type(),
390 [
391 'name' => 'tab_typography',
392 'selector' => '{{WRAPPER}} .elementor-tab-title',
393 'global' => [
394 'default' => Global_Typography::TYPOGRAPHY_PRIMARY,
395 ],
396 ]
397 );
398
399 $this->add_group_control(
400 Group_Control_Text_Stroke::get_type(),
401 [
402 'name' => 'text_stroke',
403 'selector' => '{{WRAPPER}} .elementor-tab-title',
404 ]
405 );
406
407 $this->add_group_control(
408 Group_Control_Text_Shadow::get_type(),
409 [
410 'name' => 'title_shadow',
411 'selector' => '{{WRAPPER}} .elementor-tab-title',
412 ]
413 );
414
415 $this->add_control(
416 'title_align',
417 [
418 'label' => esc_html__( 'Alignment', 'elementor' ),
419 'type' => Controls_Manager::CHOOSE,
420 'options' => [
421 'left' => [
422 'title' => esc_html__( 'Left', 'elementor' ),
423 'icon' => 'eicon-text-align-left',
424 ],
425 'center' => [
426 'title' => esc_html__( 'Center', 'elementor' ),
427 'icon' => 'eicon-text-align-center',
428 ],
429 'right' => [
430 'title' => esc_html__( 'Right', 'elementor' ),
431 'icon' => 'eicon-text-align-right',
432 ],
433 ],
434 'selectors' => [
435 '{{WRAPPER}} .elementor-tab-title' => 'text-align: {{VALUE}};',
436 ],
437 'condition' => [
438 'tabs_align' => 'stretch',
439 ],
440 ]
441 );
442
443 $this->add_control(
444 'heading_content',
445 [
446 'label' => esc_html__( 'Content', 'elementor' ),
447 'type' => Controls_Manager::HEADING,
448 'separator' => 'before',
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->end_controls_section();
486 }
487
488 /**
489 * Render tabs widget output on the frontend.
490 *
491 * Written in PHP and used to generate the final HTML.
492 *
493 * @since 1.0.0
494 * @access protected
495 */
496 protected function render() {
497 $tabs = $this->get_settings_for_display( 'tabs' );
498
499 $id_int = substr( $this->get_id_int(), 0, 3 );
500
501 $this->add_render_attribute( 'elementor-tabs', 'class', 'elementor-tabs' );
502
503 ?>
504 <div <?php $this->print_render_attribute_string( 'elementor-tabs' ); ?>>
505 <div class="elementor-tabs-wrapper" role="tablist" >
506 <?php
507 foreach ( $tabs as $index => $item ) :
508 $tab_count = $index + 1;
509 $tab_title_setting_key = $this->get_repeater_setting_key( 'tab_title', 'tabs', $index );
510
511 $this->add_render_attribute( $tab_title_setting_key, [
512 'id' => 'elementor-tab-title-' . $id_int . $tab_count,
513 'class' => [ 'elementor-tab-title', 'elementor-tab-desktop-title' ],
514 'aria-selected' => 1 === $tab_count ? 'true' : 'false',
515 'data-tab' => $tab_count,
516 'role' => 'tab',
517 'tabindex' => 1 === $tab_count ? '0' : '-1',
518 'aria-controls' => 'elementor-tab-content-' . $id_int . $tab_count,
519 'aria-expanded' => 'false',
520 ] );
521 ?>
522 <div <?php $this->print_render_attribute_string( $tab_title_setting_key ); ?>><?php
523 // PHPCS - the main text of a widget should not be escaped.
524 echo $item['tab_title']; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
525 ?></div>
526 <?php endforeach; ?>
527 </div>
528 <div class="elementor-tabs-content-wrapper" role="tablist" aria-orientation="vertical">
529 <?php
530 foreach ( $tabs as $index => $item ) :
531 $tab_count = $index + 1;
532 $hidden = 1 === $tab_count ? 'false' : 'hidden';
533 $tab_content_setting_key = $this->get_repeater_setting_key( 'tab_content', 'tabs', $index );
534
535 $tab_title_mobile_setting_key = $this->get_repeater_setting_key( 'tab_title_mobile', 'tabs', $tab_count );
536
537 $this->add_render_attribute( $tab_content_setting_key, [
538 'id' => 'elementor-tab-content-' . $id_int . $tab_count,
539 'class' => [ 'elementor-tab-content', 'elementor-clearfix' ],
540 'data-tab' => $tab_count,
541 'role' => 'tabpanel',
542 'aria-labelledby' => 'elementor-tab-title-' . $id_int . $tab_count,
543 'tabindex' => '0',
544 'hidden' => $hidden,
545 ] );
546
547 $this->add_render_attribute( $tab_title_mobile_setting_key, [
548 'class' => [ 'elementor-tab-title', 'elementor-tab-mobile-title' ],
549 'aria-selected' => 1 === $tab_count ? 'true' : 'false',
550 'data-tab' => $tab_count,
551 'role' => 'tab',
552 'tabindex' => 1 === $tab_count ? '0' : '-1',
553 'aria-controls' => 'elementor-tab-content-' . $id_int . $tab_count,
554 'aria-expanded' => 'false',
555 ] );
556
557 $this->add_inline_editing_attributes( $tab_content_setting_key, 'advanced' );
558 ?>
559 <div <?php $this->print_render_attribute_string( $tab_title_mobile_setting_key ); ?>><?php
560 $this->print_unescaped_setting( 'tab_title', 'tabs', $index );
561 ?></div>
562 <div <?php $this->print_render_attribute_string( $tab_content_setting_key ); ?>><?php
563 $this->print_text_editor( $item['tab_content'] );
564 ?></div>
565 <?php endforeach; ?>
566 </div>
567 </div>
568 <?php
569 }
570
571 /**
572 * Render tabs widget output in the editor.
573 *
574 * Written as a Backbone JavaScript template and used to generate the live preview.
575 *
576 * @since 2.9.0
577 * @access protected
578 */
579 protected function content_template() {
580 ?>
581 <div class="elementor-tabs" role="tablist" aria-orientation="vertical">
582 <# if ( settings.tabs ) {
583 var elementUid = view.getIDInt().toString().substr( 0, 3 ); #>
584 <div class="elementor-tabs-wrapper" role="tablist">
585 <# _.each( settings.tabs, function( item, index ) {
586 var tabCount = index + 1,
587 tabUid = elementUid + tabCount,
588 tabTitleKey = 'tab-title-' + tabUid;
589
590 view.addRenderAttribute( tabTitleKey, {
591 'id': 'elementor-tab-title-' + tabUid,
592 'class': [ 'elementor-tab-title','elementor-tab-desktop-title' ],
593 'data-tab': tabCount,
594 'role': 'tab',
595 'tabindex': 1 === tabCount ? '0' : '-1',
596 'aria-controls': 'elementor-tab-content-' + tabUid,
597 'aria-expanded': 'false',
598 } );
599 #>
600 <div {{{ view.getRenderAttributeString( tabTitleKey ) }}}>{{{ item.tab_title }}}</div>
601 <# } ); #>
602 </div>
603 <div class="elementor-tabs-content-wrapper">
604 <# _.each( settings.tabs, function( item, index ) {
605 var tabCount = index + 1,
606 tabContentKey = view.getRepeaterSettingKey( 'tab_content', 'tabs',index );
607
608 view.addRenderAttribute( tabContentKey, {
609 'id': 'elementor-tab-content-' + elementUid + tabCount,
610 'class': [ 'elementor-tab-content', 'elementor-clearfix', 'elementor-repeater-item-' + item._id ],
611 'data-tab': tabCount,
612 'role' : 'tabpanel',
613 'aria-labelledby' : 'elementor-tab-title-' + elementUid + tabCount
614 } );
615
616 view.addInlineEditingAttributes( tabContentKey, 'advanced' ); #>
617 <div class="elementor-tab-title elementor-tab-mobile-title" data-tab="{{ tabCount }}" role="tab">{{{ item.tab_title }}}</div>
618 <div {{{ view.getRenderAttributeString( tabContentKey ) }}}>{{{ item.tab_content }}}</div>
619 <# } ); #>
620 </div>
621 <# } #>
622 </div>
623 <?php
624 }
625 }
626