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 / Quick_Card_Slider / Quick_Card_Slider.php

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

1,947 lines 63.7 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * Quick Card Slider Widget (Free)
4 *
5 * @package King_Addons
6 */
7
8 namespace King_Addons;
9
10 use Elementor\Controls_Manager;
11 use Elementor\Group_Control_Border;
12 use Elementor\Group_Control_Box_Shadow;
13 use Elementor\Group_Control_Image_Size;
14 use Elementor\Group_Control_Typography;
15 use Elementor\Repeater;
16 use Elementor\Utils;
17 use Elementor\Widget_Base;
18
19 if (!defined('ABSPATH')) {
20 exit;
21 }
22
23 /**
24 * Renders the Quick Card Slider widget for the free version.
25 */
26 class Quick_Card_Slider extends Widget_Base
27 {
28 /**
29 * Get widget slug.
30 *
31 * @return string
32 */
33 public function get_name(): string
34 {
35 return 'king-addons-quick-card-slider';
36 }
37
38 /**
39 * Get widget title.
40 *
41 * @return string
42 */
43 public function get_title(): string
44 {
45 return esc_html__('Quick Card Slider', 'king-addons');
46 }
47
48 /**
49 * Get widget icon CSS classes.
50 *
51 * @return string
52 */
53 public function get_icon(): string
54 {
55 return 'king-addons-icon king-addons-card-slider';
56 }
57
58 /**
59 * Get script dependencies.
60 *
61 * @return array<string>
62 */
63 public function get_script_depends(): array
64 {
65 return [
66 KING_ADDONS_ASSETS_UNIQUE_KEY . '-swiper-swiper',
67 KING_ADDONS_ASSETS_UNIQUE_KEY . '-quick-card-slider-script',
68 ];
69 }
70
71 /**
72 * Get style dependencies.
73 *
74 * @return array<string>
75 */
76 public function get_style_depends(): array
77 {
78 return [
79 KING_ADDONS_ASSETS_UNIQUE_KEY . '-swiper-swiper',
80 KING_ADDONS_ASSETS_UNIQUE_KEY . '-quick-card-slider-style',
81 ];
82 }
83
84 /**
85 * Get widget categories.
86 *
87 * @return array<string>
88 */
89 public function get_categories(): array
90 {
91 return ['king-addons'];
92 }
93
94 /**
95 * Get widget keywords.
96 *
97 * @return array<string>
98 */
99 public function get_keywords(): array
100 {
101 return ['slider', 'card', 'carousel', 'content', 'king-addons'];
102 }
103
104 public function get_custom_help_url()
105 {
106 return 'mailto:bug@kingaddons.com?subject=Bug Report - King Addons&body=Please describe the issue';
107 }
108
109 /**
110 * Register widget controls.
111 *
112 * @return void
113 */
114 public function register_controls(): void
115 {
116 $this->register_content_controls();
117 $this->register_slider_controls();
118 $this->register_navigation_controls();
119 $this->register_pagination_controls();
120 $this->register_style_card_controls();
121 $this->register_style_typography_controls();
122 $this->register_style_button_controls();
123 $this->register_style_navigation_controls();
124 $this->register_style_pagination_controls();
125 $this->register_pro_notice_controls();
126 }
127
128 /**
129 * Render widget output on the frontend.
130 *
131 * @return void
132 */
133 public function render(): void
134 {
135 $settings = $this->get_settings_for_display();
136 $this->render_output($settings);
137 }
138
139 /**
140 * Render widget output using provided settings.
141 *
142 * @param array<string, mixed> $settings Widget settings.
143 *
144 * @return void
145 */
146 public function render_output(array $settings): void
147 {
148 $cards = $settings['kng_cards'] ?? [];
149
150 if (empty($cards)) {
151 return;
152 }
153
154 $wrapper_classes = $this->get_wrapper_classes($settings);
155 $wrapper_styles = $this->get_wrapper_style_attributes($settings);
156
157 $data_attributes = $this->get_slider_data_attributes($settings);
158
159 $show_navigation = $settings['kng_show_navigation'] === 'yes';
160 $show_pagination = $settings['kng_show_pagination'] === 'yes';
161
162 ?>
163 <div class="<?php echo esc_attr(implode(' ', $wrapper_classes)); ?>"<?php echo $wrapper_styles; ?>>
164 <div class="king-addons-card-slider__track swiper" <?php echo $data_attributes; ?>>
165 <div class="king-addons-card-slider__wrapper swiper-wrapper">
166 <?php foreach ($cards as $card) : ?>
167 <?php $this->render_slide($card); ?>
168 <?php endforeach; ?>
169 </div>
170 <?php if ($show_pagination) : ?>
171 <div class="king-addons-card-slider__pagination swiper-pagination" aria-label="<?php echo esc_attr__('Slider pagination', 'king-addons'); ?>"></div>
172 <?php endif; ?>
173 </div>
174 <?php if ($show_navigation) : ?>
175 <div class="king-addons-card-slider__navigation" aria-label="<?php echo esc_attr__('Slider navigation', 'king-addons'); ?>">
176 <button type="button" class="king-addons-card-slider__arrow king-addons-card-slider__arrow--prev swiper-button-prev" aria-label="<?php echo esc_attr__('Previous slide', 'king-addons'); ?>">
177 <span class="king-addons-card-slider__arrow-icon" aria-hidden="true"></span>
178 </button>
179 <button type="button" class="king-addons-card-slider__arrow king-addons-card-slider__arrow--next swiper-button-next" aria-label="<?php echo esc_attr__('Next slide', 'king-addons'); ?>">
180 <span class="king-addons-card-slider__arrow-icon" aria-hidden="true"></span>
181 </button>
182 </div>
183 <?php endif; ?>
184 </div>
185 <?php
186 }
187
188 /**
189 * Register content controls for cards.
190 *
191 * @return void
192 */
193 public function register_content_controls(): void
194 {
195 $this->start_controls_section(
196 'kng_content_section',
197 [
198 'label' => KING_ADDONS_ELEMENTOR_ICON . esc_html__('Cards', 'king-addons'),
199 'tab' => Controls_Manager::TAB_CONTENT,
200 ]
201 );
202
203 $repeater = new Repeater();
204
205 $repeater->add_control(
206 'kng_card_image',
207 [
208 'label' => esc_html__('Image', 'king-addons'),
209 'type' => Controls_Manager::MEDIA,
210 'default' => [
211 'url' => Utils::get_placeholder_image_src(),
212 ],
213 ]
214 );
215
216 $repeater->add_control(
217 'kng_card_title',
218 [
219 'label' => esc_html__('Title', 'king-addons'),
220 'type' => Controls_Manager::TEXT,
221 'default' => esc_html__('Feature highlight', 'king-addons'),
222 'label_block' => true,
223 ]
224 );
225
226 $repeater->add_control(
227 'kng_card_description',
228 [
229 'label' => esc_html__('Description', 'king-addons'),
230 'type' => Controls_Manager::TEXTAREA,
231 'rows' => 3,
232 'default' => esc_html__('Share a concise value statement for this card.', 'king-addons'),
233 ]
234 );
235
236 $repeater->add_control(
237 'kng_card_button_text',
238 [
239 'label' => esc_html__('Button Text', 'king-addons'),
240 'type' => Controls_Manager::TEXT,
241 'default' => esc_html__('Learn more', 'king-addons'),
242 'label_block' => true,
243 ]
244 );
245
246 $repeater->add_control(
247 'kng_card_button_link',
248 [
249 'label' => esc_html__('Button Link', 'king-addons'),
250 'type' => Controls_Manager::URL,
251 'placeholder' => esc_html__('https://your-link.com', 'king-addons'),
252 ]
253 );
254
255 $repeater->add_control(
256 'kng_card_link_enable',
257 [
258 'label' => esc_html__('Make Whole Card Clickable', 'king-addons'),
259 'type' => Controls_Manager::SWITCHER,
260 'label_on' => esc_html__('Yes', 'king-addons'),
261 'label_off' => esc_html__('No', 'king-addons'),
262 'return_value' => 'yes',
263 'description' => esc_html__('Editor safety: the card link is disabled in the Elementor editor to prevent accidental navigation.', 'king-addons'),
264 ]
265 );
266
267 $repeater->add_control(
268 'kng_card_link',
269 [
270 'label' => esc_html__('Card Link', 'king-addons'),
271 'type' => Controls_Manager::URL,
272 'placeholder' => esc_html__('https://your-link.com', 'king-addons'),
273 'condition' => [
274 'kng_card_link_enable' => 'yes',
275 ],
276 ]
277 );
278
279 // Pro-only badges: show a disabled switcher hint in free.
280 $repeater->add_control(
281 'kng_card_badge_pro_notice',
282 [
283 'label' => sprintf(__('Card Badge %s', 'king-addons'), '<i class="eicon-pro-icon"></i>'),
284 'type' => Controls_Manager::SWITCHER,
285 'classes' => 'king-addons-pro-control no-distance',
286 ]
287 );
288
289 $this->add_group_control(
290 Group_Control_Image_Size::get_type(),
291 [
292 'name' => 'kng_card_image',
293 'default' => 'medium',
294 'separator' => 'before',
295 ]
296 );
297
298 $this->add_control(
299 'kng_cards',
300 [
301 'label' => esc_html__('Cards', 'king-addons'),
302 'type' => Controls_Manager::REPEATER,
303 'fields' => $repeater->get_controls(),
304 'default' => $this->get_default_cards(),
305 'title_field' => '{{ kng_card_title }}',
306 ]
307 );
308
309 $this->end_controls_section();
310 }
311
312 /**
313 * Register slider behavior controls.
314 *
315 * @return void
316 */
317 public function register_slider_controls(): void
318 {
319 $this->start_controls_section(
320 'kng_slider_section',
321 [
322 'label' => KING_ADDONS_ELEMENTOR_ICON . esc_html__('Slider Settings', 'king-addons'),
323 'tab' => Controls_Manager::TAB_CONTENT,
324 ]
325 );
326
327 $this->add_control(
328 'kng_slides_per_view',
329 [
330 'label' => esc_html__('Slides Per View', 'king-addons'),
331 'type' => Controls_Manager::NUMBER,
332 'min' => 1,
333 'max' => 6,
334 'step' => 1,
335 'default' => 3,
336 ]
337 );
338
339 $this->add_control(
340 'kng_slides_per_view_tablet',
341 [
342 'label' => esc_html__('Slides Per View (Tablet)', 'king-addons'),
343 'type' => Controls_Manager::NUMBER,
344 'min' => 1,
345 'max' => 6,
346 'step' => 1,
347 'default' => 2,
348 ]
349 );
350
351 $this->add_control(
352 'kng_slides_per_view_mobile',
353 [
354 'label' => esc_html__('Slides Per View (Mobile)', 'king-addons'),
355 'type' => Controls_Manager::NUMBER,
356 'min' => 1,
357 'max' => 6,
358 'step' => 1,
359 'default' => 1,
360 ]
361 );
362
363 $this->add_control(
364 'kng_space_between',
365 [
366 'label' => esc_html__('Space Between (px)', 'king-addons'),
367 'type' => Controls_Manager::SLIDER,
368 'size_units' => ['px'],
369 'range' => [
370 'px' => [
371 'min' => 0,
372 'max' => 80,
373 ],
374 ],
375 'default' => [
376 'size' => 20,
377 'unit' => 'px',
378 ],
379 ]
380 );
381
382 $this->add_control(
383 'kng_loop',
384 [
385 'label' => esc_html__('Loop', 'king-addons'),
386 'type' => Controls_Manager::SWITCHER,
387 'label_on' => esc_html__('Yes', 'king-addons'),
388 'label_off' => esc_html__('No', 'king-addons'),
389 'return_value' => 'yes',
390 'default' => 'yes',
391 ]
392 );
393
394 $this->add_control(
395 'kng_autoplay',
396 [
397 'label' => esc_html__('Autoplay', 'king-addons'),
398 'type' => Controls_Manager::SWITCHER,
399 'label_on' => esc_html__('Yes', 'king-addons'),
400 'label_off' => esc_html__('No', 'king-addons'),
401 'return_value' => 'yes',
402 'default' => 'yes',
403 ]
404 );
405
406 $this->add_control(
407 'kng_autoplay_delay',
408 [
409 'label' => esc_html__('Autoplay Delay (ms)', 'king-addons'),
410 'type' => Controls_Manager::NUMBER,
411 'min' => 100,
412 'step' => 100,
413 'default' => 3200,
414 'condition' => [
415 'kng_autoplay' => 'yes',
416 ],
417 ]
418 );
419
420 $this->add_control(
421 'kng_speed',
422 [
423 'label' => esc_html__('Transition Speed (ms)', 'king-addons'),
424 'type' => Controls_Manager::NUMBER,
425 'min' => 100,
426 'step' => 50,
427 'default' => 600,
428 ]
429 );
430
431 $this->end_controls_section();
432 }
433
434 /**
435 * Register navigation controls (layout and placement).
436 *
437 * @return void
438 */
439 public function register_navigation_controls(): void
440 {
441 $this->start_controls_section(
442 'kng_navigation_section',
443 [
444 'label' => KING_ADDONS_ELEMENTOR_ICON . esc_html__('Navigation', 'king-addons'),
445 'tab' => Controls_Manager::TAB_CONTENT,
446 ]
447 );
448
449 $this->add_control(
450 'kng_show_navigation',
451 [
452 'label' => esc_html__('Show Arrows', 'king-addons'),
453 'type' => Controls_Manager::SWITCHER,
454 'return_value' => 'yes',
455 'default' => 'yes',
456 ]
457 );
458
459 $this->add_pro_navigation_controls();
460
461 $this->add_control(
462 'kng_navigation_position',
463 [
464 'label' => esc_html__('Position', 'king-addons'),
465 'type' => Controls_Manager::SELECT,
466 'default' => 'outside',
467 'options' => [
468 'outside' => esc_html__('Outside', 'king-addons'),
469 'inside' => esc_html__('Inside', 'king-addons'),
470 ],
471 'condition' => [
472 'kng_show_navigation' => 'yes',
473 ],
474 ]
475 );
476
477 $this->add_control(
478 'kng_navigation_alignment',
479 [
480 'label' => esc_html__('Alignment', 'king-addons'),
481 'type' => Controls_Manager::CHOOSE,
482 'options' => [
483 'flex-start' => [
484 'title' => esc_html__('Start', 'king-addons'),
485 'icon' => 'eicon-h-align-left',
486 ],
487 'center' => [
488 'title' => esc_html__('Center', 'king-addons'),
489 'icon' => 'eicon-h-align-center',
490 ],
491 'flex-end' => [
492 'title' => esc_html__('End', 'king-addons'),
493 'icon' => 'eicon-h-align-right',
494 ],
495 ],
496 'toggle' => false,
497 'default' => 'center',
498 'condition' => [
499 'kng_show_navigation' => 'yes',
500 ],
501 ]
502 );
503
504 $this->add_responsive_control(
505 'kng_navigation_offset',
506 [
507 'label' => esc_html__('Offset', 'king-addons'),
508 'type' => Controls_Manager::SLIDER,
509 'size_units' => ['px'],
510 'range' => [
511 'px' => [
512 'min' => 0,
513 'max' => 80,
514 ],
515 ],
516 'default' => [
517 'size' => 25,
518 'unit' => 'px',
519 ],
520 'condition' => [
521 'kng_show_navigation' => 'yes',
522 ],
523 'selectors' => [
524 '{{WRAPPER}} .king-addons-card-slider' => '--kng-card-slider-nav-offset: {{SIZE}}{{UNIT}};',
525 ],
526 ]
527 );
528
529 $this->add_control(
530 'kng_navigation_hide_tablet',
531 [
532 'label' => esc_html__('Hide on Tablet', 'king-addons'),
533 'type' => Controls_Manager::SWITCHER,
534 'label_on' => esc_html__('Yes', 'king-addons'),
535 'label_off' => esc_html__('No', 'king-addons'),
536 'return_value' => 'yes',
537 'condition' => [
538 'kng_show_navigation' => 'yes',
539 ],
540 ]
541 );
542
543 $this->add_control(
544 'kng_navigation_hide_mobile',
545 [
546 'label' => esc_html__('Hide on Mobile', 'king-addons'),
547 'type' => Controls_Manager::SWITCHER,
548 'label_on' => esc_html__('Yes', 'king-addons'),
549 'label_off' => esc_html__('No', 'king-addons'),
550 'return_value' => 'yes',
551 'condition' => [
552 'kng_show_navigation' => 'yes',
553 ],
554 ]
555 );
556
557 $this->add_control(
558 'kng_navigation_inside_padding',
559 [
560 'label' => esc_html__('Inside Padding', 'king-addons'),
561 'type' => Controls_Manager::SLIDER,
562 'size_units' => ['px'],
563 'range' => [
564 'px' => [
565 'min' => 0,
566 'max' => 80,
567 ],
568 ],
569 'default' => [
570 'size' => 12,
571 'unit' => 'px',
572 ],
573 'condition' => [
574 'kng_show_navigation' => 'yes',
575 'kng_navigation_position' => 'inside',
576 ],
577 'selectors' => [
578 '{{WRAPPER}} .king-addons-card-slider' => '--kng-card-slider-nav-padding: {{SIZE}}{{UNIT}};',
579 ],
580 ]
581 );
582
583 $this->add_control(
584 'kng_navigation_gap',
585 [
586 'label' => esc_html__('Arrows Gap', 'king-addons'),
587 'type' => Controls_Manager::SLIDER,
588 'size_units' => ['px'],
589 'range' => [
590 'px' => [
591 'min' => 4,
592 'max' => 80,
593 ],
594 ],
595 'default' => [
596 'size' => 12,
597 'unit' => 'px',
598 ],
599 'condition' => [
600 'kng_show_navigation' => 'yes',
601 ],
602 'selectors' => [
603 '{{WRAPPER}} .king-addons-card-slider' => '--kng-card-slider-nav-gap: {{SIZE}}{{UNIT}};',
604 ],
605 ]
606 );
607
608 $this->end_controls_section();
609 }
610
611 /**
612 * Register pagination controls (layout and placement).
613 *
614 * @return void
615 */
616 public function register_pagination_controls(): void
617 {
618 $this->start_controls_section(
619 'kng_pagination_section',
620 [
621 'label' => KING_ADDONS_ELEMENTOR_ICON . esc_html__('Pagination', 'king-addons'),
622 'tab' => Controls_Manager::TAB_CONTENT,
623 ]
624 );
625
626 $this->add_control(
627 'kng_show_pagination',
628 [
629 'label' => esc_html__('Show Pagination', 'king-addons'),
630 'type' => Controls_Manager::SWITCHER,
631 'return_value' => 'yes',
632 'default' => 'yes',
633 ]
634 );
635
636 $this->add_pro_pagination_controls();
637
638 $this->add_control(
639 'kng_pagination_position',
640 [
641 'label' => esc_html__('Position', 'king-addons'),
642 'type' => Controls_Manager::SELECT,
643 'default' => 'outside',
644 'options' => [
645 'outside' => esc_html__('Outside', 'king-addons'),
646 'inside' => esc_html__('Inside', 'king-addons'),
647 ],
648 'condition' => [
649 'kng_show_pagination' => 'yes',
650 ],
651 ]
652 );
653
654 $this->add_control(
655 'kng_pagination_alignment',
656 [
657 'label' => esc_html__('Alignment', 'king-addons'),
658 'type' => Controls_Manager::CHOOSE,
659 'options' => [
660 'flex-start' => [
661 'title' => esc_html__('Start', 'king-addons'),
662 'icon' => 'eicon-h-align-left',
663 ],
664 'center' => [
665 'title' => esc_html__('Center', 'king-addons'),
666 'icon' => 'eicon-h-align-center',
667 ],
668 'flex-end' => [
669 'title' => esc_html__('End', 'king-addons'),
670 'icon' => 'eicon-h-align-right',
671 ],
672 ],
673 'toggle' => false,
674 'default' => 'center',
675 'condition' => [
676 'kng_show_pagination' => 'yes',
677 ],
678 ]
679 );
680
681 $this->add_responsive_control(
682 'kng_pagination_offset',
683 [
684 'label' => esc_html__('Offset', 'king-addons'),
685 'type' => Controls_Manager::SLIDER,
686 'size_units' => ['px'],
687 'range' => [
688 'px' => [
689 'min' => 0,
690 'max' => 80,
691 ],
692 ],
693 'default' => [
694 'size' => 14,
695 'unit' => 'px',
696 ],
697 'condition' => [
698 'kng_show_pagination' => 'yes',
699 ],
700 'selectors' => [
701 '{{WRAPPER}} .king-addons-card-slider' => '--kng-card-slider-pagination-offset: {{SIZE}}{{UNIT}};',
702 ],
703 ]
704 );
705
706 $this->add_responsive_control(
707 'kng_pagination_gap',
708 [
709 'label' => esc_html__('Dots Gap', 'king-addons'),
710 'type' => Controls_Manager::SLIDER,
711 'size_units' => ['px'],
712 'range' => [
713 'px' => [
714 'min' => 2,
715 'max' => 36,
716 ],
717 ],
718 'default' => [
719 'size' => 10,
720 'unit' => 'px',
721 ],
722 'condition' => [
723 'kng_show_pagination' => 'yes',
724 ],
725 'selectors' => [
726 '{{WRAPPER}} .king-addons-card-slider' => '--kng-card-slider-pagination-gap: {{SIZE}}{{UNIT}};',
727 ],
728 ]
729 );
730
731 $this->end_controls_section();
732 }
733
734 /**
735 * Register card container style controls.
736 *
737 * @return void
738 */
739 public function register_style_card_controls(): void
740 {
741 $this->start_controls_section(
742 'kng_style_card_section',
743 [
744 'label' => KING_ADDONS_ELEMENTOR_ICON . esc_html__('Card', 'king-addons'),
745 'tab' => Controls_Manager::TAB_STYLE,
746 ]
747 );
748
749 $this->add_responsive_control(
750 'kng_track_padding',
751 [
752 'label' => esc_html__('Track Padding', 'king-addons'),
753 'type' => Controls_Manager::DIMENSIONS,
754 'size_units' => ['px', '%', 'em'],
755 'selectors' => [
756 '{{WRAPPER}} .king-addons-card-slider__track' => 'padding: {{TOP}}{{UNIT}} {{RIGHT}}{{UNIT}} {{BOTTOM}}{{UNIT}} {{LEFT}}{{UNIT}};',
757 ],
758 ]
759 );
760
761 $this->add_responsive_control(
762 'kng_card_padding',
763 [
764 'label' => esc_html__('Card Padding', 'king-addons'),
765 'type' => Controls_Manager::DIMENSIONS,
766 'size_units' => ['px', '%', 'em'],
767 'selectors' => [
768 '{{WRAPPER}} .king-addons-card-slider__card' => 'padding: {{TOP}}{{UNIT}} {{RIGHT}}{{UNIT}} {{BOTTOM}}{{UNIT}} {{LEFT}}{{UNIT}};',
769 ],
770 ]
771 );
772
773 $this->add_control(
774 'kng_card_background',
775 [
776 'label' => esc_html__('Background', 'king-addons'),
777 'type' => Controls_Manager::COLOR,
778 'selectors' => [
779 '{{WRAPPER}} .king-addons-card-slider__card' => 'background-color: {{VALUE}};',
780 ],
781 ]
782 );
783
784 $this->add_group_control(
785 Group_Control_Border::get_type(),
786 [
787 'name' => 'kng_card_border',
788 'selector' => '{{WRAPPER}} .king-addons-card-slider__card',
789 ]
790 );
791
792 $this->add_control(
793 'kng_card_radius',
794 [
795 'label' => esc_html__('Border Radius', 'king-addons'),
796 'type' => Controls_Manager::SLIDER,
797 'size_units' => ['px', '%'],
798 'range' => [
799 'px' => [
800 'min' => 0,
801 'max' => 60,
802 ],
803 '%' => [
804 'min' => 0,
805 'max' => 100,
806 ],
807 ],
808 'selectors' => [
809 '{{WRAPPER}} .king-addons-card-slider__card' => 'border-radius: {{SIZE}}{{UNIT}};',
810 ],
811 ]
812 );
813
814 $this->add_group_control(
815 Group_Control_Box_Shadow::get_type(),
816 [
817 'name' => 'kng_card_shadow',
818 'selector' => '{{WRAPPER}} .king-addons-card-slider__card',
819 'render_type' => 'ui',
820 'selector_value' => '{{WRAPPER}} .king-addons-card-slider__card',
821 ]
822 );
823
824 $this->add_group_control(
825 Group_Control_Box_Shadow::get_type(),
826 [
827 'name' => 'kng_card_shadow_hover',
828 'label' => esc_html__('Hover Shadow', 'king-addons'),
829 'selector' => '{{WRAPPER}} .king-addons-card-slider__card:hover, {{WRAPPER}} .king-addons-card-slider__slide-inner:hover .king-addons-card-slider__card',
830 ]
831 );
832
833 $this->add_control(
834 'kng_card_shadow_disable',
835 [
836 'label' => esc_html__('Disable Box Shadow', 'king-addons'),
837 'type' => Controls_Manager::SWITCHER,
838 'label_on' => esc_html__('Yes', 'king-addons'),
839 'label_off' => esc_html__('No', 'king-addons'),
840 'return_value' => 'yes',
841 'default' => '',
842 'selectors' => [
843 '{{WRAPPER}} .king-addons-card-slider__card' => 'box-shadow: none !important;',
844 ],
845 ]
846 );
847
848 $this->add_control(
849 'kng_card_shadow_hover_disable',
850 [
851 'label' => esc_html__('Disable Box Shadow on Hover', 'king-addons'),
852 'type' => Controls_Manager::SWITCHER,
853 'label_on' => esc_html__('Yes', 'king-addons'),
854 'label_off' => esc_html__('No', 'king-addons'),
855 'return_value' => 'yes',
856 'default' => '',
857 'selectors' => [
858 '{{WRAPPER}} .king-addons-card-slider__card:hover, {{WRAPPER}} .king-addons-card-slider__slide-inner:hover .king-addons-card-slider__card' => 'box-shadow: none !important;',
859 ],
860 ]
861 );
862
863 $this->add_responsive_control(
864 'kng_media_radius',
865 [
866 'label' => esc_html__('Image Radius', 'king-addons'),
867 'type' => Controls_Manager::SLIDER,
868 'size_units' => ['px', '%'],
869 'range' => [
870 'px' => ['min' => 0, 'max' => 60],
871 '%' => ['min' => 0, 'max' => 100],
872 ],
873 'selectors' => [
874 '{{WRAPPER}} .king-addons-card-slider__media img' => 'border-radius: {{SIZE}}{{UNIT}};',
875 ],
876 ]
877 );
878
879 $this->add_responsive_control(
880 'kng_media_spacing',
881 [
882 'label' => esc_html__('Image Bottom Spacing', 'king-addons'),
883 'type' => Controls_Manager::SLIDER,
884 'size_units' => ['px'],
885 'range' => [
886 'px' => ['min' => 0, 'max' => 80],
887 ],
888 'selectors' => [
889 '{{WRAPPER}} .king-addons-card-slider__media' => 'margin-bottom: {{SIZE}}{{UNIT}};',
890 ],
891 ]
892 );
893
894 $this->end_controls_section();
895 }
896
897 /**
898 * Register typography and text color style controls.
899 *
900 * @return void
901 */
902 public function register_style_typography_controls(): void
903 {
904 $this->start_controls_section(
905 'kng_style_typography_section',
906 [
907 'label' => KING_ADDONS_ELEMENTOR_ICON . esc_html__('Text', 'king-addons'),
908 'tab' => Controls_Manager::TAB_STYLE,
909 ]
910 );
911
912 $this->add_group_control(
913 Group_Control_Typography::get_type(),
914 [
915 'name' => 'kng_title_typography',
916 'selector' => '{{WRAPPER}} .king-addons-card-slider__title',
917 ]
918 );
919
920 $this->add_control(
921 'kng_title_color',
922 [
923 'label' => esc_html__('Title Color', 'king-addons'),
924 'type' => Controls_Manager::COLOR,
925 'selectors' => [
926 '{{WRAPPER}} .king-addons-card-slider__title' => 'color: {{VALUE}};',
927 ],
928 ]
929 );
930
931 $this->add_group_control(
932 Group_Control_Typography::get_type(),
933 [
934 'name' => 'kng_description_typography',
935 'selector' => '{{WRAPPER}} .king-addons-card-slider__description',
936 ]
937 );
938
939 $this->add_control(
940 'kng_description_color',
941 [
942 'label' => esc_html__('Description Color', 'king-addons'),
943 'type' => Controls_Manager::COLOR,
944 'selectors' => [
945 '{{WRAPPER}} .king-addons-card-slider__description' => 'color: {{VALUE}};',
946 ],
947 ]
948 );
949
950 $this->add_responsive_control(
951 'kng_title_spacing',
952 [
953 'label' => esc_html__('Title Bottom Spacing', 'king-addons'),
954 'type' => Controls_Manager::SLIDER,
955 'size_units' => ['px'],
956 'range' => [
957 'px' => ['min' => 0, 'max' => 60],
958 ],
959 'selectors' => [
960 '{{WRAPPER}} .king-addons-card-slider__title' => 'margin-bottom: {{SIZE}}{{UNIT}};',
961 ],
962 ]
963 );
964
965 $this->add_control(
966 'kng_text_alignment',
967 [
968 'label' => esc_html__('Text Alignment', 'king-addons'),
969 'type' => Controls_Manager::CHOOSE,
970 'options' => [
971 'left' => [
972 'title' => esc_html__('Left', 'king-addons'),
973 'icon' => 'eicon-text-align-left',
974 ],
975 'center' => [
976 'title' => esc_html__('Center', 'king-addons'),
977 'icon' => 'eicon-text-align-center',
978 ],
979 'right' => [
980 'title' => esc_html__('Right', 'king-addons'),
981 'icon' => 'eicon-text-align-right',
982 ],
983 ],
984 'toggle' => false,
985 'default' => 'left',
986 'prefix_class' => 'king-addons-card-slider--text-align-',
987 ]
988 );
989
990 $this->add_responsive_control(
991 'kng_description_spacing',
992 [
993 'label' => esc_html__('Description Bottom Spacing', 'king-addons'),
994 'type' => Controls_Manager::SLIDER,
995 'size_units' => ['px'],
996 'range' => [
997 'px' => ['min' => 0, 'max' => 80],
998 ],
999 'selectors' => [
1000 '{{WRAPPER}} .king-addons-card-slider__description' => 'margin-bottom: {{SIZE}}{{UNIT}};',
1001 ],
1002 ]
1003 );
1004
1005 $this->end_controls_section();
1006 }
1007
1008 /**
1009 * Register button style controls.
1010 *
1011 * @return void
1012 */
1013 public function register_style_button_controls(): void
1014 {
1015 $this->start_controls_section(
1016 'kng_style_button_section',
1017 [
1018 'label' => KING_ADDONS_ELEMENTOR_ICON . esc_html__('Button', 'king-addons'),
1019 'tab' => Controls_Manager::TAB_STYLE,
1020 ]
1021 );
1022
1023 $this->add_control(
1024 'kng_button_alignment',
1025 [
1026 'label' => esc_html__('Button Alignment', 'king-addons'),
1027 'type' => Controls_Manager::CHOOSE,
1028 'options' => [
1029 'left' => [
1030 'title' => esc_html__('Left', 'king-addons'),
1031 'icon' => 'eicon-h-align-left',
1032 ],
1033 'center' => [
1034 'title' => esc_html__('Center', 'king-addons'),
1035 'icon' => 'eicon-h-align-center',
1036 ],
1037 'right' => [
1038 'title' => esc_html__('Right', 'king-addons'),
1039 'icon' => 'eicon-h-align-right',
1040 ],
1041 ],
1042 'toggle' => false,
1043 'default' => 'left',
1044 'prefix_class' => 'king-addons-card-slider--button-align-',
1045 ]
1046 );
1047
1048 $this->add_control(
1049 'kng_button_text_alignment',
1050 [
1051 'label' => esc_html__('Button Text Alignment', 'king-addons'),
1052 'type' => Controls_Manager::CHOOSE,
1053 'options' => [
1054 'left' => [
1055 'title' => esc_html__('Left', 'king-addons'),
1056 'icon' => 'eicon-h-align-left',
1057 ],
1058 'center' => [
1059 'title' => esc_html__('Center', 'king-addons'),
1060 'icon' => 'eicon-h-align-center',
1061 ],
1062 'right' => [
1063 'title' => esc_html__('Right', 'king-addons'),
1064 'icon' => 'eicon-h-align-right',
1065 ],
1066 ],
1067 'toggle' => false,
1068 'default' => 'center',
1069 'prefix_class' => 'king-addons-card-slider--button-text-align-',
1070 ]
1071 );
1072
1073 $this->add_group_control(
1074 Group_Control_Typography::get_type(),
1075 [
1076 'name' => 'kng_button_typography',
1077 'selector' => '{{WRAPPER}} .king-addons-card-slider__button',
1078 ]
1079 );
1080
1081 $this->start_controls_tabs('kng_button_tabs');
1082
1083 $this->start_controls_tab(
1084 'kng_button_tab_normal',
1085 [
1086 'label' => esc_html__('Normal', 'king-addons'),
1087 ]
1088 );
1089
1090 $this->add_control(
1091 'kng_button_text_color',
1092 [
1093 'label' => esc_html__('Text Color', 'king-addons'),
1094 'type' => Controls_Manager::COLOR,
1095 'default' => '#ffffff',
1096 'selectors' => [
1097 '{{WRAPPER}} .king-addons-card-slider__button' => 'color: {{VALUE}};',
1098 ],
1099 ]
1100 );
1101
1102 $this->add_control(
1103 'kng_button_background',
1104 [
1105 'label' => esc_html__('Background', 'king-addons'),
1106 'type' => Controls_Manager::COLOR,
1107 'selectors' => [
1108 '{{WRAPPER}} .king-addons-card-slider__button' => 'background-color: {{VALUE}};',
1109 ],
1110 ]
1111 );
1112
1113 $this->add_group_control(
1114 Group_Control_Border::get_type(),
1115 [
1116 'name' => 'kng_button_border',
1117 'selector' => '{{WRAPPER}} .king-addons-card-slider__button',
1118 ]
1119 );
1120
1121 $this->add_group_control(
1122 Group_Control_Box_Shadow::get_type(),
1123 [
1124 'name' => 'kng_button_shadow',
1125 'selector' => '{{WRAPPER}} .king-addons-card-slider__button',
1126 ]
1127 );
1128
1129 $this->add_group_control(
1130 Group_Control_Box_Shadow::get_type(),
1131 [
1132 'name' => 'kng_button_shadow_hover',
1133 'label' => esc_html__('Hover Shadow', 'king-addons'),
1134 'selector' => '{{WRAPPER}} .king-addons-card-slider__button:hover',
1135 ]
1136 );
1137
1138 $this->add_control(
1139 'kng_button_shadow_disable',
1140 [
1141 'label' => esc_html__('Disable Box Shadow', 'king-addons'),
1142 'type' => Controls_Manager::SWITCHER,
1143 'label_on' => esc_html__('Yes', 'king-addons'),
1144 'label_off' => esc_html__('No', 'king-addons'),
1145 'return_value' => 'yes',
1146 'default' => '',
1147 'selectors' => [
1148 '{{WRAPPER}} .king-addons-card-slider__button' => 'box-shadow: none !important;',
1149 ],
1150 ]
1151 );
1152
1153 $this->add_control(
1154 'kng_button_shadow_hover_disable',
1155 [
1156 'label' => esc_html__('Disable Box Shadow on Hover', 'king-addons'),
1157 'type' => Controls_Manager::SWITCHER,
1158 'label_on' => esc_html__('Yes', 'king-addons'),
1159 'label_off' => esc_html__('No', 'king-addons'),
1160 'return_value' => 'yes',
1161 'default' => '',
1162 'selectors' => [
1163 '{{WRAPPER}} .king-addons-card-slider__button:hover' => 'box-shadow: none !important;',
1164 ],
1165 ]
1166 );
1167
1168 $this->end_controls_tab();
1169
1170 $this->start_controls_tab(
1171 'kng_button_tab_hover',
1172 [
1173 'label' => esc_html__('Hover', 'king-addons'),
1174 ]
1175 );
1176
1177 $this->add_control(
1178 'kng_button_text_color_hover',
1179 [
1180 'label' => esc_html__('Text Color', 'king-addons'),
1181 'type' => Controls_Manager::COLOR,
1182 'selectors' => [
1183 '{{WRAPPER}} .king-addons-card-slider__button:hover' => 'color: {{VALUE}};',
1184 ],
1185 ]
1186 );
1187
1188 $this->add_control(
1189 'kng_button_background_hover',
1190 [
1191 'label' => esc_html__('Background', 'king-addons'),
1192 'type' => Controls_Manager::COLOR,
1193 'selectors' => [
1194 '{{WRAPPER}} .king-addons-card-slider__button:hover' => 'background-color: {{VALUE}};',
1195 ],
1196 ]
1197 );
1198
1199 $this->add_control(
1200 'kng_button_border_color_hover',
1201 [
1202 'label' => esc_html__('Border Color', 'king-addons'),
1203 'type' => Controls_Manager::COLOR,
1204 'selectors' => [
1205 '{{WRAPPER}} .king-addons-card-slider__button:hover' => 'border-color: {{VALUE}};',
1206 ],
1207 ]
1208 );
1209
1210 $this->add_group_control(
1211 Group_Control_Box_Shadow::get_type(),
1212 [
1213 'name' => 'kng_button_shadow_hover',
1214 'selector' => '{{WRAPPER}} .king-addons-card-slider__button:hover',
1215 ]
1216 );
1217
1218 $this->end_controls_tab();
1219
1220 $this->end_controls_tabs();
1221
1222 $this->add_responsive_control(
1223 'kng_button_padding',
1224 [
1225 'label' => esc_html__('Padding', 'king-addons'),
1226 'type' => Controls_Manager::DIMENSIONS,
1227 'size_units' => ['px', '%', 'em'],
1228 'selectors' => [
1229 '{{WRAPPER}} .king-addons-card-slider__button' => 'padding: {{TOP}}{{UNIT}} {{RIGHT}}{{UNIT}} {{BOTTOM}}{{UNIT}} {{LEFT}}{{UNIT}};',
1230 ],
1231 'separator' => 'before',
1232 ]
1233 );
1234
1235 $this->add_control(
1236 'kng_button_radius',
1237 [
1238 'label' => esc_html__('Border Radius', 'king-addons'),
1239 'type' => Controls_Manager::SLIDER,
1240 'size_units' => ['px', '%'],
1241 'range' => [
1242 'px' => ['min' => 0, 'max' => 80],
1243 '%' => ['min' => 0, 'max' => 100],
1244 ],
1245 'selectors' => [
1246 '{{WRAPPER}} .king-addons-card-slider__button' => 'border-radius: {{SIZE}}{{UNIT}};',
1247 ],
1248 ]
1249 );
1250
1251 $this->end_controls_section();
1252 }
1253
1254 /**
1255 * Register navigation style controls.
1256 *
1257 * @return void
1258 */
1259 public function register_style_navigation_controls(): void
1260 {
1261 $this->start_controls_section(
1262 'kng_style_navigation_section',
1263 [
1264 'label' => KING_ADDONS_ELEMENTOR_ICON . esc_html__('Navigation Arrows', 'king-addons'),
1265 'tab' => Controls_Manager::TAB_STYLE,
1266 'condition' => [
1267 'kng_show_navigation' => 'yes',
1268 ],
1269 ]
1270 );
1271
1272 $this->add_control(
1273 'kng_nav_size',
1274 [
1275 'label' => esc_html__('Size', 'king-addons'),
1276 'type' => Controls_Manager::SLIDER,
1277 'size_units' => ['px'],
1278 'range' => [
1279 'px' => ['min' => 24, 'max' => 96],
1280 ],
1281 'default' => [
1282 'size' => 44,
1283 'unit' => 'px',
1284 ],
1285 'selectors' => [
1286 '{{WRAPPER}} .king-addons-card-slider' => '--kng-card-slider-nav-size: {{SIZE}}{{UNIT}};',
1287 ],
1288 ]
1289 );
1290
1291 $this->add_control(
1292 'kng_nav_icon_size',
1293 [
1294 'label' => esc_html__('Icon Size', 'king-addons'),
1295 'type' => Controls_Manager::SLIDER,
1296 'size_units' => ['px'],
1297 'range' => [
1298 'px' => ['min' => 6, 'max' => 28],
1299 ],
1300 'default' => [
1301 'size' => 12,
1302 'unit' => 'px',
1303 ],
1304 'selectors' => [
1305 '{{WRAPPER}} .king-addons-card-slider' => '--kng-card-slider-nav-icon-size: {{SIZE}}{{UNIT}};',
1306 ],
1307 ]
1308 );
1309
1310 $this->start_controls_tabs('kng_nav_tabs');
1311
1312 $this->start_controls_tab(
1313 'kng_nav_tab_normal',
1314 [
1315 'label' => esc_html__('Normal', 'king-addons'),
1316 ]
1317 );
1318
1319 $this->add_control(
1320 'kng_nav_color',
1321 [
1322 'label' => esc_html__('Icon Color', 'king-addons'),
1323 'type' => Controls_Manager::COLOR,
1324 'selectors' => [
1325 '{{WRAPPER}} .king-addons-card-slider__arrow' => 'color: {{VALUE}};',
1326 ],
1327 ]
1328 );
1329
1330 $this->add_control(
1331 'kng_nav_background',
1332 [
1333 'label' => esc_html__('Background', 'king-addons'),
1334 'type' => Controls_Manager::COLOR,
1335 'selectors' => [
1336 '{{WRAPPER}} .king-addons-card-slider__arrow' => 'background-color: {{VALUE}};',
1337 ],
1338 ]
1339 );
1340
1341 $this->add_group_control(
1342 Group_Control_Border::get_type(),
1343 [
1344 'name' => 'kng_nav_border',
1345 'selector' => '{{WRAPPER}} .king-addons-card-slider__arrow',
1346 ]
1347 );
1348
1349 $this->add_group_control(
1350 Group_Control_Box_Shadow::get_type(),
1351 [
1352 'name' => 'kng_nav_shadow',
1353 'selector' => '{{WRAPPER}} .king-addons-card-slider__arrow',
1354 ]
1355 );
1356
1357 $this->end_controls_tab();
1358
1359 $this->start_controls_tab(
1360 'kng_nav_tab_hover',
1361 [
1362 'label' => esc_html__('Hover', 'king-addons'),
1363 ]
1364 );
1365
1366 $this->add_control(
1367 'kng_nav_color_hover',
1368 [
1369 'label' => esc_html__('Icon Color', 'king-addons'),
1370 'type' => Controls_Manager::COLOR,
1371 'selectors' => [
1372 '{{WRAPPER}} .king-addons-card-slider__arrow:hover' => 'color: {{VALUE}};',
1373 ],
1374 ]
1375 );
1376
1377 $this->add_control(
1378 'kng_nav_background_hover',
1379 [
1380 'label' => esc_html__('Background', 'king-addons'),
1381 'type' => Controls_Manager::COLOR,
1382 'selectors' => [
1383 '{{WRAPPER}} .king-addons-card-slider__arrow:hover' => 'background-color: {{VALUE}};',
1384 ],
1385 ]
1386 );
1387
1388 $this->add_control(
1389 'kng_nav_border_hover',
1390 [
1391 'label' => esc_html__('Border Color', 'king-addons'),
1392 'type' => Controls_Manager::COLOR,
1393 'selectors' => [
1394 '{{WRAPPER}} .king-addons-card-slider__arrow:hover' => 'border-color: {{VALUE}};',
1395 ],
1396 ]
1397 );
1398
1399 $this->add_group_control(
1400 Group_Control_Box_Shadow::get_type(),
1401 [
1402 'name' => 'kng_nav_shadow_hover',
1403 'selector' => '{{WRAPPER}} .king-addons-card-slider__arrow:hover',
1404 ]
1405 );
1406
1407 $this->end_controls_tab();
1408
1409 $this->end_controls_tabs();
1410
1411 $this->add_control(
1412 'kng_nav_radius',
1413 [
1414 'label' => esc_html__('Border Radius', 'king-addons'),
1415 'type' => Controls_Manager::SLIDER,
1416 'size_units' => ['px', '%'],
1417 'range' => [
1418 'px' => ['min' => 0, 'max' => 80],
1419 '%' => ['min' => 0, 'max' => 100],
1420 ],
1421 'selectors' => [
1422 '{{WRAPPER}} .king-addons-card-slider__arrow' => 'border-radius: {{SIZE}}{{UNIT}};',
1423 ],
1424 'separator' => 'before',
1425 ]
1426 );
1427
1428 $this->end_controls_section();
1429 }
1430
1431 /**
1432 * Register pagination style controls.
1433 *
1434 * @return void
1435 */
1436 public function register_style_pagination_controls(): void
1437 {
1438 $this->start_controls_section(
1439 'kng_style_pagination_section',
1440 [
1441 'label' => KING_ADDONS_ELEMENTOR_ICON . esc_html__('Pagination Dots', 'king-addons'),
1442 'tab' => Controls_Manager::TAB_STYLE,
1443 'condition' => [
1444 'kng_show_pagination' => 'yes',
1445 ],
1446 ]
1447 );
1448
1449 $this->add_control(
1450 'kng_pagination_size',
1451 [
1452 'label' => esc_html__('Dot Size', 'king-addons'),
1453 'type' => Controls_Manager::SLIDER,
1454 'size_units' => ['px'],
1455 'range' => [
1456 'px' => ['min' => 4, 'max' => 24],
1457 ],
1458 'default' => [
1459 'size' => 8,
1460 'unit' => 'px',
1461 ],
1462 'selectors' => [
1463 '{{WRAPPER}} .king-addons-card-slider' => '--kng-card-slider-pagination-size: {{SIZE}}{{UNIT}};',
1464 ],
1465 ]
1466 );
1467
1468 $this->start_controls_tabs('kng_pagination_tabs');
1469
1470 $this->start_controls_tab(
1471 'kng_pagination_tab_normal',
1472 [
1473 'label' => esc_html__('Normal', 'king-addons'),
1474 ]
1475 );
1476
1477 $this->add_control(
1478 'kng_pagination_color',
1479 [
1480 'label' => esc_html__('Color', 'king-addons'),
1481 'type' => Controls_Manager::COLOR,
1482 'selectors' => [
1483 '{{WRAPPER}} .king-addons-card-slider__pagination .swiper-pagination-bullet' => 'background-color: {{VALUE}};',
1484 ],
1485 ]
1486 );
1487
1488 $this->end_controls_tab();
1489
1490 $this->start_controls_tab(
1491 'kng_pagination_tab_active',
1492 [
1493 'label' => esc_html__('Active', 'king-addons'),
1494 ]
1495 );
1496
1497 $this->add_control(
1498 'kng_pagination_color_active',
1499 [
1500 'label' => esc_html__('Color', 'king-addons'),
1501 'type' => Controls_Manager::COLOR,
1502 'selectors' => [
1503 '{{WRAPPER}} .king-addons-card-slider__pagination .swiper-pagination-bullet-active' => 'background-color: {{VALUE}};',
1504 ],
1505 ]
1506 );
1507
1508 $this->add_control(
1509 'kng_pagination_active_width',
1510 [
1511 'label' => esc_html__('Active Width', 'king-addons'),
1512 'type' => Controls_Manager::SLIDER,
1513 'size_units' => ['px'],
1514 'range' => [
1515 'px' => ['min' => 4, 'max' => 32],
1516 ],
1517 'selectors' => [
1518 '{{WRAPPER}} .king-addons-card-slider' => '--kng-card-slider-pagination-active-width: {{SIZE}}{{UNIT}};',
1519 ],
1520 ]
1521 );
1522
1523 $this->end_controls_tab();
1524
1525 $this->end_controls_tabs();
1526
1527 $this->end_controls_section();
1528 }
1529
1530 /**
1531 * Render a single slide.
1532 *
1533 * @param array<string, mixed> $card Card data.
1534 *
1535 * @return void
1536 */
1537 public function render_slide(array $card): void
1538 {
1539 $image_html = $this->get_card_image($card);
1540
1541 $title = $card['kng_card_title'] ?? '';
1542 $description = $card['kng_card_description'] ?? '';
1543 $button_text = $card['kng_card_button_text'] ?? '';
1544 $button_link = $card['kng_card_button_link'] ?? [];
1545 $card_link_enabled = ($card['kng_card_link_enable'] ?? '') === 'yes';
1546 $card_link = $card['kng_card_link'] ?? [];
1547
1548 $slide_classes = $this->get_slide_classes($card);
1549
1550 $card_link_attributes = $this->get_card_link_attributes($card_link_enabled, $card_link);
1551
1552 ?>
1553 <div class="king-addons-card-slider__slide swiper-slide <?php echo esc_attr($slide_classes); ?>" <?php echo $card_link_attributes; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped ?>>
1554 <article class="king-addons-card-slider__card">
1555 <?php if (!empty($image_html)) : ?>
1556 <div class="king-addons-card-slider__media">
1557 <?php echo $image_html; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped ?>
1558 <?php $this->render_card_badge($card); ?>
1559 </div>
1560 <?php endif; ?>
1561
1562 <div class="king-addons-card-slider__body">
1563 <?php if (!empty($title)) : ?>
1564 <h3 class="king-addons-card-slider__title"><?php echo esc_html($title); ?></h3>
1565 <?php endif; ?>
1566 <?php if (!empty($description)) : ?>
1567 <div class="king-addons-card-slider__description"><?php echo esc_html($description); ?></div>
1568 <?php endif; ?>
1569 <?php if (!empty($button_text)) : ?>
1570 <?php $this->render_button($button_text, $button_link); ?>
1571 <?php endif; ?>
1572 </div>
1573 </article>
1574 </div>
1575 <?php
1576 }
1577
1578 /**
1579 * Get default cards for the repeater.
1580 *
1581 * @return array<int, array<string, mixed>>
1582 */
1583 public function get_default_cards(): array
1584 {
1585 return [
1586 [
1587 'kng_card_title' => esc_html__('Feature-rich card', 'king-addons'),
1588 'kng_card_description' => esc_html__('Highlight what makes your offer compelling with concise supporting text.', 'king-addons'),
1589 'kng_card_button_text' => esc_html__('Explore', 'king-addons'),
1590 'kng_card_image' => ['url' => Utils::get_placeholder_image_src()],
1591 ],
1592 [
1593 'kng_card_title' => esc_html__('Built-in spacing', 'king-addons'),
1594 'kng_card_description' => esc_html__('Defaults ensure navigation and pagination never cover your content.', 'king-addons'),
1595 'kng_card_button_text' => esc_html__('See details', 'king-addons'),
1596 'kng_card_image' => ['url' => Utils::get_placeholder_image_src()],
1597 ],
1598 [
1599 'kng_card_title' => esc_html__('Modern styling', 'king-addons'),
1600 'kng_card_description' => esc_html__('Cards ship with clean typography, soft shadows, and rounded corners.', 'king-addons'),
1601 'kng_card_button_text' => esc_html__('Get started', 'king-addons'),
1602 'kng_card_image' => ['url' => Utils::get_placeholder_image_src()],
1603 ],
1604 [
1605 'kng_card_title' => esc_html__('Responsive design', 'king-addons'),
1606 'kng_card_description' => esc_html__('Looks great on all devices with optimized touch interactions.', 'king-addons'),
1607 'kng_card_button_text' => esc_html__('Learn more', 'king-addons'),
1608 'kng_card_image' => ['url' => Utils::get_placeholder_image_src()],
1609 ],
1610 ];
1611 }
1612
1613 /**
1614 * Get slider data attributes string for frontend JS.
1615 *
1616 * @param array<string, mixed> $settings Widget settings.
1617 *
1618 * @return string
1619 */
1620 public function get_slider_data_attributes(array $settings): string
1621 {
1622 $slides = !empty($settings['kng_slides_per_view']) ? (int) $settings['kng_slides_per_view'] : 1;
1623 $slides_tablet = !empty($settings['kng_slides_per_view_tablet']) ? (int) $settings['kng_slides_per_view_tablet'] : $slides;
1624 $slides_mobile = !empty($settings['kng_slides_per_view_mobile']) ? (int) $settings['kng_slides_per_view_mobile'] : $slides_tablet;
1625 $space_between = isset($settings['kng_space_between']['size']) ? (int) $settings['kng_space_between']['size'] : 20;
1626 $autoplay = $settings['kng_autoplay'] === 'yes' ? 'yes' : 'no';
1627 $autoplay_delay = !empty($settings['kng_autoplay_delay']) ? (int) $settings['kng_autoplay_delay'] : 3200;
1628 $loop = $settings['kng_loop'] === 'yes' ? 'yes' : 'no';
1629 $speed = !empty($settings['kng_speed']) ? (int) $settings['kng_speed'] : 600;
1630
1631 $show_navigation = $settings['kng_show_navigation'] === 'yes' ? 'yes' : 'no';
1632 $show_pagination = $settings['kng_show_pagination'] === 'yes' ? 'yes' : 'no';
1633
1634 $attributes = [
1635 'data-slides-per-view' => $slides,
1636 'data-slides-per-view-tablet' => $slides_tablet,
1637 'data-slides-per-view-mobile' => $slides_mobile,
1638 'data-space-between' => $space_between,
1639 'data-autoplay' => $autoplay,
1640 'data-autoplay-delay' => $autoplay_delay,
1641 'data-loop' => $loop,
1642 'data-speed' => $speed,
1643 'data-navigation' => $show_navigation,
1644 'data-pagination' => $show_pagination,
1645 ];
1646
1647 return $this->format_data_attributes($attributes);
1648 }
1649
1650 /**
1651 * Build wrapper classes based on settings.
1652 *
1653 * @param array<string, mixed> $settings Widget settings.
1654 *
1655 * @return array<int, string>
1656 */
1657 public function get_wrapper_classes(array $settings): array
1658 {
1659 $classes = ['king-addons-card-slider'];
1660
1661 $nav_position = $settings['kng_navigation_position'] ?? 'outside';
1662 $classes[] = 'king-addons-card-slider--nav-' . sanitize_html_class((string) $nav_position);
1663
1664 $nav_alignment = $settings['kng_navigation_alignment'] ?? 'flex-end';
1665 $classes[] = 'king-addons-card-slider--nav-align-' . sanitize_html_class((string) $nav_alignment);
1666
1667 if (!empty($settings['kng_navigation_hide_tablet'])) {
1668 $classes[] = 'king-addons-card-slider--nav-hide-tablet';
1669 }
1670
1671 if (!empty($settings['kng_navigation_hide_mobile'])) {
1672 $classes[] = 'king-addons-card-slider--nav-hide-mobile';
1673 }
1674
1675 $pagination_position = $settings['kng_pagination_position'] ?? 'outside';
1676 $classes[] = 'king-addons-card-slider--pagination-' . sanitize_html_class((string) $pagination_position);
1677
1678 $pagination_alignment = $settings['kng_pagination_alignment'] ?? 'center';
1679 $classes[] = 'king-addons-card-slider--pagination-align-' . sanitize_html_class((string) $pagination_alignment);
1680
1681 $classes = array_merge($classes, $this->get_additional_wrapper_classes($settings));
1682
1683 return array_filter($classes);
1684 }
1685
1686 /**
1687 * Get wrapper style attributes for CSS variables.
1688 *
1689 * @param array<string, mixed> $settings Widget settings.
1690 *
1691 * @return string
1692 */
1693 public function get_wrapper_style_attributes(array $settings): string
1694 {
1695 // CSS variables for pagination offset, pagination gap, and navigation gap
1696 // are now handled via Elementor selectors in the control definitions.
1697 // This ensures proper responsive behavior and avoids conflicts with
1698 // Elementor's built-in style handling.
1699 return '';
1700 }
1701
1702 /**
1703 * Render button element.
1704 *
1705 * @param string $text Button text.
1706 * @param array<string, mixed> $link Button link array.
1707 *
1708 * @return void
1709 */
1710 public function render_button(string $text, array $link): void
1711 {
1712 $url = $link['url'] ?? '';
1713 $rel = [];
1714
1715 if (!empty($link['nofollow'])) {
1716 $rel[] = 'nofollow';
1717 }
1718
1719 if (!empty($link['is_external'])) {
1720 $rel[] = 'noopener';
1721 $rel[] = 'noreferrer';
1722 }
1723
1724 $attributes = '';
1725
1726 if (!empty($url)) {
1727 $attributes .= ' href="' . esc_url($url) . '"';
1728 }
1729
1730 if (!empty($link['is_external'])) {
1731 $attributes .= ' target="_blank"';
1732 }
1733
1734 if (!empty($rel)) {
1735 $attributes .= ' rel="' . esc_attr(implode(' ', array_unique($rel))) . '"';
1736 }
1737
1738 ?>
1739 <a class="king-addons-card-slider__button"<?php echo $attributes; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped ?>>
1740 <?php echo esc_html($text); ?>
1741 </a>
1742 <?php
1743 }
1744
1745 /**
1746 * Get card image HTML.
1747 *
1748 * @param array<string, mixed> $card Card data.
1749 *
1750 * @return string
1751 */
1752 public function get_card_image(array $card): string
1753 {
1754 if (empty($card['kng_card_image']['id']) && empty($card['kng_card_image']['url'])) {
1755 return '';
1756 }
1757
1758 return Group_Control_Image_Size::get_attachment_image_html($card, 'kng_card_image');
1759 }
1760
1761 /**
1762 * Get slide classes.
1763 *
1764 * @param array<string, mixed> $card Card data.
1765 *
1766 * @return string
1767 */
1768 public function get_slide_classes(array $card): string
1769 {
1770 $classes = ['king-addons-card-slider__slide-inner'];
1771
1772 $classes = array_merge($classes, $this->get_additional_slide_classes($card));
1773
1774 return implode(' ', array_filter($classes));
1775 }
1776
1777 /**
1778 * Build data attributes for card-level navigation.
1779 *
1780 * @param bool $enabled Whether link is enabled.
1781 * @param array<string, mixed> $link Link data.
1782 *
1783 * @return string
1784 */
1785 public function get_card_link_attributes(bool $enabled, array $link): string
1786 {
1787 if (!$enabled || empty($link['url'])) {
1788 return '';
1789 }
1790
1791 $attrs = [
1792 'data-card-link' => esc_url_raw($link['url']),
1793 ];
1794
1795 if (!empty($link['is_external'])) {
1796 $attrs['data-card-link-target'] = '_blank';
1797 }
1798
1799 if (!empty($link['nofollow'])) {
1800 $attrs['data-card-link-rel'] = 'nofollow';
1801 }
1802
1803 $attributes = [];
1804 foreach ($attrs as $key => $value) {
1805 $attributes[] = esc_attr($key) . '="' . esc_attr((string) $value) . '"';
1806 }
1807
1808 return implode(' ', $attributes);
1809 }
1810
1811 /**
1812 * Format data attributes array into HTML attributes string.
1813 *
1814 * @param array<string, string|int> $attributes Attributes to format.
1815 *
1816 * @return string
1817 */
1818 public function format_data_attributes(array $attributes): string
1819 {
1820 $output = [];
1821
1822 foreach ($attributes as $key => $value) {
1823 $output[] = esc_attr($key) . '="' . esc_attr((string) $value) . '"';
1824 }
1825
1826 return implode(' ', $output);
1827 }
1828
1829 /**
1830 * Placeholder for additional wrapper classes (Pro overrides).
1831 *
1832 * @param array<string, mixed> $settings Widget settings.
1833 *
1834 * @return array<int, string>
1835 */
1836 public function get_additional_wrapper_classes(array $settings): array
1837 {
1838 unset($settings);
1839 return [];
1840 }
1841
1842 /**
1843 * Placeholder for additional slide classes (Pro overrides).
1844 *
1845 * @param array<string, mixed> $card Card data.
1846 *
1847 * @return array<int, string>
1848 */
1849 public function get_additional_slide_classes(array $card): array
1850 {
1851 unset($card);
1852 return [];
1853 }
1854
1855 /**
1856 * Placeholder for navigation pro controls.
1857 *
1858 * @return void
1859 */
1860 public function add_pro_navigation_controls(): void
1861 {
1862 // Premium navigation style controls are added in Pro.
1863 $this->add_control(
1864 'kng_navigation_skin',
1865 [
1866 'label' => sprintf(__('Arrow Style %s', 'king-addons'), '<i class="eicon-pro-icon"></i>'),
1867 'type' => Controls_Manager::SELECT,
1868 'default' => 'elevated',
1869 'options' => [
1870 'elevated' => esc_html__('Elevated', 'king-addons'),
1871 'pro-solid' => esc_html__('Solid (Pro)', 'king-addons'),
1872 'pro-ghost' => esc_html__('Ghost (Pro)', 'king-addons'),
1873 'pro-minimal' => esc_html__('Minimal (Pro)', 'king-addons'),
1874 ],
1875 'condition' => [
1876 'kng_show_navigation' => 'yes',
1877 ],
1878 ]
1879 );
1880 }
1881
1882 /**
1883 * Placeholder for pagination pro controls.
1884 *
1885 * @return void
1886 */
1887 public function add_pro_pagination_controls(): void
1888 {
1889 // Premium pagination style controls are added in Pro.
1890 $this->add_control(
1891 'kng_pagination_skin',
1892 [
1893 'label' => sprintf(__('Dots Style %s', 'king-addons'), '<i class="eicon-pro-icon"></i>'),
1894 'type' => Controls_Manager::SELECT,
1895 'default' => 'dot',
1896 'options' => [
1897 'dot' => esc_html__('Dots', 'king-addons'),
1898 'pro-pill' => esc_html__('Pill (Pro)', 'king-addons'),
1899 'pro-outlined' => esc_html__('Outlined (Pro)', 'king-addons'),
1900 ],
1901 'condition' => [
1902 'kng_show_pagination' => 'yes',
1903 ],
1904 ]
1905 );
1906 }
1907
1908 /**
1909 * Placeholder for rendering badges (Pro overrides).
1910 *
1911 * @param array<string, mixed> $card Card data.
1912 *
1913 * @return void
1914 */
1915 public function render_card_badge(array $card): void
1916 {
1917 unset($card);
1918 // Premium badge rendering is handled in Pro.
1919 }
1920
1921 /**
1922 * Register upgrade notice section for premium features.
1923 *
1924 * @return void
1925 */
1926 public function register_pro_notice_controls(): void
1927 {
1928 if (!king_addons_freemius()->can_use_premium_code__premium_only()) {
1929 Core::renderProFeaturesSection($this, '', Controls_Manager::RAW_HTML, 'quick-card-slider', [
1930 'Per-card badges and ribbons',
1931 'Advanced hover and entrance animations',
1932 'Navigation and pagination style presets',
1933 'Extended placement and offset controls',
1934 'Badge typography and color styling',
1935 ]);
1936 }
1937 }
1938 }
1939
1940
1941
1942
1943
1944
1945
1946
1947