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

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

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