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

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