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

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