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

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