PluginProbe
Elementor Website Builder – more than just a page builder / 3.10.1
Elementor Website Builder – more than just a page builder v3.10.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 / modules / nested-tabs / widgets / nested-tabs.php

nested-tabs.php in Elementor Website Builder – more than just a page builder 3.10.1, at modules/nested-tabs/widgets/nested-tabs.php

1,186 lines 34.2 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 namespace Elementor\Modules\NestedTabs\Widgets;
3
4 use Elementor\Controls_Manager;
5 use Elementor\Core\Kits\Documents\Tabs\Global_Colors;
6 use Elementor\Core\Kits\Documents\Tabs\Global_Typography;
7 use Elementor\Group_Control_Background;
8 use Elementor\Group_Control_Border;
9 use Elementor\Group_Control_Box_Shadow;
10 use Elementor\Group_Control_Text_Shadow;
11 use Elementor\Group_Control_Text_Stroke;
12 use Elementor\Group_Control_Typography;
13 use Elementor\Icons_Manager;
14 use Elementor\Modules\NestedElements\Base\Widget_Nested_Base;
15 use Elementor\Modules\NestedElements\Controls\Control_Nested_Repeater;
16 use Elementor\Plugin;
17 use Elementor\Repeater;
18 use Elementor\Modules\DynamicTags\Module as TagsModule;
19 use Elementor\Utils;
20 use Elementor\Core\Breakpoints\Manager as Breakpoints_Manager;
21
22 if ( ! defined( 'ABSPATH' ) ) {
23 exit; // Exit if accessed directly
24 }
25
26 class NestedTabs extends Widget_Nested_Base {
27
28 public function get_name() {
29 return 'nested-tabs';
30 }
31
32 public function get_title() {
33 return esc_html__( 'Tabs', 'elementor' );
34 }
35
36 public function get_icon() {
37 return 'eicon-tabs';
38 }
39
40 public function get_keywords() {
41 return [ 'nested', 'tabs', 'accordion', 'toggle' ];
42 }
43
44 protected function tab_content_container( int $index ) {
45 return [
46 'elType' => 'container',
47 'settings' => [
48 '_title' => sprintf( __( 'Tab #%s', 'elementor' ), $index ),
49 'content_width' => 'full',
50 ],
51 ];
52 }
53
54 protected function get_default_children_elements() {
55 return [
56 $this->tab_content_container( 1 ),
57 $this->tab_content_container( 2 ),
58 $this->tab_content_container( 3 ),
59 ];
60 }
61
62 protected function get_default_repeater_title_setting_key() {
63 return 'tab_title';
64 }
65
66 protected function get_default_children_title() {
67 return esc_html__( 'Tab #%d', 'elementor' );
68 }
69
70 protected function get_default_children_placeholder_selector() {
71 return '.e-n-tabs-content';
72 }
73
74 protected function get_html_wrapper_class() {
75 return 'elementor-widget-n-tabs';
76 }
77
78 protected function register_controls() {
79 $start = is_rtl() ? 'right' : 'left';
80 $end = is_rtl() ? 'left' : 'right';
81 $tooltip_start = is_rtl() ? esc_html__( 'Right', 'elementor' ) : esc_html__( 'Left', 'elementor' );
82 $tooltip_end = is_rtl() ? esc_html__( 'Left', 'elementor' ) : esc_html__( 'Right', 'elementor' );
83 $nested_tabs_heading_selector_class = ':is( {{WRAPPER}} > .elementor-widget-container > .e-n-tabs > .e-n-tabs-heading, {{WRAPPER}} > .elementor-widget-container > .e-n-tabs > .e-n-tabs-content )';
84 $nested_tabs_content_selector_class = '{{WRAPPER}} > .elementor-widget-container > .e-n-tabs > .e-n-tabs-content';
85
86 $this->start_controls_section( 'section_tabs', [
87 'label' => esc_html__( 'Tabs', 'elementor' ),
88 ] );
89
90 $repeater = new Repeater();
91
92 $repeater->add_control( 'tab_title', [
93 'label' => esc_html__( 'Title', 'elementor' ),
94 'type' => Controls_Manager::TEXT,
95 'default' => esc_html__( 'Tab Title', 'elementor' ),
96 'placeholder' => esc_html__( 'Tab Title', 'elementor' ),
97 'label_block' => true,
98 'dynamic' => [
99 'active' => true,
100 ],
101 ] );
102
103 $repeater->add_control(
104 'tab_icon',
105 [
106 'label' => esc_html__( 'Icon', 'elementor' ),
107 'type' => Controls_Manager::ICONS,
108 'fa4compatibility' => 'icon',
109 'skin' => 'inline',
110 'label_block' => false,
111 ]
112 );
113
114 $repeater->add_control(
115 'tab_icon_active',
116 [
117 'label' => esc_html__( 'Active Icon', 'elementor' ),
118 'type' => Controls_Manager::ICONS,
119 'fa4compatibility' => 'icon',
120 'skin' => 'inline',
121 'label_block' => false,
122 'condition' => [
123 'tab_icon[value]!' => '',
124 ],
125 ]
126 );
127
128 $repeater->add_control(
129 'element_id',
130 [
131 'label' => esc_html__( 'CSS ID', 'elementor' ),
132 'type' => Controls_Manager::TEXT,
133 'default' => '',
134 'dynamic' => [
135 'active' => true,
136 ],
137 'title' => esc_html__( 'Add your custom id WITHOUT the Pound key. e.g: my-id', 'elementor' ),
138 'style_transfer' => false,
139 'classes' => 'elementor-control-direction-ltr',
140 ]
141 );
142
143 $this->add_control( 'tabs', [
144 'label' => esc_html__( 'Tabs Items', 'elementor' ),
145 'type' => Control_Nested_Repeater::CONTROL_TYPE,
146 'fields' => $repeater->get_controls(),
147 'default' => [
148 [
149 'tab_title' => esc_html__( 'Tab #1', 'elementor' ),
150 ],
151 [
152 'tab_title' => esc_html__( 'Tab #2', 'elementor' ),
153 ],
154 [
155 'tab_title' => esc_html__( 'Tab #3', 'elementor' ),
156 ],
157 ],
158 'title_field' => '{{{ tab_title }}}',
159 'button_text' => 'Add Tab',
160 ] );
161
162 $this->add_responsive_control( 'tabs_direction', [
163 'label' => esc_html__( 'Direction', 'elementor' ),
164 'type' => Controls_Manager::CHOOSE,
165 'options' => [
166 'top' => [
167 'title' => esc_html__( 'Top', 'elementor' ),
168 'icon' => 'eicon-v-align-top',
169 ],
170 'bottom' => [
171 'title' => esc_html__( 'Bottom', 'elementor' ),
172 'icon' => 'eicon-v-align-bottom',
173 ],
174 'end' => [
175 'title' => $tooltip_end,
176 'icon' => 'eicon-h-align-' . $end,
177 ],
178 'start' => [
179 'title' => $tooltip_start,
180 'icon' => 'eicon-h-align-' . $start,
181 ],
182 ],
183 'separator' => 'before',
184 'selectors_dictionary' => [
185 'top' => '--n-tabs-direction: column; --n-tabs-heading-direction: row; --n-tabs-heading-width: initial;',
186 'bottom' => '--n-tabs-direction: column-reverse; --n-tabs-heading-direction: row; --n-tabs-heading-width: initial;',
187 'end' => '--n-tabs-direction: row-reverse; --n-tabs-heading-direction: column; --n-tabs-heading-width: 240px;',
188 'start' => '--n-tabs-direction: row; --n-tabs-heading-direction: column; --n-tabs-heading-width: 240px;',
189 ],
190 'selectors' => [
191 '{{WRAPPER}}' => '{{VALUE}}',
192 ],
193 ] );
194
195 $this->add_responsive_control( 'tabs_justify_horizontal', [
196 'label' => esc_html__( 'Justify', 'elementor' ),
197 'type' => Controls_Manager::CHOOSE,
198 'options' => [
199 'start' => [
200 'title' => esc_html__( 'Start', 'elementor' ),
201 'icon' => 'eicon-flex eicon-align-start-h',
202 ],
203 'center' => [
204 'title' => esc_html__( 'Center', 'elementor' ),
205 'icon' => 'eicon-h-align-center',
206 ],
207 'end' => [
208 'title' => esc_html__( 'End', 'elementor' ),
209 'icon' => 'eicon-flex eicon-align-end-h',
210 ],
211 'stretch' => [
212 'title' => esc_html__( 'Justified', 'elementor' ),
213 'icon' => 'eicon-h-align-stretch',
214 ],
215 ],
216 'selectors_dictionary' => [
217 'start' => '--n-tabs-heading-justify-content: flex-start; --n-tabs-title-width: initial; --n-tabs-title-height: initial; --n-tabs-title-align-items: center;',
218 'center' => '--n-tabs-heading-justify-content: center; --n-tabs-title-width: initial; --n-tabs-title-height: initial; --n-tabs-title-align-items: center;',
219 'end' => '--n-tabs-heading-justify-content: flex-end; --n-tabs-title-width: initial; --n-tabs-title-height: initial; --n-tabs-title-align-items: center',
220 'stretch' => '--n-tabs-heading-justify-content: initial; --n-tabs-title-width: 100%; --n-tabs-title-height: initial; --n-tabs-title-align-items: center;',
221 ],
222 'selectors' => [
223 '{{WRAPPER}}' => '{{VALUE}}',
224 ],
225 'condition' => [
226 'tabs_direction' => [
227 '',
228 'top',
229 'bottom',
230 ],
231 ],
232 ] );
233
234 $this->add_responsive_control( 'tabs_justify_vertical', [
235 'label' => esc_html__( 'Justify', 'elementor' ),
236 'type' => Controls_Manager::CHOOSE,
237 'options' => [
238 'start' => [
239 'title' => esc_html__( 'Start', 'elementor' ),
240 'icon' => 'eicon-flex eicon-align-start-v',
241 ],
242 'center' => [
243 'title' => esc_html__( 'Center', 'elementor' ),
244 'icon' => 'eicon-v-align-middle',
245 ],
246 'end' => [
247 'title' => esc_html__( 'End', 'elementor' ),
248 'icon' => 'eicon-flex eicon-align-end-v',
249 ],
250 'stretch' => [
251 'title' => esc_html__( 'Justified', 'elementor' ),
252 'icon' => 'eicon-v-align-stretch',
253 ],
254 ],
255 'selectors_dictionary' => [
256 'start' => '--n-tabs-heading-justify-content: flex-start; --n-tabs-title-width: initial; --n-tabs-title-height: initial; --n-tabs-title-align-items: initial;',
257 'center' => '--n-tabs-heading-justify-content: center; --n-tabs-title-width: initial; --n-tabs-title-height: initial; --n-tabs-title-align-items: initial;',
258 'end' => '--n-tabs-heading-justify-content: flex-end; --n-tabs-title-width: initial; --n-tabs-title-height: initial; --n-tabs-title-align-items: initial;',
259 'stretch' => '--n-tabs-heading-justify-content: flex-start; --n-tabs-title-width: initial; --n-tabs-title-height: 100%; --n-tabs-title-align-items: center;',
260 ],
261 'selectors' => [
262 '{{WRAPPER}}' => '{{VALUE}}',
263 ],
264 'condition' => [
265 'tabs_direction' => [
266 'start',
267 'end',
268 ],
269 ],
270 ] );
271
272 $this->add_responsive_control( 'tabs_width', [
273 'label' => esc_html__( 'Width', 'elementor' ),
274 'type' => Controls_Manager::SLIDER,
275 'range' => [
276 '%' => [
277 'min' => 10,
278 'max' => 50,
279 ],
280 'px' => [
281 'min' => 20,
282 'max' => 600,
283 ],
284 ],
285 'default' => [
286 'unit' => '%',
287 ],
288 'size_units' => [ '%', 'px' ],
289 'selectors' => [
290 '{{WRAPPER}}' => '--n-tabs-heading-width: {{SIZE}}{{UNIT}}',
291 ],
292 'condition' => [
293 'tabs_direction' => [
294 'start',
295 'end',
296 ],
297 ],
298 ] );
299
300 $this->add_responsive_control( 'title_alignment', [
301 'label' => esc_html__( 'Align Title', 'elementor' ),
302 'type' => Controls_Manager::CHOOSE,
303 'options' => [
304 'start' => [
305 'title' => esc_html__( 'Left', 'elementor' ),
306 'icon' => 'eicon-text-align-left',
307 ],
308 'center' => [
309 'title' => esc_html__( 'Center', 'elementor' ),
310 'icon' => 'eicon-text-align-center',
311 ],
312 'end' => [
313 'title' => esc_html__( 'Right', 'elementor' ),
314 'icon' => 'eicon-text-align-right',
315 ],
316 ],
317 'selectors_dictionary' => [
318 'start' => '--n-tabs-title-justify-content: flex-start; --n-tabs-title-align-items: flex-start;',
319 'center' => '--n-tabs-title-justify-content: center; --n-tabs-title-align-items: center;',
320 'end' => '--n-tabs-title-justify-content: flex-end; --n-tabs-title-align-items: flex-end;',
321 ],
322 'selectors' => [
323 '{{WRAPPER}}' => '{{VALUE}}',
324 ],
325 ] );
326
327 $this->end_controls_section();
328
329 $this->start_controls_section( 'section_tabs_responsive', [
330 'label' => esc_html__( 'Responsive Settings', 'elementor' ),
331 ] );
332
333 $dropdown_options = [];
334 $excluded_breakpoints = [
335 'laptop',
336 'tablet_extra',
337 'widescreen',
338 ];
339
340 foreach ( Plugin::$instance->breakpoints->get_active_breakpoints() as $breakpoint_key => $breakpoint_instance ) {
341 // Exclude the larger breakpoints from the dropdown selector.
342 if ( in_array( $breakpoint_key, $excluded_breakpoints, true ) ) {
343 continue;
344 }
345
346 $dropdown_options[ $breakpoint_key ] = sprintf(
347 /* translators: 1: Breakpoint label, 2: `>` character, 3: Breakpoint value. */
348 esc_html__( '%1$s (%2$s %3$dpx)', 'elementor' ),
349 $breakpoint_instance->get_label(),
350 '>',
351 $breakpoint_instance->get_value()
352 );
353 }
354
355 $this->add_control(
356 'breakpoint_selector',
357 [
358 'label' => esc_html__( 'Breakpoint', 'elementor' ),
359 'type' => Controls_Manager::SELECT,
360 'description' => esc_html__( 'Note: Choose at which breakpoint tabs will automatically switch to a vertical (“accordion”) layout.', 'elementor' ),
361 'options' => $dropdown_options,
362 'default' => 'mobile',
363 'prefix_class' => 'e-n-tabs-',
364 ]
365 );
366
367 $this->end_controls_section();
368
369 $this->start_controls_section( 'section_tabs_style', [
370 'label' => esc_html__( 'Tabs', 'elementor' ),
371 'tab' => Controls_Manager::TAB_STYLE,
372 ] );
373
374 $this->add_responsive_control( 'tabs_title_space_between', [
375 'label' => esc_html__( 'Gap between tabs', 'elementor' ),
376 'type' => Controls_Manager::SLIDER,
377 'range' => [
378 'px' => [
379 'min' => 0,
380 'max' => 400,
381 ],
382 ],
383 'size_units' => [ 'px' ],
384 'selectors' => [
385 '{{WRAPPER}}' => '--n-tabs-title-gap: {{SIZE}}{{UNIT}}',
386 ],
387 ] );
388
389 $this->add_responsive_control( 'tabs_title_spacing', [
390 'label' => esc_html__( 'Distance from content', 'elementor' ),
391 'type' => Controls_Manager::SLIDER,
392 'range' => [
393 'px' => [
394 'min' => 0,
395 'max' => 400,
396 ],
397 ],
398 'size_units' => [ 'px' ],
399 'selectors' => [
400 '{{WRAPPER}}' => '--n-tabs-gap: {{SIZE}}{{UNIT}}',
401 ],
402 ] );
403
404 $this->start_controls_tabs( 'tabs_title_style' );
405
406 $this->start_controls_tab(
407 'tabs_title_normal',
408 [
409 'label' => esc_html__( 'Normal', 'elementor' ),
410 ]
411 );
412
413 $this->add_group_control(
414 Group_Control_Background::get_type(),
415 [
416 'name' => 'tabs_title_background_color',
417 'types' => [ 'classic', 'gradient' ],
418 'exclude' => [ 'image' ],
419 'selector' => "{$nested_tabs_heading_selector_class} > .e-n-tab-title:not( .e-active ):not( :hover )",
420 'fields_options' => [
421 'color' => [
422 'label' => esc_html__( 'Background Color', 'elementor' ),
423 'selectors' => [
424 '{{SELECTOR}}' => 'background: {{VALUE}}',
425 ],
426 ],
427 ],
428 ]
429 );
430
431 $this->add_group_control(
432 Group_Control_Border::get_type(),
433 [
434 'name' => 'tabs_title_border',
435 'selector' => "{$nested_tabs_heading_selector_class} > .e-n-tab-title:not( .e-active ):not( :hover )",
436 'fields_options' => [
437 'color' => [
438 'label' => esc_html__( 'Border Color', 'elementor' ),
439 ],
440 'width' => [
441 'label' => esc_html__( 'Border Width', 'elementor' ),
442 ],
443 ],
444 ]
445 );
446
447 $this->add_group_control(
448 Group_Control_Box_Shadow::get_type(),
449 [
450 'name' => 'tabs_title_box_shadow',
451 'label' => esc_html__( 'Shadow', 'elementor' ),
452 'separator' => 'after',
453 'selector' => "{$nested_tabs_heading_selector_class} > .e-n-tab-title:not( .e-active ):not( :hover )",
454 ]
455 );
456
457 $this->end_controls_tab();
458
459 $this->start_controls_tab(
460 'tabs_title_hover',
461 [
462 'label' => esc_html__( 'Hover', 'elementor' ),
463 ]
464 );
465
466 $this->add_group_control(
467 Group_Control_Background::get_type(),
468 [
469 'name' => 'tabs_title_background_color_hover',
470 'types' => [ 'classic', 'gradient' ],
471 'exclude' => [ 'image' ],
472 'selector' => "{$nested_tabs_heading_selector_class} > .e-n-tab-title:not( .e-active ):hover",
473 'fields_options' => [
474 'background' => [
475 'default' => 'classic',
476 ],
477 'color' => [
478 'global' => [
479 'default' => Global_Colors::COLOR_ACCENT,
480 ],
481 'label' => esc_html__( 'Background Color', 'elementor' ),
482 'selectors' => [
483 '{{SELECTOR}}' => 'background: {{VALUE}};',
484 ],
485 ],
486 ],
487 ]
488 );
489
490 $this->add_group_control(
491 Group_Control_Border::get_type(),
492 [
493 'name' => 'tabs_title_border_hover',
494 'selector' => "{$nested_tabs_heading_selector_class} > .e-n-tab-title:not( .e-active ):hover",
495 'fields_options' => [
496 'color' => [
497 'label' => esc_html__( 'Border Color', 'elementor' ),
498 ],
499 'width' => [
500 'label' => esc_html__( 'Border Width', 'elementor' ),
501 ],
502 ],
503 ]
504 );
505
506 $this->add_group_control(
507 Group_Control_Box_Shadow::get_type(),
508 [
509 'name' => 'tabs_title_box_shadow_hover',
510 'label' => esc_html__( 'Shadow', 'elementor' ),
511 'separator' => 'after',
512 'selector' => "{$nested_tabs_heading_selector_class} > .e-n-tab-title:not( .e-active ):hover",
513 ]
514 );
515
516 $this->add_control(
517 'hover_animation',
518 [
519 'label' => esc_html__( 'Hover Animation', 'elementor' ),
520 'type' => Controls_Manager::HOVER_ANIMATION,
521 ]
522 );
523
524 $this->add_control(
525 'tabs_title_transition_duration',
526 [
527 'label' => esc_html__( 'Transition Duration (s)', 'elementor' ),
528 'type' => Controls_Manager::SLIDER,
529 'selectors' => [
530 '{{WRAPPER}}' => '--n-tabs-title-transition: {{SIZE}}s',
531 ],
532 'range' => [
533 'px' => [
534 'max' => 3,
535 'step' => 0.1,
536 ],
537 ],
538 ]
539 );
540
541 $this->end_controls_tab();
542
543 $this->start_controls_tab(
544 'tabs_title_active',
545 [
546 'label' => esc_html__( 'Active', 'elementor' ),
547 ]
548 );
549
550 $this->add_group_control(
551 Group_Control_Background::get_type(),
552 [
553 'name' => 'tabs_title_background_color_active',
554 'types' => [ 'classic', 'gradient' ],
555 'exclude' => [ 'image' ],
556 'selector' => "{$nested_tabs_heading_selector_class} > .e-n-tab-title.e-active",
557 'fields_options' => [
558 'background' => [
559 'default' => 'classic',
560 ],
561 'color' => [
562 'global' => [
563 'default' => Global_Colors::COLOR_ACCENT,
564 ],
565 'label' => esc_html__( 'Background Color', 'elementor' ),
566 'selectors' => [
567 '{{SELECTOR}}' => 'background: {{VALUE}};',
568 ],
569 ],
570 ],
571 ]
572 );
573
574 $this->add_group_control(
575 Group_Control_Border::get_type(),
576 [
577 'name' => 'tabs_title_border_active',
578 'selector' => "{$nested_tabs_heading_selector_class} > .e-n-tab-title.e-active",
579 'fields_options' => [
580 'color' => [
581 'label' => esc_html__( 'Border Color', 'elementor' ),
582 ],
583 'width' => [
584 'label' => esc_html__( 'Border Width', 'elementor' ),
585 ],
586 ],
587 ]
588 );
589
590 $this->add_group_control(
591 Group_Control_Box_Shadow::get_type(),
592 [
593 'name' => 'tabs_title_box_shadow_active',
594 'label' => esc_html__( 'Shadow', 'elementor' ),
595 'selector' => "{$nested_tabs_heading_selector_class} > .e-n-tab-title.e-active",
596 ]
597 );
598
599 $this->end_controls_tab();
600
601 $this->end_controls_tabs();
602
603 $this->add_responsive_control(
604 'tabs_title_border_radius',
605 [
606 'label' => esc_html__( 'Border Radius', 'elementor' ),
607 'type' => Controls_Manager::DIMENSIONS,
608 'size_units' => [ 'px', 'em', '%', 'rem' ],
609 'separator' => 'before',
610 'selectors' => [
611 '{{WRAPPER}}' => '--n-tabs-title-border-radius: {{TOP}}{{UNIT}} {{RIGHT}}{{UNIT}} {{BOTTOM}}{{UNIT}} {{LEFT}}{{UNIT}};',
612 ],
613 ]
614 );
615
616 $this->add_responsive_control(
617 'padding',
618 [
619 'label' => esc_html__( 'Padding', 'elementor' ),
620 'type' => Controls_Manager::DIMENSIONS,
621 'size_units' => [ 'px', 'em', '%', 'rem' ],
622 'selectors' => [
623 '{{WRAPPER}}' => '--n-tabs-title-padding-top: {{TOP}}{{UNIT}}; --n-tabs-title-padding-right: {{RIGHT}}{{UNIT}}; --n-tabs-title-padding-bottom: {{BOTTOM}}{{UNIT}}; --n-tabs-title-padding-left: {{LEFT}}{{UNIT}};',
624 ],
625 ]
626 );
627
628 $this->end_controls_section();
629
630 $this->start_controls_section( 'section_title_style', [
631 'label' => esc_html__( 'Titles', 'elementor' ),
632 'tab' => Controls_Manager::TAB_STYLE,
633 ] );
634
635 $this->add_group_control( Group_Control_Typography::get_type(), [
636 'name' => 'title_typography',
637 'global' => [
638 'default' => Global_Typography::TYPOGRAPHY_ACCENT,
639 ],
640 'selector' => "{$nested_tabs_heading_selector_class} > :is( .e-n-tab-title > .e-n-tab-title-text, .e-n-tab-title )",
641 'fields_options' => [
642 'font_size' => [
643 'selectors' => [
644 '{{WRAPPER}}' => '--n-tabs-title-font-size: {{SIZE}}{{UNIT}}',
645 ],
646 ],
647 ],
648 ] );
649
650 $this->start_controls_tabs( 'title_style' );
651
652 $this->start_controls_tab(
653 'title_normal',
654 [
655 'label' => esc_html__( 'Normal', 'elementor' ),
656 ]
657 );
658
659 $this->add_control(
660 'title_text_color',
661 [
662 'label' => esc_html__( 'Color', 'elementor' ),
663 'type' => Controls_Manager::COLOR,
664 'selectors' => [
665 '{{WRAPPER}}' => '--n-tabs-title-color: {{VALUE}}',
666 ],
667 ]
668 );
669
670 $this->add_group_control(
671 Group_Control_Text_Shadow::get_type(),
672 [
673 'name' => 'title_text_shadow',
674 'selector' => "{$nested_tabs_heading_selector_class} > .e-n-tab-title:not( .e-active ):not( :hover )",
675 'fields_options' => [
676 'text_shadow_type' => [
677 'label' => esc_html_x( 'Shadow', 'Text Shadow Control', 'elementor' ),
678 ],
679 ],
680 ]
681 );
682
683 $this->add_group_control(
684 Group_Control_Text_Stroke::get_type(),
685 [
686 'name' => 'title_text_stroke',
687 'selector' => "{$nested_tabs_heading_selector_class} > .e-n-tab-title:not( .e-active ):not( :hover ) :is( span, a, i )",
688 'fields_options' => [
689 'text_stroke_type' => [
690 'label' => esc_html__( 'Stroke', 'elementor' ),
691 ],
692 ],
693 ]
694 );
695
696 $this->end_controls_tab();
697
698 $this->start_controls_tab(
699 'title_hover',
700 [
701 'label' => esc_html__( 'Hover', 'elementor' ),
702 ]
703 );
704
705 $this->add_control(
706 'title_text_color_hover',
707 [
708 'label' => esc_html__( 'Color', 'elementor' ),
709 'type' => Controls_Manager::COLOR,
710 'selectors' => [
711 '{{WRAPPER}} .e-n-tab-title:not( .e-active ):hover' => '--n-tabs-title-color-hover: {{VALUE}}',
712 ],
713 ]
714 );
715
716 $this->add_group_control(
717 Group_Control_Text_Shadow::get_type(),
718 [
719 'name' => 'title_text_shadow_hover',
720 'selector' => "{$nested_tabs_heading_selector_class} > .e-n-tab-title:not( .e-active ):hover",
721 'fields_options' => [
722 'text_shadow_type' => [
723 'label' => esc_html_x( 'Shadow', 'Text Shadow Control', 'elementor' ),
724 ],
725 ],
726
727 ]
728 );
729
730 $this->add_group_control(
731 Group_Control_Text_Stroke::get_type(),
732 [
733 'name' => 'title_text_stroke_hover',
734 'selector' => "{$nested_tabs_heading_selector_class} > .e-n-tab-title:not( .e-active ):hover :is( span, a, i )",
735 'fields_options' => [
736 'text_stroke_type' => [
737 'label' => esc_html__( 'Stroke', 'elementor' ),
738 ],
739 ],
740 ]
741 );
742
743 $this->end_controls_tab();
744
745 $this->start_controls_tab(
746 'title_active',
747 [
748 'label' => esc_html__( 'Active', 'elementor' ),
749 ]
750 );
751
752 $this->add_control(
753 'title_text_color_active',
754 [
755 'label' => esc_html__( 'Color', 'elementor' ),
756 'type' => Controls_Manager::COLOR,
757 'selectors' => [
758 '{{WRAPPER}}' => '--n-tabs-title-color-active: {{VALUE}}',
759 ],
760 ]
761 );
762
763 $this->add_group_control(
764 Group_Control_Text_Shadow::get_type(),
765 [
766 'name' => 'title_text_shadow_active',
767 'selector' => "{$nested_tabs_heading_selector_class} > .e-n-tab-title.e-active",
768 'fields_options' => [
769 'text_shadow_type' => [
770 'label' => esc_html_x( 'Shadow', 'Text Shadow Control', 'elementor' ),
771 ],
772 ],
773 ]
774 );
775
776 $this->add_group_control(
777 Group_Control_Text_Stroke::get_type(),
778 [
779 'name' => 'title_text_stroke_active',
780 'selector' => "{$nested_tabs_heading_selector_class} > .e-n-tab-title.e-active :is( span, a, i )",
781 'fields_options' => [
782 'text_stroke_type' => [
783 'label' => esc_html__( 'Stroke', 'elementor' ),
784 ],
785 ],
786 ]
787 );
788
789 $this->end_controls_tab();
790
791 $this->end_controls_tabs();
792
793 $this->end_controls_section();
794
795 $this->start_controls_section( 'icon_section_style', [
796 'label' => esc_html__( 'Icon', 'elementor' ),
797 'tab' => Controls_Manager::TAB_STYLE,
798 ] );
799
800 $this->add_responsive_control( 'icon_position', [
801 'label' => esc_html__( 'Position', 'elementor' ),
802 'type' => Controls_Manager::CHOOSE,
803 'options' => [
804 'top' => [
805 'title' => esc_html__( 'Top', 'elementor' ),
806 'icon' => 'eicon-v-align-top',
807 ],
808 'end' => [
809 'title' => $tooltip_end,
810 'icon' => 'eicon-h-align-' . $end,
811 ],
812 'bottom' => [
813 'title' => esc_html__( 'Bottom', 'elementor' ),
814 'icon' => 'eicon-v-align-bottom',
815 ],
816 'start' => [
817 'title' => $tooltip_start,
818 'icon' => 'eicon-h-align-' . $start,
819 ],
820 ],
821 'selectors_dictionary' => [
822 // The toggle variables for 'align items' and 'justify content' have been added to separate the styling of the two 'flex direction' modes.
823 'top' => '--n-tabs-title-direction: column; --n-tabs-icon-order: initial; --n-tabs-title-justify-content-toggle: center; --n-tabs-title-align-items-toggle: initial;',
824 'end' => '--n-tabs-title-direction: row; --n-tabs-icon-order: 1; --n-tabs-title-justify-content-toggle: initial; --n-tabs-title-align-items-toggle: center;',
825 'bottom' => '--n-tabs-title-direction: column; --n-tabs-icon-order: 1; --n-tabs-title-justify-content-toggle: center; --n-tabs-title-align-items-toggle: initial;',
826 'start' => '--n-tabs-title-direction: row; --n-tabs-icon-order: initial; --n-tabs-title-justify-content-toggle: initial; --n-tabs-title-align-items-toggle: center;',
827 ],
828 'selectors' => [
829 '{{WRAPPER}}' => '{{VALUE}}',
830 ],
831 ] );
832
833 $this->add_responsive_control( 'icon_size', [
834 'label' => esc_html__( 'Size', 'elementor' ),
835 'type' => Controls_Manager::SLIDER,
836 'range' => [
837 'px' => [
838 'min' => 0,
839 'max' => 100,
840 ],
841 'em' => [
842 'min' => 0,
843 'max' => 10,
844 'step' => 0.1,
845 ],
846 'rem' => [
847 'min' => 0,
848 'max' => 10,
849 'step' => 0.1,
850 ],
851 ],
852 'default' => [
853 'unit' => 'px',
854 ],
855 'size_units' => [ 'px', 'em', 'rem' ],
856 'selectors' => [
857 '{{WRAPPER}}' => '--n-tabs-icon-size: {{SIZE}}{{UNIT}}',
858 ],
859 ] );
860
861 $this->add_responsive_control( 'icon_spacing', [
862 'label' => esc_html__( 'Spacing', 'elementor' ),
863 'type' => Controls_Manager::SLIDER,
864 'range' => [
865 'px' => [
866 'min' => 0,
867 'max' => 400,
868 ],
869 'vw' => [
870 'min' => 0,
871 'max' => 50,
872 'step' => 0.1,
873 ],
874 ],
875 'default' => [
876 'unit' => 'px',
877 ],
878 'size_units' => [ 'px', 'vw' ],
879 'selectors' => [
880 '{{WRAPPER}}' => '--n-tabs-icon-gap: {{SIZE}}{{UNIT}}',
881 ],
882 ] );
883
884 $this->start_controls_tabs( 'icon_style_states' );
885
886 $this->start_controls_tab(
887 'icon_section_normal',
888 [
889 'label' => esc_html__( 'Normal', 'elementor' ),
890 ]
891 );
892
893 $this->add_control( 'icon_color', [
894 'label' => esc_html__( 'Color', 'elementor' ),
895 'type' => Controls_Manager::COLOR,
896 'selectors' => [
897 '{{WRAPPER}}' => '--n-tabs-icon-color: {{VALUE}};',
898 ],
899 ] );
900
901 $this->end_controls_tab();
902
903 $this->start_controls_tab(
904 'icon_section_hover',
905 [
906 'label' => esc_html__( 'Hover', 'elementor' ),
907 ]
908 );
909
910 $this->add_control( 'icon_color_hover', [
911 'label' => esc_html__( 'Color', 'elementor' ),
912 'type' => Controls_Manager::COLOR,
913 'selectors' => [
914 '{{WRAPPER}} .e-n-tab-title:not( .e-active ):hover' => '--n-tabs-icon-color-hover: {{VALUE}};',
915 ],
916 ] );
917
918 $this->end_controls_tab();
919
920 $this->start_controls_tab(
921 'icon_section_active',
922 [
923 'label' => esc_html__( 'Active', 'elementor' ),
924 ]
925 );
926
927 $this->add_control( 'icon_color_active', [
928 'label' => esc_html__( 'Color', 'elementor' ),
929 'type' => Controls_Manager::COLOR,
930 'selectors' => [
931 '{{WRAPPER}}' => '--n-tabs-icon-color-active: {{VALUE}};',
932 ],
933 ] );
934
935 $this->end_controls_tab();
936
937 $this->end_controls_tabs();
938
939 $this->end_controls_section();
940
941 $this->start_controls_section( 'section_box_style', [
942 'label' => esc_html__( 'Content', 'elementor' ),
943 'tab' => Controls_Manager::TAB_STYLE,
944 ] );
945
946 $this->add_group_control(
947 Group_Control_Background::get_type(),
948 [
949 'name' => 'box_background_color',
950 'types' => [ 'classic', 'gradient' ],
951 'exclude' => [ 'image' ],
952 'selector' => "{$nested_tabs_content_selector_class}",
953 'fields_options' => [
954 'color' => [
955 'label' => esc_html__( 'Background Color', 'elementor' ),
956 ],
957 ],
958 ]
959 );
960
961 $this->add_group_control(
962 Group_Control_Border::get_type(),
963 [
964 'name' => 'box_border',
965 'selector' => "{$nested_tabs_content_selector_class}",
966 'fields_options' => [
967 'color' => [
968 'label' => esc_html__( 'Border Color', 'elementor' ),
969 ],
970 'width' => [
971 'label' => esc_html__( 'Border Width', 'elementor' ),
972 ],
973 ],
974 ]
975 );
976
977 $this->add_responsive_control(
978 'box_border_radius',
979 [
980 'label' => esc_html__( 'Border Radius', 'elementor' ),
981 'type' => Controls_Manager::DIMENSIONS,
982 'size_units' => [ 'px', 'em', 'rem' ],
983 'selectors' => [
984 '{{WRAPPER}}' => '--n-tabs-content-border-radius: {{TOP}}{{UNIT}} {{RIGHT}}{{UNIT}} {{BOTTOM}}{{UNIT}} {{LEFT}}{{UNIT}};',
985 ],
986 ]
987 );
988
989 $this->add_group_control(
990 Group_Control_Box_Shadow::get_type(),
991 [
992 'name' => 'box_shadow_box_shadow',
993 'selector' => "{$nested_tabs_content_selector_class}",
994 'condition' => [
995 'box_height!' => 'height',
996 ],
997 ]
998 );
999
1000 $this->add_responsive_control(
1001 'box_padding',
1002 [
1003 'label' => esc_html__( 'Padding', 'elementor' ),
1004 'type' => Controls_Manager::DIMENSIONS,
1005 'size_units' => [ 'px', 'em', 'rem' ],
1006 'selectors' => [
1007 '{{WRAPPER}}' => '--n-tabs-content-padding: {{TOP}}{{UNIT}} {{RIGHT}}{{UNIT}} {{BOTTOM}}{{UNIT}} {{LEFT}}{{UNIT}};',
1008 ],
1009 ]
1010 );
1011
1012 $this->end_controls_section();
1013 }
1014
1015 protected function render() {
1016 // Copied from tabs.php
1017 $settings = $this->get_settings_for_display();
1018 $tabs = $settings['tabs'];
1019
1020 $id_int = substr( $this->get_id_int(), 0, 3 );
1021
1022 $a11y_improvements_experiment = Plugin::$instance->experiments->is_feature_active( 'a11y_improvements' );
1023
1024 if ( ! empty( $settings['link'] ) ) {
1025 $this->add_link_attributes( 'elementor-tabs', $settings['link'] );
1026 }
1027
1028 $this->add_render_attribute( 'elementor-tabs', 'class', 'e-n-tabs' );
1029 $this->add_render_attribute( 'tab-title-text', 'class', 'e-n-tab-title-text' );
1030 $this->add_render_attribute( 'tab-icon', 'class', 'e-n-tab-icon' );
1031 $this->add_render_attribute( 'tab-icon-active', 'class', [ 'e-n-tab-icon', 'e-active' ] );
1032
1033 $tabs_title_html = '';
1034 $mobile_tabs_title_html = '';
1035
1036 foreach ( $tabs as $index => $item ) {
1037 // Tabs title.
1038 $tab_count = $index + 1;
1039 $tab_title_setting_key = $this->get_repeater_setting_key( 'tab_title', 'tabs', $index );
1040 $tab_title = $a11y_improvements_experiment ? $item['tab_title'] : '<a href="">' . $item['tab_title'] . '</a>';
1041 $tab_title_mobile_setting_key = $this->get_repeater_setting_key( 'tab_title_mobile', 'tabs', $tab_count );
1042 $tab_title_classes = [ 'e-n-tab-title', 'e-normal' ];
1043 $tab_title_mobile_classes = [ 'e-n-tab-title', 'e-collapse' ];
1044
1045 if ( $settings['hover_animation'] ) {
1046 array_push( $tab_title_classes, 'elementor-animation-' . $settings['hover_animation'] );
1047 array_push( $tab_title_mobile_classes, 'elementor-animation-' . $settings['hover_animation'] );
1048 }
1049
1050 $tab_id = empty( $item['element_id'] ) ? 'e-n-tabs-title-' . $id_int . $tab_count : $item['element_id'];
1051
1052 $this->add_render_attribute( $tab_title_setting_key, [
1053 'id' => $tab_id,
1054 'class' => $tab_title_classes,
1055 'aria-selected' => 1 === $tab_count ? 'true' : 'false',
1056 'data-tab' => $tab_count,
1057 'role' => 'tab',
1058 'tabindex' => 1 === $tab_count ? '0' : '-1',
1059 'aria-controls' => 'e-n-tab-content-' . $id_int . $tab_count,
1060 'aria-expanded' => 'false',
1061 ] );
1062
1063 $this->add_render_attribute( $tab_title_mobile_setting_key, [
1064 'class' => $tab_title_mobile_classes,
1065 'aria-selected' => 1 === $tab_count ? 'true' : 'false',
1066 'data-tab' => $tab_count,
1067 'role' => 'tab',
1068 'tabindex' => 1 === $tab_count ? '0' : '-1',
1069 'aria-controls' => 'e-n-tab-content-' . $id_int . $tab_count,
1070 'aria-expanded' => 'false',
1071 'id' => $tab_id . '-accordion',
1072 ] );
1073
1074 $title_render_attributes = $this->get_render_attribute_string( $tab_title_setting_key );
1075 $mobile_title_attributes = $this->get_render_attribute_string( $tab_title_mobile_setting_key );
1076 $tab_title_text_class = $this->get_render_attribute_string( 'tab-title-text' );
1077 $tab_icon_class = $this->get_render_attribute_string( 'tab-icon' );
1078
1079 $icon_html = Icons_Manager::try_get_icon_html( $item['tab_icon'], [ 'aria-hidden' => 'true' ] );
1080 $icon_active_html = $icon_html;
1081
1082 if ( $this->is_active_icon_exist( $item ) ) {
1083 $icon_active_html = Icons_Manager::try_get_icon_html( $item['tab_icon_active'], [ 'aria-hidden' => 'true' ] );
1084 }
1085
1086 $tabs_title_html .= "<div {$title_render_attributes}>";
1087 $tabs_title_html .= "\t<span {$tab_icon_class}>{$icon_html}{$icon_active_html}</span>";
1088 $tabs_title_html .= "\t<span {$tab_title_text_class}>{$tab_title}</span>";
1089 $tabs_title_html .= '</div>';
1090
1091 // Tabs content.
1092 ob_start();
1093 $this->print_child( $index );
1094 $tab_content = ob_get_clean();
1095
1096 $mobile_tabs_title_html .= "<div $mobile_title_attributes>";
1097 $mobile_tabs_title_html .= "\t<span {$tab_icon_class}>{$icon_html}{$icon_active_html}</span>";
1098 $mobile_tabs_title_html .= "\t<span {$tab_title_text_class}>{$tab_title}</span>";
1099 $mobile_tabs_title_html .= "</div>$tab_content";
1100 }
1101 ?>
1102 <div <?php $this->print_render_attribute_string( 'elementor-tabs' ); ?>>
1103 <div class="e-n-tabs-heading" role="tablist">
1104 <?php echo $tabs_title_html;// phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped ?>
1105 </div>
1106 <div class="e-n-tabs-content" role="tablist" aria-orientation="vertical">
1107 <?php echo $mobile_tabs_title_html;// phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped ?>
1108 </div>
1109 </div>
1110 <?php
1111 }
1112
1113 protected function content_template() {
1114 ?>
1115 <div class="e-n-tabs" role="tablist" aria-orientation="vertical">
1116 <# if ( settings['tabs'] ) {
1117 const elementUid = view.getIDInt().toString().substr( 0, 3 ); #>
1118 <div class="e-n-tabs-heading" role="tablist">
1119 <# _.each( settings['tabs'], function( item, index ) {
1120 const tabCount = index + 1,
1121 tabUid = elementUid + tabCount,
1122 tabWrapperKey = tabUid,
1123 tabTitleKey = 'tab-title-' + tabUid,
1124 tabIconKey = 'tab-icon-' + tabUid,
1125 tabIcon = elementor.helpers.renderIcon( view, item.tab_icon, { 'aria-hidden': true }, 'i' , 'object' ),
1126 hoverAnimationClass = settings['hover_animation'] ? `elementor-animation-${ settings['hover_animation'] }` : '';
1127
1128 let tabActiveIcon = tabIcon,
1129 tabId = 'e-n-tab-title-' + tabUid;
1130
1131 if ( '' !== item.tab_icon_active.value ) {
1132 tabActiveIcon = elementor.helpers.renderIcon( view, item.tab_icon_active, { 'aria-hidden': true }, 'i' , 'object' );
1133 }
1134
1135 if ( '' !== item.element_id ) {
1136 tabId = item.element_id;
1137 }
1138
1139 view.addRenderAttribute( tabWrapperKey, {
1140 'id': tabId,
1141 'class': [ 'e-n-tab-title','e-normal',hoverAnimationClass ],
1142 'data-tab': tabCount,
1143 'role': 'tab',
1144 'tabindex': 1 === tabCount ? '0' : '-1',
1145 'aria-controls': 'e-n-tab-content-' + tabUid,
1146 'aria-expanded': 'false',
1147 } );
1148
1149 view.addRenderAttribute( tabTitleKey, {
1150 'class': [ 'e-n-tab-title-text' ],
1151 'data-binding-type': 'repeater-item',
1152 'data-binding-repeater-name': 'tabs',
1153 'data-binding-setting': [ 'tab_title' ],
1154 'data-binding-index': tabCount,
1155 } );
1156
1157 view.addRenderAttribute( tabIconKey, {
1158 'class': [ 'e-n-tab-icon' ],
1159 'data-binding-type': 'repeater-item',
1160 'data-binding-repeater-name': 'tabs',
1161 'data-binding-setting': [ 'tab_icon.value', 'tab_icon_active.value' ],
1162 'data-binding-index': tabCount,
1163 } );
1164 #>
1165 <div {{{ view.getRenderAttributeString( tabWrapperKey ) }}}>
1166 <span {{{ view.getRenderAttributeString( tabIconKey ) }}}>{{{ tabIcon.value }}}{{{ tabActiveIcon.value }}}</span>
1167 <span {{{ view.getRenderAttributeString( tabTitleKey ) }}}>{{{ item.tab_title }}}</span>
1168 </div>
1169 <# } ); #>
1170 </div>
1171 <div class="e-n-tabs-content">
1172 </div>
1173 <# } #>
1174 </div>
1175 <?php
1176 }
1177
1178 /**
1179 * @param $item
1180 * @return bool
1181 */
1182 private function is_active_icon_exist( $item ) {
1183 return array_key_exists( 'tab_icon_active', $item ) && ! empty( $item['tab_icon_active'] ) && ! empty( $item['tab_icon_active']['value'] );
1184 }
1185 }
1186