PluginProbe
King Addons for Elementor – 80+ Elementor Widgets, 4 000+ Elementor Templates, WooCommerce, Mega Menu, Popup Builder / 51.1.49
King Addons for Elementor – 80+ Elementor Widgets, 4 000+ Elementor Templates, WooCommerce, Mega Menu, Popup Builder v51.1.49
51.1.83 51.1.82 51.1.81 51.1.79 51.1.78 51.1.77 51.1.76 51.1.74 51.1.75 51.1.65 51.1.64 51.1.63 trunk 51.1.14 51.1.2 51.1.35 51.1.36 51.1.37 51.1.38 51.1.39 51.1.44 51.1.45 51.1.46 51.1.47 51.1.49 All 37 releases
king-addons / includes / widgets / Unfold / Unfold.php

Unfold.php in King Addons for Elementor – 80+ Elementor Widgets, 4 000+ Elementor Templates, WooCommerce, Mega Menu, Popup Builder 51.1.49, at includes/widgets/Unfold/Unfold.php

1,726 lines 58.3 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * Unfold Widget (Free).
4 *
5 * @package King_Addons
6 */
7
8 namespace King_Addons;
9
10 use Elementor\Controls_Manager;
11 use Elementor\Group_Control_Background;
12 use Elementor\Group_Control_Border;
13 use Elementor\Group_Control_Box_Shadow;
14 use Elementor\Group_Control_Typography;
15 use Elementor\Icons_Manager;
16 use Elementor\Plugin;
17 use Elementor\Widget_Base;
18
19 if (!defined('ABSPATH')) {
20 exit;
21 }
22
23 /**
24 * Collapsible content box with fade overlay.
25 */
26 class Unfold extends Widget_Base
27 {
28 /**
29 * Widget slug.
30 *
31 * @return string
32 */
33 public function get_name(): string
34 {
35 return 'king-addons-unfold';
36 }
37
38 /**
39 * Widget title.
40 *
41 * @return string
42 */
43 public function get_title(): string
44 {
45 return esc_html__('Unfold', 'king-addons');
46 }
47
48 /**
49 * Widget icon.
50 *
51 * @return string
52 */
53 public function get_icon(): string
54 {
55 return 'king-addons-icon king-addons-unfold';
56 }
57
58 /**
59 * Widget categories.
60 *
61 * @return array<int, string>
62 */
63 public function get_categories(): array
64 {
65 return ['king-addons'];
66 }
67
68 /**
69 * Search keywords.
70 *
71 * @return array<int, string>
72 */
73 public function get_keywords(): array
74 {
75 return ['unfold', 'toggle', 'collapse', 'read more', 'expand'];
76 }
77
78 /**
79 * Style dependencies.
80 *
81 * @return array<int, string>
82 */
83 public function get_style_depends(): array
84 {
85 return [
86 KING_ADDONS_ASSETS_UNIQUE_KEY . '-unfold-style',
87 ];
88 }
89
90 /**
91 * Script dependencies.
92 *
93 * @return array<int, string>
94 */
95 public function get_script_depends(): array
96 {
97 return [
98 KING_ADDONS_ASSETS_UNIQUE_KEY . '-unfold-script',
99 ];
100 }
101
102 /**
103 * Register controls.
104 *
105 * @return void
106 */
107 public function register_controls(): void
108 {
109 $this->register_content_controls(false);
110 $this->register_button_controls(false);
111 $this->register_fade_controls(false);
112 $this->register_advanced_controls(false);
113 $this->register_style_box_controls();
114 $this->register_style_title_controls();
115 $this->register_style_content_controls();
116 $this->register_style_button_controls();
117 $this->register_style_fade_controls();
118 $this->register_pro_notice_controls();
119 }
120
121 /**
122 * Render widget.
123 *
124 * @return void
125 */
126 public function render(): void
127 {
128 $this->render_output(false);
129 }
130
131 /**
132 * Register content controls.
133 *
134 * @param bool $is_pro Whether pro controls are available.
135 *
136 * @return void
137 */
138 public function register_content_controls(bool $is_pro): void
139 {
140 $this->start_controls_section(
141 'kng_content_section',
142 [
143 'label' => KING_ADDONS_ELEMENTOR_ICON . esc_html__('Content', 'king-addons'),
144 'tab' => Controls_Manager::TAB_CONTENT,
145 ]
146 );
147
148 $this->add_control(
149 'kng_content_source',
150 [
151 'label' => esc_html__('Content Source', 'king-addons'),
152 'type' => Controls_Manager::SELECT,
153 'default' => 'editor',
154 'options' => [
155 'editor' => esc_html__('Editor', 'king-addons'),
156 'template' => $is_pro ?
157 esc_html__('Elementor Template', 'king-addons') :
158 sprintf('%s %s', esc_html__('Elementor Template', 'king-addons'), '<i class="eicon-pro-icon"></i>'),
159 ],
160 'description' => $is_pro ? '' : esc_html__('Use Elementor Template with the Pro version.', 'king-addons'),
161 ]
162 );
163
164 $this->add_control(
165 'kng_title_enable',
166 [
167 'label' => esc_html__('Title Enable', 'king-addons'),
168 'type' => Controls_Manager::SWITCHER,
169 'return_value' => 'yes',
170 'default' => '',
171 ]
172 );
173
174 $this->add_control(
175 'kng_title',
176 [
177 'label' => esc_html__('Title', 'king-addons'),
178 'type' => Controls_Manager::TEXT,
179 'default' => esc_html__('Expandable block', 'king-addons'),
180 'condition' => [
181 'kng_title_enable' => 'yes',
182 ],
183 ]
184 );
185
186 $this->add_control(
187 'kng_title_tag',
188 [
189 'label' => esc_html__('Title HTML Tag', 'king-addons'),
190 'type' => Controls_Manager::SELECT,
191 'options' => [
192 'h1' => 'H1',
193 'h2' => 'H2',
194 'h3' => 'H3',
195 'h4' => 'H4',
196 'h5' => 'H5',
197 'h6' => 'H6',
198 'div' => 'DIV',
199 ],
200 'default' => 'h3',
201 'condition' => [
202 'kng_title_enable' => 'yes',
203 ],
204 ]
205 );
206
207 $this->add_control(
208 'kng_editor_content',
209 [
210 'label' => esc_html__('Content', 'king-addons'),
211 'type' => Controls_Manager::WYSIWYG,
212 'default' => esc_html__('Add your description here. The block will unfold to reveal the full content.', 'king-addons'),
213 'condition' => [
214 'kng_content_source' => 'editor',
215 ],
216 ]
217 );
218
219 $this->add_control(
220 'kng_template_id',
221 [
222 'label' => sprintf('%s %s', esc_html__('Template', 'king-addons'), $is_pro ? '' : '<i class="eicon-pro-icon"></i>'),
223 'type' => Controls_Manager::SELECT,
224 'options' => $is_pro ? $this->get_elementor_templates_options() : [],
225 'condition' => [
226 'kng_content_source' => 'template',
227 ],
228 'description' => $is_pro ? '' : esc_html__('Select an Elementor template (Pro).', 'king-addons'),
229 ]
230 );
231
232 $this->add_responsive_control(
233 'kng_content_alignment',
234 [
235 'label' => esc_html__('Alignment', 'king-addons'),
236 'type' => Controls_Manager::CHOOSE,
237 'options' => [
238 'left' => [
239 'title' => esc_html__('Left', 'king-addons'),
240 'icon' => 'eicon-text-align-left',
241 ],
242 'center' => [
243 'title' => esc_html__('Center', 'king-addons'),
244 'icon' => 'eicon-text-align-center',
245 ],
246 'right' => [
247 'title' => esc_html__('Right', 'king-addons'),
248 'icon' => 'eicon-text-align-right',
249 ],
250 'justify' => [
251 'title' => esc_html__('Justify', 'king-addons'),
252 'icon' => 'eicon-text-align-justify',
253 ],
254 ],
255 'default' => 'left',
256 'selectors' => [
257 '{{WRAPPER}} .king-addons-unfold__box' => 'text-align: {{VALUE}};',
258 ],
259 ]
260 );
261
262 $this->end_controls_section();
263 }
264
265 /**
266 * Register button controls.
267 *
268 * @param bool $is_pro Whether pro controls are available.
269 *
270 * @return void
271 */
272 public function register_button_controls(bool $is_pro): void
273 {
274 $this->start_controls_section(
275 'kng_button_section',
276 [
277 'label' => KING_ADDONS_ELEMENTOR_ICON . esc_html__('Button', 'king-addons'),
278 'tab' => Controls_Manager::TAB_CONTENT,
279 ]
280 );
281
282 $this->add_control(
283 'kng_button_enable',
284 [
285 'label' => esc_html__('Button Enable', 'king-addons'),
286 'type' => Controls_Manager::SWITCHER,
287 'return_value' => 'yes',
288 'default' => 'yes',
289 ]
290 );
291
292 $this->add_control(
293 'kng_unfold_text',
294 [
295 'label' => esc_html__('Unfold Text', 'king-addons'),
296 'type' => Controls_Manager::TEXT,
297 'default' => esc_html__('Read more', 'king-addons'),
298 'condition' => [
299 'kng_button_enable' => 'yes',
300 ],
301 ]
302 );
303
304 $this->add_control(
305 'kng_fold_text',
306 [
307 'label' => esc_html__('Fold Text', 'king-addons'),
308 'type' => Controls_Manager::TEXT,
309 'default' => esc_html__('Read less', 'king-addons'),
310 'condition' => [
311 'kng_button_enable' => 'yes',
312 ],
313 ]
314 );
315
316 $this->add_control(
317 'kng_icon_enable',
318 [
319 'label' => esc_html__('Icon Enable', 'king-addons'),
320 'type' => Controls_Manager::SWITCHER,
321 'return_value' => 'yes',
322 'default' => 'yes',
323 'condition' => [
324 'kng_button_enable' => 'yes',
325 ],
326 ]
327 );
328
329 $this->add_control(
330 'kng_unfold_icon',
331 [
332 'label' => esc_html__('Unfold Icon', 'king-addons'),
333 'type' => Controls_Manager::ICONS,
334 'default' => [
335 'value' => 'fas fa-chevron-down',
336 'library' => 'fa-solid',
337 ],
338 'condition' => [
339 'kng_button_enable' => 'yes',
340 'kng_icon_enable' => 'yes',
341 ],
342 ]
343 );
344
345 $this->add_control(
346 'kng_fold_icon',
347 [
348 'label' => esc_html__('Fold Icon', 'king-addons'),
349 'type' => Controls_Manager::ICONS,
350 'default' => [
351 'value' => 'fas fa-chevron-up',
352 'library' => 'fa-solid',
353 ],
354 'condition' => [
355 'kng_button_enable' => 'yes',
356 'kng_icon_enable' => 'yes',
357 ],
358 ]
359 );
360
361 $this->add_control(
362 'kng_icon_position',
363 [
364 'label' => esc_html__('Icon Position', 'king-addons'),
365 'type' => Controls_Manager::SELECT,
366 'default' => 'before',
367 'options' => [
368 'before' => esc_html__('Before', 'king-addons'),
369 'after' => esc_html__('After', 'king-addons'),
370 ],
371 'condition' => [
372 'kng_button_enable' => 'yes',
373 'kng_icon_enable' => 'yes',
374 ],
375 ]
376 );
377
378 $this->add_control(
379 'kng_button_size',
380 [
381 'label' => esc_html__('Button Size', 'king-addons'),
382 'type' => Controls_Manager::SELECT,
383 'default' => 'md',
384 'options' => [
385 'xs' => esc_html__('XS', 'king-addons'),
386 'sm' => esc_html__('SM', 'king-addons'),
387 'md' => esc_html__('MD', 'king-addons'),
388 'lg' => esc_html__('LG', 'king-addons'),
389 'block' => esc_html__('Block', 'king-addons'),
390 ],
391 'condition' => [
392 'kng_button_enable' => 'yes',
393 ],
394 ]
395 );
396
397 $this->add_control(
398 'kng_button_position',
399 [
400 'label' => $is_pro ?
401 esc_html__('Button Position', 'king-addons') :
402 sprintf(__('Button Position %s', 'king-addons'), '<i class="eicon-pro-icon"></i>'),
403 'type' => Controls_Manager::SELECT,
404 'default' => 'outside',
405 'options' => [
406 'inside' => esc_html__('Inside', 'king-addons'),
407 'outside' => esc_html__('Outside', 'king-addons'),
408 ],
409 'condition' => [
410 'kng_button_enable' => 'yes',
411 ],
412 'description' => $is_pro ? '' : esc_html__('Inside placement is available in Pro.', 'king-addons'),
413 ]
414 );
415
416 $this->add_responsive_control(
417 'kng_button_alignment',
418 [
419 'label' => esc_html__('Button Alignment', 'king-addons'),
420 'type' => Controls_Manager::CHOOSE,
421 'options' => [
422 'flex-start' => [
423 'title' => esc_html__('Left', 'king-addons'),
424 'icon' => 'eicon-text-align-left',
425 ],
426 'center' => [
427 'title' => esc_html__('Center', 'king-addons'),
428 'icon' => 'eicon-text-align-center',
429 ],
430 'flex-end' => [
431 'title' => esc_html__('Right', 'king-addons'),
432 'icon' => 'eicon-text-align-right',
433 ],
434 ],
435 'default' => 'center',
436 'condition' => [
437 'kng_button_enable' => 'yes',
438 ],
439 'selectors' => [
440 '{{WRAPPER}} .king-addons-unfold__button-wrapper' => 'justify-content: {{VALUE}};',
441 ],
442 ]
443 );
444
445 $this->end_controls_section();
446 }
447
448 /**
449 * Register fade controls.
450 *
451 * @param bool $is_pro Whether pro controls are available.
452 *
453 * @return void
454 */
455 public function register_fade_controls(bool $is_pro): void
456 {
457 $this->start_controls_section(
458 'kng_fade_section',
459 [
460 'label' => KING_ADDONS_ELEMENTOR_ICON . esc_html__('Fade Effect', 'king-addons'),
461 'tab' => Controls_Manager::TAB_CONTENT,
462 ]
463 );
464
465 $this->add_control(
466 'kng_fade_enable',
467 [
468 'label' => esc_html__('Fade Enable', 'king-addons'),
469 'type' => Controls_Manager::SWITCHER,
470 'return_value' => 'yes',
471 'default' => 'yes',
472 ]
473 );
474
475 $this->add_control(
476 'kng_fade_height',
477 [
478 'label' => $is_pro ? esc_html__('Fade Height', 'king-addons') : sprintf(__('Fade Height %s', 'king-addons'), '<i class="eicon-pro-icon"></i>'),
479 'type' => Controls_Manager::SLIDER,
480 'size_units' => ['px'],
481 'range' => [
482 'px' => [
483 'min' => 0,
484 'max' => 400,
485 ],
486 ],
487 'default' => [
488 'unit' => 'px',
489 'size' => 30,
490 ],
491 'condition' => [
492 'kng_fade_enable' => 'yes',
493 ],
494 'description' => $is_pro ? '' : esc_html__('Adjustable fade height is available in Pro.', 'king-addons'),
495 ]
496 );
497
498 $this->add_control(
499 'kng_fade_only_folded',
500 [
501 'label' => esc_html__('Fade Only When Folded', 'king-addons'),
502 'type' => Controls_Manager::SWITCHER,
503 'return_value' => 'yes',
504 'default' => 'yes',
505 'condition' => [
506 'kng_fade_enable' => 'yes',
507 ],
508 ]
509 );
510
511 $this->end_controls_section();
512 }
513
514 /**
515 * Register advanced controls.
516 *
517 * @param bool $is_pro Whether pro controls are available.
518 *
519 * @return void
520 */
521 public function register_advanced_controls(bool $is_pro): void
522 {
523 $this->start_controls_section(
524 'kng_advanced_section',
525 [
526 'label' => KING_ADDONS_ELEMENTOR_ICON . esc_html__('Advanced Settings', 'king-addons'),
527 'tab' => Controls_Manager::TAB_CONTENT,
528 ]
529 );
530
531 $this->add_control(
532 'kng_initial_state',
533 [
534 'label' => esc_html__('Initial State', 'king-addons'),
535 'type' => Controls_Manager::SELECT,
536 'default' => 'folded',
537 'options' => [
538 'folded' => esc_html__('Folded', 'king-addons'),
539 'unfolded' => esc_html__('Unfolded', 'king-addons'),
540 ],
541 ]
542 );
543
544 $this->add_control(
545 'kng_fold_height_unit',
546 [
547 'label' => esc_html__('Fold Height Unit', 'king-addons'),
548 'type' => Controls_Manager::CHOOSE,
549 'options' => [
550 'percent' => [
551 'title' => esc_html__('Percent', 'king-addons'),
552 'icon' => 'eicon-percentage',
553 ],
554 'px' => [
555 'title' => esc_html__('PX', 'king-addons'),
556 'icon' => 'eicon-editor-list-ol',
557 ],
558 ],
559 'default' => 'percent',
560 ]
561 );
562
563 $this->add_responsive_control(
564 'kng_fold_height_percent',
565 [
566 'label' => esc_html__('Fold Height', 'king-addons'),
567 'type' => Controls_Manager::SLIDER,
568 'size_units' => ['%'],
569 'range' => [
570 '%' => [
571 'min' => 10,
572 'max' => 100,
573 ],
574 ],
575 'default' => [
576 'unit' => '%',
577 'size' => 60,
578 ],
579 'condition' => [
580 'kng_fold_height_unit' => 'percent',
581 ],
582 ]
583 );
584
585 $this->add_responsive_control(
586 'kng_fold_height_px',
587 [
588 'label' => $is_pro ? esc_html__('Fold Height', 'king-addons') : sprintf(__('Fold Height %s', 'king-addons'), '<i class="eicon-pro-icon"></i>'),
589 'type' => Controls_Manager::SLIDER,
590 'size_units' => ['px'],
591 'range' => [
592 'px' => [
593 'min' => 50,
594 'max' => 2000,
595 ],
596 ],
597 'default' => [
598 'unit' => 'px',
599 'size' => 320,
600 ],
601 'condition' => [
602 'kng_fold_height_unit' => 'px',
603 ],
604 'description' => $is_pro ? '' : esc_html__('Fixed height is available in Pro.', 'king-addons'),
605 ]
606 );
607
608 $this->add_control(
609 'kng_shared_duration',
610 [
611 'label' => esc_html__('Animation Duration', 'king-addons'),
612 'type' => Controls_Manager::SELECT,
613 'default' => 'normal',
614 'options' => [
615 'fast' => esc_html__('Fast', 'king-addons'),
616 'normal' => esc_html__('Normal', 'king-addons'),
617 'slow' => esc_html__('Slow', 'king-addons'),
618 'custom' => esc_html__('Custom', 'king-addons'),
619 ],
620 ]
621 );
622
623 $this->add_control(
624 'kng_shared_duration_custom',
625 [
626 'label' => esc_html__('Custom Duration (s)', 'king-addons'),
627 'type' => Controls_Manager::NUMBER,
628 'min' => 0.1,
629 'step' => 0.1,
630 'default' => 0.5,
631 'condition' => [
632 'kng_shared_duration' => 'custom',
633 ],
634 ]
635 );
636
637 $this->add_control(
638 'kng_shared_easing',
639 [
640 'label' => esc_html__('Easing', 'king-addons'),
641 'type' => Controls_Manager::SELECT,
642 'default' => 'ease',
643 'options' => [
644 'linear' => esc_html__('Linear', 'king-addons'),
645 'ease' => esc_html__('Ease', 'king-addons'),
646 'ease-in' => esc_html__('Ease In', 'king-addons'),
647 'ease-out' => esc_html__('Ease Out', 'king-addons'),
648 'ease-in-out' => esc_html__('Ease In Out', 'king-addons'),
649 ],
650 ]
651 );
652
653 $this->add_control(
654 'kng_fold_duration_mode',
655 [
656 'label' => $is_pro ? esc_html__('Fold Duration', 'king-addons') : sprintf(__('Fold Duration %s', 'king-addons'), '<i class="eicon-pro-icon"></i>'),
657 'type' => Controls_Manager::SELECT,
658 'default' => 'shared',
659 'options' => [
660 'shared' => esc_html__('Use Shared', 'king-addons'),
661 'fast' => esc_html__('Fast', 'king-addons'),
662 'normal' => esc_html__('Normal', 'king-addons'),
663 'slow' => esc_html__('Slow', 'king-addons'),
664 'custom' => esc_html__('Custom', 'king-addons'),
665 ],
666 'description' => $is_pro ? '' : esc_html__('Separate duration is available in Pro.', 'king-addons'),
667 ]
668 );
669
670 $this->add_control(
671 'kng_fold_duration_custom',
672 [
673 'label' => esc_html__('Fold Custom (s)', 'king-addons'),
674 'type' => Controls_Manager::NUMBER,
675 'min' => 0.1,
676 'step' => 0.1,
677 'default' => 0.5,
678 'condition' => [
679 'kng_fold_duration_mode' => 'custom',
680 ],
681 ]
682 );
683
684 $this->add_control(
685 'kng_fold_easing',
686 [
687 'label' => $is_pro ? esc_html__('Fold Easing', 'king-addons') : sprintf(__('Fold Easing %s', 'king-addons'), '<i class="eicon-pro-icon"></i>'),
688 'type' => Controls_Manager::SELECT,
689 'default' => 'shared',
690 'options' => [
691 'shared' => esc_html__('Use Shared', 'king-addons'),
692 'linear' => esc_html__('Linear', 'king-addons'),
693 'ease' => esc_html__('Ease', 'king-addons'),
694 'ease-in' => esc_html__('Ease In', 'king-addons'),
695 'ease-out' => esc_html__('Ease Out', 'king-addons'),
696 'ease-in-out' => esc_html__('Ease In Out', 'king-addons'),
697 ],
698 'description' => $is_pro ? '' : esc_html__('Separate easing is available in Pro.', 'king-addons'),
699 ]
700 );
701
702 $this->add_control(
703 'kng_unfold_duration_mode',
704 [
705 'label' => $is_pro ? esc_html__('Unfold Duration', 'king-addons') : sprintf(__('Unfold Duration %s', 'king-addons'), '<i class="eicon-pro-icon"></i>'),
706 'type' => Controls_Manager::SELECT,
707 'default' => 'shared',
708 'options' => [
709 'shared' => esc_html__('Use Shared', 'king-addons'),
710 'fast' => esc_html__('Fast', 'king-addons'),
711 'normal' => esc_html__('Normal', 'king-addons'),
712 'slow' => esc_html__('Slow', 'king-addons'),
713 'custom' => esc_html__('Custom', 'king-addons'),
714 ],
715 'description' => $is_pro ? '' : esc_html__('Separate duration is available in Pro.', 'king-addons'),
716 ]
717 );
718
719 $this->add_control(
720 'kng_unfold_duration_custom',
721 [
722 'label' => esc_html__('Unfold Custom (s)', 'king-addons'),
723 'type' => Controls_Manager::NUMBER,
724 'min' => 0.1,
725 'step' => 0.1,
726 'default' => 0.5,
727 'condition' => [
728 'kng_unfold_duration_mode' => 'custom',
729 ],
730 ]
731 );
732
733 $this->add_control(
734 'kng_unfold_easing',
735 [
736 'label' => $is_pro ? esc_html__('Unfold Easing', 'king-addons') : sprintf(__('Unfold Easing %s', 'king-addons'), '<i class="eicon-pro-icon"></i>'),
737 'type' => Controls_Manager::SELECT,
738 'default' => 'shared',
739 'options' => [
740 'shared' => esc_html__('Use Shared', 'king-addons'),
741 'linear' => esc_html__('Linear', 'king-addons'),
742 'ease' => esc_html__('Ease', 'king-addons'),
743 'ease-in' => esc_html__('Ease In', 'king-addons'),
744 'ease-out' => esc_html__('Ease Out', 'king-addons'),
745 'ease-in-out' => esc_html__('Ease In Out', 'king-addons'),
746 ],
747 'description' => $is_pro ? '' : esc_html__('Separate easing is available in Pro.', 'king-addons'),
748 ]
749 );
750
751 $this->add_control(
752 'kng_animate_height_type',
753 [
754 'label' => $is_pro ? esc_html__('Animate Height Type', 'king-addons') : sprintf(__('Animate Height Type %s', 'king-addons'), '<i class="eicon-pro-icon"></i>'),
755 'type' => Controls_Manager::SELECT,
756 'default' => 'auto-to-fixed',
757 'options' => [
758 'auto-to-fixed' => esc_html__('Auto to fixed', 'king-addons'),
759 'max-height' => esc_html__('Max height', 'king-addons'),
760 ],
761 'description' => $is_pro ? '' : esc_html__('Max height animation is available in Pro.', 'king-addons'),
762 ]
763 );
764
765 $this->add_control(
766 'kng_scroll_after_unfold',
767 [
768 'label' => $is_pro ? esc_html__('Scroll After Unfold', 'king-addons') : sprintf(__('Scroll After Unfold %s', 'king-addons'), '<i class="eicon-pro-icon"></i>'),
769 'type' => Controls_Manager::SWITCHER,
770 'return_value' => 'yes',
771 'default' => '',
772 'description' => $is_pro ? '' : esc_html__('Auto scroll is available in Pro.', 'king-addons'),
773 ]
774 );
775
776 $this->add_responsive_control(
777 'kng_scroll_offset',
778 [
779 'label' => esc_html__('Scroll Offset', 'king-addons'),
780 'type' => Controls_Manager::SLIDER,
781 'size_units' => ['px'],
782 'range' => [
783 'px' => [
784 'min' => 0,
785 'max' => 400,
786 ],
787 ],
788 'default' => [
789 'unit' => 'px',
790 'size' => 40,
791 ],
792 'condition' => [
793 'kng_scroll_after_unfold' => 'yes',
794 ],
795 ]
796 );
797
798 $this->end_controls_section();
799 }
800
801 /**
802 * Register box style controls.
803 *
804 * @return void
805 */
806 public function register_style_box_controls(): void
807 {
808 $this->start_controls_section(
809 'kng_box_style_section',
810 [
811 'label' => KING_ADDONS_ELEMENTOR_ICON . esc_html__('Box', 'king-addons'),
812 'tab' => Controls_Manager::TAB_STYLE,
813 ]
814 );
815
816 $this->add_group_control(
817 Group_Control_Background::get_type(),
818 [
819 'name' => 'kng_box_background',
820 'types' => ['classic', 'gradient'],
821 'selector' => '{{WRAPPER}} .king-addons-unfold__box',
822 ]
823 );
824
825 $this->add_group_control(
826 Group_Control_Border::get_type(),
827 [
828 'name' => 'kng_box_border',
829 'selector' => '{{WRAPPER}} .king-addons-unfold__box',
830 ]
831 );
832
833 $this->add_control(
834 'kng_box_border_radius',
835 [
836 'label' => esc_html__('Border Radius', 'king-addons'),
837 'type' => Controls_Manager::DIMENSIONS,
838 'size_units' => ['px', '%'],
839 'selectors' => [
840 '{{WRAPPER}} .king-addons-unfold__box' => 'border-radius: {{TOP}}{{UNIT}} {{RIGHT}}{{UNIT}} {{BOTTOM}}{{UNIT}} {{LEFT}}{{UNIT}};',
841 ],
842 ]
843 );
844
845 $this->add_group_control(
846 Group_Control_Box_Shadow::get_type(),
847 [
848 'name' => 'kng_box_shadow',
849 'selector' => '{{WRAPPER}} .king-addons-unfold__box',
850 ]
851 );
852
853 $this->add_responsive_control(
854 'kng_box_padding',
855 [
856 'label' => esc_html__('Padding', 'king-addons'),
857 'type' => Controls_Manager::DIMENSIONS,
858 'size_units' => ['px', '%', 'em'],
859 'selectors' => [
860 '{{WRAPPER}} .king-addons-unfold__box' => 'padding: {{TOP}}{{UNIT}} {{RIGHT}}{{UNIT}} {{BOTTOM}}{{UNIT}} {{LEFT}}{{UNIT}};',
861 ],
862 ]
863 );
864
865 $this->add_responsive_control(
866 'kng_box_margin',
867 [
868 'label' => esc_html__('Margin', 'king-addons'),
869 'type' => Controls_Manager::DIMENSIONS,
870 'size_units' => ['px', '%', 'em'],
871 'selectors' => [
872 '{{WRAPPER}} .king-addons-unfold' => 'margin: {{TOP}}{{UNIT}} {{RIGHT}}{{UNIT}} {{BOTTOM}}{{UNIT}} {{LEFT}}{{UNIT}};',
873 ],
874 ]
875 );
876
877 $this->end_controls_section();
878 }
879
880 /**
881 * Register title style controls.
882 *
883 * @return void
884 */
885 public function register_style_title_controls(): void
886 {
887 $this->start_controls_section(
888 'kng_title_style_section',
889 [
890 'label' => KING_ADDONS_ELEMENTOR_ICON . esc_html__('Title', 'king-addons'),
891 'tab' => Controls_Manager::TAB_STYLE,
892 'condition' => [
893 'kng_title_enable' => 'yes',
894 ],
895 ]
896 );
897
898 $this->add_group_control(
899 Group_Control_Typography::get_type(),
900 [
901 'name' => 'kng_title_typography',
902 'selector' => '{{WRAPPER}} .king-addons-unfold__title',
903 ]
904 );
905
906 $this->add_control(
907 'kng_title_color',
908 [
909 'label' => esc_html__('Text Color', 'king-addons'),
910 'type' => Controls_Manager::COLOR,
911 'selectors' => [
912 '{{WRAPPER}} .king-addons-unfold__title' => 'color: {{VALUE}};',
913 ],
914 ]
915 );
916
917 $this->add_responsive_control(
918 'kng_title_margin_bottom',
919 [
920 'label' => esc_html__('Margin Bottom', 'king-addons'),
921 'type' => Controls_Manager::SLIDER,
922 'size_units' => ['px', 'em'],
923 'range' => [
924 'px' => [
925 'min' => 0,
926 'max' => 200,
927 ],
928 ],
929 'selectors' => [
930 '{{WRAPPER}} .king-addons-unfold__title' => 'margin-bottom: {{SIZE}}{{UNIT}};',
931 ],
932 ]
933 );
934
935 $this->end_controls_section();
936 }
937
938 /**
939 * Register content style controls.
940 *
941 * @return void
942 */
943 public function register_style_content_controls(): void
944 {
945 $this->start_controls_section(
946 'kng_content_style_section',
947 [
948 'label' => KING_ADDONS_ELEMENTOR_ICON . esc_html__('Content', 'king-addons'),
949 'tab' => Controls_Manager::TAB_STYLE,
950 ]
951 );
952
953 $this->add_group_control(
954 Group_Control_Typography::get_type(),
955 [
956 'name' => 'kng_content_typography',
957 'selector' => '{{WRAPPER}} .king-addons-unfold__content',
958 ]
959 );
960
961 $this->add_control(
962 'kng_content_color',
963 [
964 'label' => esc_html__('Text Color', 'king-addons'),
965 'type' => Controls_Manager::COLOR,
966 'selectors' => [
967 '{{WRAPPER}} .king-addons-unfold__content' => 'color: {{VALUE}};',
968 ],
969 ]
970 );
971
972 $this->add_control(
973 'kng_content_link_color',
974 [
975 'label' => esc_html__('Link Color', 'king-addons'),
976 'type' => Controls_Manager::COLOR,
977 'selectors' => [
978 '{{WRAPPER}} .king-addons-unfold__content a' => 'color: {{VALUE}};',
979 ],
980 ]
981 );
982
983 $this->add_control(
984 'kng_content_link_hover_color',
985 [
986 'label' => esc_html__('Link Hover Color', 'king-addons'),
987 'type' => Controls_Manager::COLOR,
988 'selectors' => [
989 '{{WRAPPER}} .king-addons-unfold__content a:hover' => 'color: {{VALUE}};',
990 ],
991 ]
992 );
993
994 $this->add_responsive_control(
995 'kng_paragraph_spacing',
996 [
997 'label' => esc_html__('Paragraph Spacing', 'king-addons'),
998 'type' => Controls_Manager::SLIDER,
999 'size_units' => ['px', 'em'],
1000 'range' => [
1001 'px' => [
1002 'min' => 0,
1003 'max' => 50,
1004 ],
1005 ],
1006 'selectors' => [
1007 '{{WRAPPER}} .king-addons-unfold__content p:not(:last-child)' => 'margin-bottom: {{SIZE}}{{UNIT}};',
1008 ],
1009 ]
1010 );
1011
1012 $this->end_controls_section();
1013 }
1014
1015 /**
1016 * Register button style controls.
1017 *
1018 * @return void
1019 */
1020 public function register_style_button_controls(): void
1021 {
1022 $this->start_controls_section(
1023 'kng_button_style_section',
1024 [
1025 'label' => KING_ADDONS_ELEMENTOR_ICON . esc_html__('Button', 'king-addons'),
1026 'tab' => Controls_Manager::TAB_STYLE,
1027 'condition' => [
1028 'kng_button_enable' => 'yes',
1029 ],
1030 ]
1031 );
1032
1033 $this->add_group_control(
1034 Group_Control_Typography::get_type(),
1035 [
1036 'name' => 'kng_button_typography',
1037 'selector' => '{{WRAPPER}} .king-addons-unfold__button',
1038 ]
1039 );
1040
1041 $this->start_controls_tabs('kng_button_style_tabs');
1042
1043 $this->start_controls_tab(
1044 'kng_button_tab_normal',
1045 [
1046 'label' => esc_html__('Normal', 'king-addons'),
1047 ]
1048 );
1049
1050 $this->add_control(
1051 'kng_button_text_color',
1052 [
1053 'label' => esc_html__('Text Color', 'king-addons'),
1054 'type' => Controls_Manager::COLOR,
1055 'selectors' => [
1056 '{{WRAPPER}} .king-addons-unfold__button' => 'color: {{VALUE}};',
1057 ],
1058 ]
1059 );
1060
1061 $this->add_control(
1062 'kng_button_background_color',
1063 [
1064 'label' => esc_html__('Background Color', 'king-addons'),
1065 'type' => Controls_Manager::COLOR,
1066 'selectors' => [
1067 '{{WRAPPER}} .king-addons-unfold__button' => 'background-color: {{VALUE}};',
1068 ],
1069 ]
1070 );
1071
1072 $this->add_group_control(
1073 Group_Control_Border::get_type(),
1074 [
1075 'name' => 'kng_button_border',
1076 'selector' => '{{WRAPPER}} .king-addons-unfold__button',
1077 ]
1078 );
1079
1080 $this->add_control(
1081 'kng_button_border_radius',
1082 [
1083 'label' => esc_html__('Border Radius', 'king-addons'),
1084 'type' => Controls_Manager::DIMENSIONS,
1085 'size_units' => ['px', '%'],
1086 'selectors' => [
1087 '{{WRAPPER}} .king-addons-unfold__button' => 'border-radius: {{TOP}}{{UNIT}} {{RIGHT}}{{UNIT}} {{BOTTOM}}{{UNIT}} {{LEFT}}{{UNIT}};',
1088 ],
1089 ]
1090 );
1091
1092 $this->add_group_control(
1093 Group_Control_Box_Shadow::get_type(),
1094 [
1095 'name' => 'kng_button_shadow',
1096 'selector' => '{{WRAPPER}} .king-addons-unfold__button',
1097 ]
1098 );
1099
1100 $this->add_responsive_control(
1101 'kng_button_padding',
1102 [
1103 'label' => esc_html__('Padding', 'king-addons'),
1104 'type' => Controls_Manager::DIMENSIONS,
1105 'size_units' => ['px', 'em'],
1106 'selectors' => [
1107 '{{WRAPPER}} .king-addons-unfold__button' => 'padding: {{TOP}}{{UNIT}} {{RIGHT}}{{UNIT}} {{BOTTOM}}{{UNIT}} {{LEFT}}{{UNIT}};',
1108 ],
1109 ]
1110 );
1111
1112 $this->add_control(
1113 'kng_icon_spacing',
1114 [
1115 'label' => esc_html__('Icon Spacing', 'king-addons'),
1116 'type' => Controls_Manager::SLIDER,
1117 'size_units' => ['px', 'em'],
1118 'range' => [
1119 'px' => [
1120 'min' => 0,
1121 'max' => 50,
1122 ],
1123 ],
1124 'selectors' => [
1125 '{{WRAPPER}} .king-addons-unfold__button--icon-before .king-addons-unfold__icon' => 'margin-right: {{SIZE}}{{UNIT}};',
1126 '{{WRAPPER}} .king-addons-unfold__button--icon-after .king-addons-unfold__icon' => 'margin-left: {{SIZE}}{{UNIT}};',
1127 ],
1128 'condition' => [
1129 'kng_icon_enable' => 'yes',
1130 ],
1131 ]
1132 );
1133
1134 $this->add_control(
1135 'kng_button_hover_animation',
1136 [
1137 'label' => esc_html__('Hover Animation', 'king-addons'),
1138 'type' => Controls_Manager::SELECT,
1139 'default' => 'none',
1140 'options' => [
1141 'none' => esc_html__('None', 'king-addons'),
1142 'lift' => esc_html__('Lift', 'king-addons'),
1143 'scale' => esc_html__('Scale', 'king-addons'),
1144 ],
1145 ]
1146 );
1147
1148 $this->end_controls_tab();
1149
1150 $this->start_controls_tab(
1151 'kng_button_tab_hover',
1152 [
1153 'label' => esc_html__('Hover', 'king-addons'),
1154 ]
1155 );
1156
1157 $this->add_control(
1158 'kng_button_text_color_hover',
1159 [
1160 'label' => esc_html__('Text Color', 'king-addons'),
1161 'type' => Controls_Manager::COLOR,
1162 'selectors' => [
1163 '{{WRAPPER}} .king-addons-unfold__button:hover' => 'color: {{VALUE}};',
1164 ],
1165 ]
1166 );
1167
1168 $this->add_control(
1169 'kng_button_background_color_hover',
1170 [
1171 'label' => esc_html__('Background Color', 'king-addons'),
1172 'type' => Controls_Manager::COLOR,
1173 'selectors' => [
1174 '{{WRAPPER}} .king-addons-unfold__button:hover' => 'background-color: {{VALUE}};',
1175 ],
1176 ]
1177 );
1178
1179 $this->add_group_control(
1180 Group_Control_Border::get_type(),
1181 [
1182 'name' => 'kng_button_border_hover',
1183 'selector' => '{{WRAPPER}} .king-addons-unfold__button:hover',
1184 ]
1185 );
1186
1187 $this->add_group_control(
1188 Group_Control_Box_Shadow::get_type(),
1189 [
1190 'name' => 'kng_button_shadow_hover',
1191 'selector' => '{{WRAPPER}} .king-addons-unfold__button:hover',
1192 ]
1193 );
1194
1195 $this->end_controls_tab();
1196
1197 $this->end_controls_tabs();
1198
1199 $this->end_controls_section();
1200 }
1201
1202 /**
1203 * Register fade style controls.
1204 *
1205 * @return void
1206 */
1207 public function register_style_fade_controls(): void
1208 {
1209 $this->start_controls_section(
1210 'kng_fade_style_section',
1211 [
1212 'label' => KING_ADDONS_ELEMENTOR_ICON . esc_html__('Fade Overlay', 'king-addons'),
1213 'tab' => Controls_Manager::TAB_STYLE,
1214 'condition' => [
1215 'kng_fade_enable' => 'yes',
1216 ],
1217 ]
1218 );
1219
1220 $this->add_control(
1221 'kng_fade_color',
1222 [
1223 'label' => esc_html__('Fade Color', 'king-addons'),
1224 'type' => Controls_Manager::COLOR,
1225 'default' => 'rgba(0, 0, 0, 0.2)',
1226 'selectors' => [
1227 '{{WRAPPER}} .king-addons-unfold__fade' => '--ka-unfold-fade-color: {{VALUE}};',
1228 ],
1229 ]
1230 );
1231
1232 $this->end_controls_section();
1233 }
1234
1235 /**
1236 * Register pro promo controls.
1237 *
1238 * @return void
1239 */
1240 public function register_pro_notice_controls(): void
1241 {
1242 if (!king_addons_freemius()->can_use_premium_code__premium_only()) {
1243 Core::renderProFeaturesSection(
1244 $this,
1245 '',
1246 Controls_Manager::RAW_HTML,
1247 'unfold',
1248 [
1249 'Use Elementor templates as content source',
1250 'Fixed fold height and inside button placement',
1251 'Separate fold/unfold durations and easing',
1252 'Max-height animation mode and scroll after unfold',
1253 'Custom fade overlay height and behavior',
1254 ]
1255 );
1256 }
1257 }
1258
1259 /**
1260 * Render widget output.
1261 *
1262 * @param bool $is_pro Whether pro features are allowed.
1263 *
1264 * @return void
1265 */
1266 public function render_output(bool $is_pro): void
1267 {
1268 $settings = $this->get_settings_for_display();
1269 $content_id = 'king-addons-unfold-content-' . $this->get_id();
1270 $title_id = 'king-addons-unfold-title-' . $this->get_id();
1271 $initial_state = $settings['kng_initial_state'] ?? 'folded';
1272 $has_button = ($settings['kng_button_enable'] ?? 'yes') === 'yes';
1273 $has_title = ($settings['kng_title_enable'] ?? '') === 'yes' && !empty($settings['kng_title']);
1274
1275 $fold_unit = $settings['kng_fold_height_unit'] ?? 'percent';
1276 if (!$is_pro && 'px' === $fold_unit) {
1277 $fold_unit = 'percent';
1278 }
1279
1280 $fold_height = $this->get_fold_height_values($settings, $fold_unit);
1281 if (!$is_pro && 'px' === $fold_unit) {
1282 $fold_height = $this->get_fold_height_values($settings, 'percent');
1283 }
1284
1285 $fade_height = $is_pro ? (float) ($settings['kng_fade_height']['size'] ?? 30) : 30;
1286 $fade_only_folded = ($settings['kng_fade_only_folded'] ?? 'yes') === 'yes';
1287 $fade_enabled = ($settings['kng_fade_enable'] ?? 'yes') === 'yes';
1288
1289 $shared_duration = $this->resolve_duration(
1290 $settings['kng_shared_duration'] ?? 'normal',
1291 (float) ($settings['kng_shared_duration_custom'] ?? 0.5),
1292 0.5
1293 );
1294
1295 $fold_duration = $shared_duration;
1296 $unfold_duration = $shared_duration;
1297 if ($is_pro) {
1298 $fold_duration = $this->resolve_duration(
1299 $settings['kng_fold_duration_mode'] ?? 'shared',
1300 (float) ($settings['kng_fold_duration_custom'] ?? 0.5),
1301 $shared_duration
1302 );
1303 $unfold_duration = $this->resolve_duration(
1304 $settings['kng_unfold_duration_mode'] ?? 'shared',
1305 (float) ($settings['kng_unfold_duration_custom'] ?? 0.5),
1306 $shared_duration
1307 );
1308 }
1309
1310 $shared_easing = $settings['kng_shared_easing'] ?? 'ease';
1311 $fold_easing = $is_pro ? ($settings['kng_fold_easing'] ?? 'shared') : 'shared';
1312 $unfold_easing = $is_pro ? ($settings['kng_unfold_easing'] ?? 'shared') : 'shared';
1313
1314 if ('shared' === $fold_easing) {
1315 $fold_easing = $shared_easing;
1316 }
1317 if ('shared' === $unfold_easing) {
1318 $unfold_easing = $shared_easing;
1319 }
1320
1321 $animate_type = $is_pro ? ($settings['kng_animate_height_type'] ?? 'auto-to-fixed') : 'auto-to-fixed';
1322 $button_position = $is_pro ? ($settings['kng_button_position'] ?? 'outside') : 'outside';
1323 $scroll_after_unfold = $is_pro && ($settings['kng_scroll_after_unfold'] ?? '') === 'yes';
1324 $scroll_offset = (int) ($settings['kng_scroll_offset']['size'] ?? 0);
1325
1326 $button_alignment_class = $this->get_button_alignment_class($settings);
1327
1328 $wrapper_classes = [
1329 'king-addons-unfold',
1330 'folded' === $initial_state ? 'king-addons-unfold--folded' : 'king-addons-unfold--unfolded',
1331 $fade_enabled ? 'king-addons-unfold--fade' : 'king-addons-unfold--no-fade',
1332 $has_button ? 'king-addons-unfold--has-button' : 'king-addons-unfold--no-button',
1333 'inside' === $button_position ? 'king-addons-unfold--button-inside' : 'king-addons-unfold--button-outside',
1334 $button_alignment_class,
1335 ];
1336
1337 $data_attributes = $this->build_wrapper_data_attributes(
1338 $fold_unit,
1339 $fold_height,
1340 $initial_state,
1341 $fade_height,
1342 $fade_only_folded,
1343 $fold_duration,
1344 $unfold_duration,
1345 $fold_easing,
1346 $unfold_easing,
1347 $animate_type,
1348 $scroll_after_unfold,
1349 $scroll_offset
1350 );
1351
1352 $button_data = $this->build_button_data_attributes($settings, $is_pro);
1353
1354 ?>
1355 <div class="<?php echo esc_attr(implode(' ', array_filter($wrapper_classes))); ?>" <?php echo $data_attributes; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped ?>>
1356 <div class="king-addons-unfold__box">
1357 <?php $this->render_title($settings, $title_id); ?>
1358 <div
1359 class="king-addons-unfold__content"
1360 id="<?php echo esc_attr($content_id); ?>"
1361 role="region"
1362 <?php if ($has_title) : ?>
1363 aria-labelledby="<?php echo esc_attr($title_id); ?>"
1364 <?php endif; ?>
1365 aria-hidden="<?php echo 'folded' === $initial_state ? 'true' : 'false'; ?>"
1366 data-fold-height-desktop="<?php echo esc_attr($fold_height['desktop']); ?>"
1367 data-fold-height-tablet="<?php echo esc_attr($fold_height['tablet']); ?>"
1368 data-fold-height-mobile="<?php echo esc_attr($fold_height['mobile']); ?>"
1369 >
1370 <?php $this->render_inner_content($settings, $is_pro); ?>
1371 </div>
1372
1373 <?php if ($fade_enabled) : ?>
1374 <div class="king-addons-unfold__fade" aria-hidden="true"></div>
1375 <?php endif; ?>
1376
1377 <?php if ($has_button && 'inside' === $button_position) : ?>
1378 <?php $this->render_button($settings, $content_id, $button_data, 'inside'); ?>
1379 <?php endif; ?>
1380 </div>
1381
1382 <?php if ($has_button && 'outside' === $button_position) : ?>
1383 <?php $this->render_button($settings, $content_id, $button_data, 'outside'); ?>
1384 <?php endif; ?>
1385 </div>
1386 <?php
1387 }
1388
1389 /**
1390 * Render title if enabled.
1391 *
1392 * @param array<string, mixed> $settings Widget settings.
1393 * @param string $title_id Title element id.
1394 *
1395 * @return void
1396 */
1397 public function render_title(array $settings, string $title_id): void
1398 {
1399 if (($settings['kng_title_enable'] ?? '') !== 'yes' || empty($settings['kng_title'])) {
1400 return;
1401 }
1402
1403 $tag = $settings['kng_title_tag'] ?? 'h3';
1404 $title = $settings['kng_title'];
1405
1406 printf(
1407 '<%1$s class="king-addons-unfold__title" id="%2$s">%3$s</%1$s>',
1408 esc_attr($tag),
1409 esc_attr($title_id),
1410 esc_html($title)
1411 );
1412 }
1413
1414 /**
1415 * Render inner content.
1416 *
1417 * @param array<string, mixed> $settings Widget settings.
1418 * @param bool $is_pro Whether pro features are allowed.
1419 *
1420 * @return void
1421 */
1422 public function render_inner_content(array $settings, bool $is_pro): void
1423 {
1424 $content_source = $settings['kng_content_source'] ?? 'editor';
1425 if (!$is_pro) {
1426 $content_source = 'editor';
1427 }
1428
1429 if ('template' === $content_source && !empty($settings['kng_template_id'])) {
1430 echo $this->get_template_content((int) $settings['kng_template_id']); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
1431 return;
1432 }
1433
1434 if (!empty($settings['kng_editor_content'])) {
1435 echo wp_kses_post($settings['kng_editor_content']);
1436 }
1437 }
1438
1439 /**
1440 * Render toggle button.
1441 *
1442 * @param array<string, mixed> $settings Widget settings.
1443 * @param string $content_id Target content id.
1444 * @param array<string, mixed> $button_data Button data attributes.
1445 * @param string $position Button position.
1446 *
1447 * @return void
1448 */
1449 public function render_button(array $settings, string $content_id, array $button_data, string $position): void
1450 {
1451 $icon_enable = ($settings['kng_icon_enable'] ?? '') === 'yes';
1452 $button_size = $settings['kng_button_size'] ?? 'md';
1453 $icon_position = $settings['kng_icon_position'] ?? 'before';
1454 $is_unfolded_initial = ($settings['kng_initial_state'] ?? 'folded') === 'unfolded';
1455 $hover_animation = $settings['kng_button_hover_animation'] ?? 'none';
1456
1457 $wrapper_classes = [
1458 'king-addons-unfold__button-wrapper',
1459 'king-addons-unfold__button-wrapper--' . $position,
1460 ];
1461
1462 $button_classes = [
1463 'king-addons-unfold__button',
1464 'king-addons-unfold__button--' . $button_size,
1465 'king-addons-unfold__button--icon-' . $icon_position,
1466 'king-addons-unfold__button--hover-' . $hover_animation,
1467 ];
1468
1469 $icon_before = 'before' === $icon_position;
1470
1471 ?>
1472 <div class="<?php echo esc_attr(implode(' ', $wrapper_classes)); ?>">
1473 <button
1474 type="button"
1475 class="<?php echo esc_attr(implode(' ', $button_classes)); ?>"
1476 aria-expanded="<?php echo $is_unfolded_initial ? 'true' : 'false'; ?>"
1477 aria-controls="<?php echo esc_attr($content_id); ?>"
1478 <?php echo $this->format_data_attributes($button_data); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped ?>
1479 >
1480 <?php if ($icon_enable && $icon_before) : ?>
1481 <?php $this->render_icons($settings, $is_unfolded_initial); ?>
1482 <?php endif; ?>
1483
1484 <span class="king-addons-unfold__text">
1485 <?php echo esc_html($is_unfolded_initial ? ($settings['kng_fold_text'] ?? '') : ($settings['kng_unfold_text'] ?? '')); ?>
1486 </span>
1487
1488 <?php if ($icon_enable && !$icon_before) : ?>
1489 <?php $this->render_icons($settings, $is_unfolded_initial); ?>
1490 <?php endif; ?>
1491 </button>
1492 </div>
1493 <?php
1494 }
1495
1496 /**
1497 * Render icon markup for both states.
1498 *
1499 * @param array<string, mixed> $settings Widget settings.
1500 * @param bool $is_unfolded_state Whether initial state is unfolded.
1501 *
1502 * @return void
1503 */
1504 public function render_icons(array $settings, bool $is_unfolded_state): void
1505 {
1506 $unfold_icon = $settings['kng_unfold_icon'] ?? null;
1507 $fold_icon = $settings['kng_fold_icon'] ?? null;
1508
1509 echo '<span class="king-addons-unfold__icon king-addons-unfold__icon--unfold" aria-hidden="' . ($is_unfolded_state ? 'true' : 'false') . '">';
1510 if (!empty($unfold_icon['value'])) {
1511 Icons_Manager::render_icon($unfold_icon);
1512 }
1513 echo '</span>';
1514
1515 echo '<span class="king-addons-unfold__icon king-addons-unfold__icon--fold" aria-hidden="' . ($is_unfolded_state ? 'false' : 'true') . '">';
1516 if (!empty($fold_icon['value'])) {
1517 Icons_Manager::render_icon($fold_icon);
1518 }
1519 echo '</span>';
1520 }
1521
1522 /**
1523 * Build wrapper data attributes string.
1524 *
1525 * @param string $fold_unit Fold unit.
1526 * @param array<string, float> $fold_height Fold height values.
1527 * @param string $initial_state Initial state.
1528 * @param float $fade_height Fade height.
1529 * @param bool $fade_only_folded Fade only when folded.
1530 * @param float $fold_duration Fold duration.
1531 * @param float $unfold_duration Unfold duration.
1532 * @param string $fold_easing Fold easing.
1533 * @param string $unfold_easing Unfold easing.
1534 * @param string $animate_type Animation type.
1535 * @param bool $scroll_after Scroll after unfold.
1536 * @param int $scroll_offset Scroll offset.
1537 *
1538 * @return string
1539 */
1540 public function build_wrapper_data_attributes(
1541 string $fold_unit,
1542 array $fold_height,
1543 string $initial_state,
1544 float $fade_height,
1545 bool $fade_only_folded,
1546 float $fold_duration,
1547 float $unfold_duration,
1548 string $fold_easing,
1549 string $unfold_easing,
1550 string $animate_type,
1551 bool $scroll_after,
1552 int $scroll_offset
1553 ): string {
1554 $attributes = [
1555 'data-fold-unit' => $fold_unit,
1556 'data-initial-state' => $initial_state,
1557 'data-fade-height' => $fade_height,
1558 'data-fade-only-folded' => $fade_only_folded ? 'true' : 'false',
1559 'data-fold-duration' => $fold_duration,
1560 'data-unfold-duration' => $unfold_duration,
1561 'data-fold-easing' => $fold_easing,
1562 'data-unfold-easing' => $unfold_easing,
1563 'data-animate-type' => $animate_type,
1564 'data-scroll-after' => $scroll_after ? 'true' : 'false',
1565 'data-scroll-offset' => $scroll_offset,
1566 ];
1567
1568 foreach ($attributes as $key => $value) {
1569 $attributes[$key] = $key . '="' . esc_attr((string) $value) . '"';
1570 }
1571
1572 $heights = [
1573 'data-fold-height-desktop' => $fold_height['desktop'],
1574 'data-fold-height-tablet' => $fold_height['tablet'],
1575 'data-fold-height-mobile' => $fold_height['mobile'],
1576 ];
1577
1578 foreach ($heights as $key => $value) {
1579 $heights[$key] = $key . '="' . esc_attr((string) $value) . '"';
1580 }
1581
1582 return implode(' ', array_merge($attributes, $heights));
1583 }
1584
1585 /**
1586 * Build button data attributes.
1587 *
1588 * @param array<string, mixed> $settings Widget settings.
1589 * @param bool $is_pro Whether pro features are available.
1590 *
1591 * @return array<string, string>
1592 */
1593 public function build_button_data_attributes(array $settings, bool $is_pro): array
1594 {
1595 $button_position = $is_pro ? ($settings['kng_button_position'] ?? 'outside') : 'outside';
1596 $data = [
1597 'data-unfold-text' => $settings['kng_unfold_text'] ?? '',
1598 'data-fold-text' => $settings['kng_fold_text'] ?? '',
1599 'data-icon-position' => $settings['kng_icon_position'] ?? 'before',
1600 'data-button-position' => $button_position,
1601 ];
1602
1603 return $data;
1604 }
1605
1606 /**
1607 * Format data attributes for HTML output.
1608 *
1609 * @param array<string, mixed> $attributes Attributes.
1610 *
1611 * @return string
1612 */
1613 public function format_data_attributes(array $attributes): string
1614 {
1615 $formatted = [];
1616 foreach ($attributes as $key => $value) {
1617 $formatted[] = $key . '="' . esc_attr((string) $value) . '"';
1618 }
1619 return implode(' ', $formatted);
1620 }
1621
1622 /**
1623 * Get fold height values for devices.
1624 *
1625 * @param array<string, mixed> $settings Widget settings.
1626 * @param string $unit Unit type.
1627 *
1628 * @return array<string, float>
1629 */
1630 public function get_fold_height_values(array $settings, string $unit): array
1631 {
1632 $key = 'percent' === $unit ? 'kng_fold_height_percent' : 'kng_fold_height_px';
1633
1634 $desktop = isset($settings[$key]['size']) ? (float) $settings[$key]['size'] : ('percent' === $unit ? 60.0 : 320.0);
1635 $tablet = isset($settings[$key . '_tablet']['size']) ? (float) $settings[$key . '_tablet']['size'] : $desktop;
1636 $mobile = isset($settings[$key . '_mobile']['size']) ? (float) $settings[$key . '_mobile']['size'] : $tablet;
1637
1638 return [
1639 'desktop' => $desktop,
1640 'tablet' => $tablet,
1641 'mobile' => $mobile,
1642 ];
1643 }
1644
1645 /**
1646 * Resolve duration based on preset.
1647 *
1648 * @param string $preset Preset.
1649 * @param float $custom_value Custom value.
1650 * @param float $shared_fallback Fallback value.
1651 *
1652 * @return float
1653 */
1654 public function resolve_duration(string $preset, float $custom_value, float $shared_fallback): float
1655 {
1656 switch ($preset) {
1657 case 'fast':
1658 return 0.3;
1659 case 'normal':
1660 return 0.5;
1661 case 'slow':
1662 return 0.8;
1663 case 'custom':
1664 return max(0.05, $custom_value);
1665 case 'shared':
1666 default:
1667 return $shared_fallback;
1668 }
1669 }
1670
1671 /**
1672 * Get Elementor template content.
1673 *
1674 * @param int $template_id Template id.
1675 *
1676 * @return string
1677 */
1678 public function get_template_content(int $template_id): string
1679 {
1680 if (empty($template_id)) {
1681 return '';
1682 }
1683
1684 $has_css = 'internal' === get_option('elementor_css_print_method');
1685
1686 return Plugin::instance()->frontend->get_builder_content_for_display($template_id, $has_css);
1687 }
1688
1689 /**
1690 * Get Elementor templates options.
1691 *
1692 * @return array<string, string>
1693 */
1694 public function get_elementor_templates_options(): array
1695 {
1696 $options = [];
1697 $templates = Plugin::$instance->templates_manager->get_source('local')->get_items();
1698
1699 if (!empty($templates)) {
1700 foreach ($templates as $template) {
1701 $options[$template['template_id']] = $template['title'];
1702 }
1703 }
1704
1705 return $options;
1706 }
1707
1708 /**
1709 * Get button alignment helper class.
1710 *
1711 * @param array<string, mixed> $settings Widget settings.
1712 *
1713 * @return string
1714 */
1715 public function get_button_alignment_class(array $settings): string
1716 {
1717 $alignment = $settings['kng_button_alignment'] ?? 'center';
1718 return 'king-addons-unfold--align-' . $alignment;
1719 }
1720 }
1721
1722
1723
1724
1725
1726