PluginProbe
King Addons for Elementor – 80+ Elementor Widgets, 4 000+ Elementor Templates, WooCommerce, Mega Menu, Popup Builder / 51.1.65
King Addons for Elementor – 80+ Elementor Widgets, 4 000+ Elementor Templates, WooCommerce, Mega Menu, Popup Builder v51.1.65
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.65, at includes/widgets/Unfold/Unfold.php

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