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

1,939 lines 63.5 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->end_controls_tab();
1211
1212 $this->end_controls_tabs();
1213
1214 $this->add_responsive_control(
1215 'kng_button_padding',
1216 [
1217 'label' => esc_html__('Padding', 'king-addons'),
1218 'type' => Controls_Manager::DIMENSIONS,
1219 'size_units' => ['px', '%', 'em'],
1220 'selectors' => [
1221 '{{WRAPPER}} .king-addons-card-slider__button' => 'padding: {{TOP}}{{UNIT}} {{RIGHT}}{{UNIT}} {{BOTTOM}}{{UNIT}} {{LEFT}}{{UNIT}};',
1222 ],
1223 'separator' => 'before',
1224 ]
1225 );
1226
1227 $this->add_control(
1228 'kng_button_radius',
1229 [
1230 'label' => esc_html__('Border Radius', 'king-addons'),
1231 'type' => Controls_Manager::SLIDER,
1232 'size_units' => ['px', '%'],
1233 'range' => [
1234 'px' => ['min' => 0, 'max' => 80],
1235 '%' => ['min' => 0, 'max' => 100],
1236 ],
1237 'selectors' => [
1238 '{{WRAPPER}} .king-addons-card-slider__button' => 'border-radius: {{SIZE}}{{UNIT}};',
1239 ],
1240 ]
1241 );
1242
1243 $this->end_controls_section();
1244 }
1245
1246 /**
1247 * Register navigation style controls.
1248 *
1249 * @return void
1250 */
1251 public function register_style_navigation_controls(): void
1252 {
1253 $this->start_controls_section(
1254 'kng_style_navigation_section',
1255 [
1256 'label' => KING_ADDONS_ELEMENTOR_ICON . esc_html__('Navigation Arrows', 'king-addons'),
1257 'tab' => Controls_Manager::TAB_STYLE,
1258 'condition' => [
1259 'kng_show_navigation' => 'yes',
1260 ],
1261 ]
1262 );
1263
1264 $this->add_control(
1265 'kng_nav_size',
1266 [
1267 'label' => esc_html__('Size', 'king-addons'),
1268 'type' => Controls_Manager::SLIDER,
1269 'size_units' => ['px'],
1270 'range' => [
1271 'px' => ['min' => 24, 'max' => 96],
1272 ],
1273 'default' => [
1274 'size' => 44,
1275 'unit' => 'px',
1276 ],
1277 'selectors' => [
1278 '{{WRAPPER}} .king-addons-card-slider' => '--kng-card-slider-nav-size: {{SIZE}}{{UNIT}};',
1279 ],
1280 ]
1281 );
1282
1283 $this->add_control(
1284 'kng_nav_icon_size',
1285 [
1286 'label' => esc_html__('Icon Size', 'king-addons'),
1287 'type' => Controls_Manager::SLIDER,
1288 'size_units' => ['px'],
1289 'range' => [
1290 'px' => ['min' => 6, 'max' => 28],
1291 ],
1292 'default' => [
1293 'size' => 12,
1294 'unit' => 'px',
1295 ],
1296 'selectors' => [
1297 '{{WRAPPER}} .king-addons-card-slider' => '--kng-card-slider-nav-icon-size: {{SIZE}}{{UNIT}};',
1298 ],
1299 ]
1300 );
1301
1302 $this->start_controls_tabs('kng_nav_tabs');
1303
1304 $this->start_controls_tab(
1305 'kng_nav_tab_normal',
1306 [
1307 'label' => esc_html__('Normal', 'king-addons'),
1308 ]
1309 );
1310
1311 $this->add_control(
1312 'kng_nav_color',
1313 [
1314 'label' => esc_html__('Icon Color', 'king-addons'),
1315 'type' => Controls_Manager::COLOR,
1316 'selectors' => [
1317 '{{WRAPPER}} .king-addons-card-slider__arrow' => 'color: {{VALUE}};',
1318 ],
1319 ]
1320 );
1321
1322 $this->add_control(
1323 'kng_nav_background',
1324 [
1325 'label' => esc_html__('Background', 'king-addons'),
1326 'type' => Controls_Manager::COLOR,
1327 'selectors' => [
1328 '{{WRAPPER}} .king-addons-card-slider__arrow' => 'background-color: {{VALUE}};',
1329 ],
1330 ]
1331 );
1332
1333 $this->add_group_control(
1334 Group_Control_Border::get_type(),
1335 [
1336 'name' => 'kng_nav_border',
1337 'selector' => '{{WRAPPER}} .king-addons-card-slider__arrow',
1338 ]
1339 );
1340
1341 $this->add_group_control(
1342 Group_Control_Box_Shadow::get_type(),
1343 [
1344 'name' => 'kng_nav_shadow',
1345 'selector' => '{{WRAPPER}} .king-addons-card-slider__arrow',
1346 ]
1347 );
1348
1349 $this->end_controls_tab();
1350
1351 $this->start_controls_tab(
1352 'kng_nav_tab_hover',
1353 [
1354 'label' => esc_html__('Hover', 'king-addons'),
1355 ]
1356 );
1357
1358 $this->add_control(
1359 'kng_nav_color_hover',
1360 [
1361 'label' => esc_html__('Icon Color', 'king-addons'),
1362 'type' => Controls_Manager::COLOR,
1363 'selectors' => [
1364 '{{WRAPPER}} .king-addons-card-slider__arrow:hover' => 'color: {{VALUE}};',
1365 ],
1366 ]
1367 );
1368
1369 $this->add_control(
1370 'kng_nav_background_hover',
1371 [
1372 'label' => esc_html__('Background', 'king-addons'),
1373 'type' => Controls_Manager::COLOR,
1374 'selectors' => [
1375 '{{WRAPPER}} .king-addons-card-slider__arrow:hover' => 'background-color: {{VALUE}};',
1376 ],
1377 ]
1378 );
1379
1380 $this->add_control(
1381 'kng_nav_border_hover',
1382 [
1383 'label' => esc_html__('Border Color', 'king-addons'),
1384 'type' => Controls_Manager::COLOR,
1385 'selectors' => [
1386 '{{WRAPPER}} .king-addons-card-slider__arrow:hover' => 'border-color: {{VALUE}};',
1387 ],
1388 ]
1389 );
1390
1391 $this->add_group_control(
1392 Group_Control_Box_Shadow::get_type(),
1393 [
1394 'name' => 'kng_nav_shadow_hover',
1395 'selector' => '{{WRAPPER}} .king-addons-card-slider__arrow:hover',
1396 ]
1397 );
1398
1399 $this->end_controls_tab();
1400
1401 $this->end_controls_tabs();
1402
1403 $this->add_control(
1404 'kng_nav_radius',
1405 [
1406 'label' => esc_html__('Border Radius', 'king-addons'),
1407 'type' => Controls_Manager::SLIDER,
1408 'size_units' => ['px', '%'],
1409 'range' => [
1410 'px' => ['min' => 0, 'max' => 80],
1411 '%' => ['min' => 0, 'max' => 100],
1412 ],
1413 'selectors' => [
1414 '{{WRAPPER}} .king-addons-card-slider__arrow' => 'border-radius: {{SIZE}}{{UNIT}};',
1415 ],
1416 'separator' => 'before',
1417 ]
1418 );
1419
1420 $this->end_controls_section();
1421 }
1422
1423 /**
1424 * Register pagination style controls.
1425 *
1426 * @return void
1427 */
1428 public function register_style_pagination_controls(): void
1429 {
1430 $this->start_controls_section(
1431 'kng_style_pagination_section',
1432 [
1433 'label' => KING_ADDONS_ELEMENTOR_ICON . esc_html__('Pagination Dots', 'king-addons'),
1434 'tab' => Controls_Manager::TAB_STYLE,
1435 'condition' => [
1436 'kng_show_pagination' => 'yes',
1437 ],
1438 ]
1439 );
1440
1441 $this->add_control(
1442 'kng_pagination_size',
1443 [
1444 'label' => esc_html__('Dot Size', 'king-addons'),
1445 'type' => Controls_Manager::SLIDER,
1446 'size_units' => ['px'],
1447 'range' => [
1448 'px' => ['min' => 4, 'max' => 24],
1449 ],
1450 'default' => [
1451 'size' => 8,
1452 'unit' => 'px',
1453 ],
1454 'selectors' => [
1455 '{{WRAPPER}} .king-addons-card-slider' => '--kng-card-slider-pagination-size: {{SIZE}}{{UNIT}};',
1456 ],
1457 ]
1458 );
1459
1460 $this->start_controls_tabs('kng_pagination_tabs');
1461
1462 $this->start_controls_tab(
1463 'kng_pagination_tab_normal',
1464 [
1465 'label' => esc_html__('Normal', 'king-addons'),
1466 ]
1467 );
1468
1469 $this->add_control(
1470 'kng_pagination_color',
1471 [
1472 'label' => esc_html__('Color', 'king-addons'),
1473 'type' => Controls_Manager::COLOR,
1474 'selectors' => [
1475 '{{WRAPPER}} .king-addons-card-slider__pagination .swiper-pagination-bullet' => 'background-color: {{VALUE}};',
1476 ],
1477 ]
1478 );
1479
1480 $this->end_controls_tab();
1481
1482 $this->start_controls_tab(
1483 'kng_pagination_tab_active',
1484 [
1485 'label' => esc_html__('Active', 'king-addons'),
1486 ]
1487 );
1488
1489 $this->add_control(
1490 'kng_pagination_color_active',
1491 [
1492 'label' => esc_html__('Color', 'king-addons'),
1493 'type' => Controls_Manager::COLOR,
1494 'selectors' => [
1495 '{{WRAPPER}} .king-addons-card-slider__pagination .swiper-pagination-bullet-active' => 'background-color: {{VALUE}};',
1496 ],
1497 ]
1498 );
1499
1500 $this->add_control(
1501 'kng_pagination_active_width',
1502 [
1503 'label' => esc_html__('Active Width', 'king-addons'),
1504 'type' => Controls_Manager::SLIDER,
1505 'size_units' => ['px'],
1506 'range' => [
1507 'px' => ['min' => 4, 'max' => 32],
1508 ],
1509 'selectors' => [
1510 '{{WRAPPER}} .king-addons-card-slider' => '--kng-card-slider-pagination-active-width: {{SIZE}}{{UNIT}};',
1511 ],
1512 ]
1513 );
1514
1515 $this->end_controls_tab();
1516
1517 $this->end_controls_tabs();
1518
1519 $this->end_controls_section();
1520 }
1521
1522 /**
1523 * Render a single slide.
1524 *
1525 * @param array<string, mixed> $card Card data.
1526 *
1527 * @return void
1528 */
1529 public function render_slide(array $card): void
1530 {
1531 $image_html = $this->get_card_image($card);
1532
1533 $title = $card['kng_card_title'] ?? '';
1534 $description = $card['kng_card_description'] ?? '';
1535 $button_text = $card['kng_card_button_text'] ?? '';
1536 $button_link = $card['kng_card_button_link'] ?? [];
1537 $card_link_enabled = ($card['kng_card_link_enable'] ?? '') === 'yes';
1538 $card_link = $card['kng_card_link'] ?? [];
1539
1540 $slide_classes = $this->get_slide_classes($card);
1541
1542 $card_link_attributes = $this->get_card_link_attributes($card_link_enabled, $card_link);
1543
1544 ?>
1545 <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 ?>>
1546 <article class="king-addons-card-slider__card">
1547 <?php if (!empty($image_html)) : ?>
1548 <div class="king-addons-card-slider__media">
1549 <?php echo $image_html; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped ?>
1550 <?php $this->render_card_badge($card); ?>
1551 </div>
1552 <?php endif; ?>
1553
1554 <div class="king-addons-card-slider__body">
1555 <?php if (!empty($title)) : ?>
1556 <h3 class="king-addons-card-slider__title"><?php echo esc_html($title); ?></h3>
1557 <?php endif; ?>
1558 <?php if (!empty($description)) : ?>
1559 <div class="king-addons-card-slider__description"><?php echo esc_html($description); ?></div>
1560 <?php endif; ?>
1561 <?php if (!empty($button_text)) : ?>
1562 <?php $this->render_button($button_text, $button_link); ?>
1563 <?php endif; ?>
1564 </div>
1565 </article>
1566 </div>
1567 <?php
1568 }
1569
1570 /**
1571 * Get default cards for the repeater.
1572 *
1573 * @return array<int, array<string, mixed>>
1574 */
1575 public function get_default_cards(): array
1576 {
1577 return [
1578 [
1579 'kng_card_title' => esc_html__('Feature-rich card', 'king-addons'),
1580 'kng_card_description' => esc_html__('Highlight what makes your offer compelling with concise supporting text.', 'king-addons'),
1581 'kng_card_button_text' => esc_html__('Explore', 'king-addons'),
1582 'kng_card_image' => ['url' => Utils::get_placeholder_image_src()],
1583 ],
1584 [
1585 'kng_card_title' => esc_html__('Built-in spacing', 'king-addons'),
1586 'kng_card_description' => esc_html__('Defaults ensure navigation and pagination never cover your content.', 'king-addons'),
1587 'kng_card_button_text' => esc_html__('See details', 'king-addons'),
1588 'kng_card_image' => ['url' => Utils::get_placeholder_image_src()],
1589 ],
1590 [
1591 'kng_card_title' => esc_html__('Modern styling', 'king-addons'),
1592 'kng_card_description' => esc_html__('Cards ship with clean typography, soft shadows, and rounded corners.', 'king-addons'),
1593 'kng_card_button_text' => esc_html__('Get started', 'king-addons'),
1594 'kng_card_image' => ['url' => Utils::get_placeholder_image_src()],
1595 ],
1596 [
1597 'kng_card_title' => esc_html__('Responsive design', 'king-addons'),
1598 'kng_card_description' => esc_html__('Looks great on all devices with optimized touch interactions.', 'king-addons'),
1599 'kng_card_button_text' => esc_html__('Learn more', 'king-addons'),
1600 'kng_card_image' => ['url' => Utils::get_placeholder_image_src()],
1601 ],
1602 ];
1603 }
1604
1605 /**
1606 * Get slider data attributes string for frontend JS.
1607 *
1608 * @param array<string, mixed> $settings Widget settings.
1609 *
1610 * @return string
1611 */
1612 public function get_slider_data_attributes(array $settings): string
1613 {
1614 $slides = !empty($settings['kng_slides_per_view']) ? (int) $settings['kng_slides_per_view'] : 1;
1615 $slides_tablet = !empty($settings['kng_slides_per_view_tablet']) ? (int) $settings['kng_slides_per_view_tablet'] : $slides;
1616 $slides_mobile = !empty($settings['kng_slides_per_view_mobile']) ? (int) $settings['kng_slides_per_view_mobile'] : $slides_tablet;
1617 $space_between = isset($settings['kng_space_between']['size']) ? (int) $settings['kng_space_between']['size'] : 20;
1618 $autoplay = $settings['kng_autoplay'] === 'yes' ? 'yes' : 'no';
1619 $autoplay_delay = !empty($settings['kng_autoplay_delay']) ? (int) $settings['kng_autoplay_delay'] : 3200;
1620 $loop = $settings['kng_loop'] === 'yes' ? 'yes' : 'no';
1621 $speed = !empty($settings['kng_speed']) ? (int) $settings['kng_speed'] : 600;
1622
1623 $show_navigation = $settings['kng_show_navigation'] === 'yes' ? 'yes' : 'no';
1624 $show_pagination = $settings['kng_show_pagination'] === 'yes' ? 'yes' : 'no';
1625
1626 $attributes = [
1627 'data-slides-per-view' => $slides,
1628 'data-slides-per-view-tablet' => $slides_tablet,
1629 'data-slides-per-view-mobile' => $slides_mobile,
1630 'data-space-between' => $space_between,
1631 'data-autoplay' => $autoplay,
1632 'data-autoplay-delay' => $autoplay_delay,
1633 'data-loop' => $loop,
1634 'data-speed' => $speed,
1635 'data-navigation' => $show_navigation,
1636 'data-pagination' => $show_pagination,
1637 ];
1638
1639 return $this->format_data_attributes($attributes);
1640 }
1641
1642 /**
1643 * Build wrapper classes based on settings.
1644 *
1645 * @param array<string, mixed> $settings Widget settings.
1646 *
1647 * @return array<int, string>
1648 */
1649 public function get_wrapper_classes(array $settings): array
1650 {
1651 $classes = ['king-addons-card-slider'];
1652
1653 $nav_position = $settings['kng_navigation_position'] ?? 'outside';
1654 $classes[] = 'king-addons-card-slider--nav-' . sanitize_html_class((string) $nav_position);
1655
1656 $nav_alignment = $settings['kng_navigation_alignment'] ?? 'flex-end';
1657 $classes[] = 'king-addons-card-slider--nav-align-' . sanitize_html_class((string) $nav_alignment);
1658
1659 if (!empty($settings['kng_navigation_hide_tablet'])) {
1660 $classes[] = 'king-addons-card-slider--nav-hide-tablet';
1661 }
1662
1663 if (!empty($settings['kng_navigation_hide_mobile'])) {
1664 $classes[] = 'king-addons-card-slider--nav-hide-mobile';
1665 }
1666
1667 $pagination_position = $settings['kng_pagination_position'] ?? 'outside';
1668 $classes[] = 'king-addons-card-slider--pagination-' . sanitize_html_class((string) $pagination_position);
1669
1670 $pagination_alignment = $settings['kng_pagination_alignment'] ?? 'center';
1671 $classes[] = 'king-addons-card-slider--pagination-align-' . sanitize_html_class((string) $pagination_alignment);
1672
1673 $classes = array_merge($classes, $this->get_additional_wrapper_classes($settings));
1674
1675 return array_filter($classes);
1676 }
1677
1678 /**
1679 * Get wrapper style attributes for CSS variables.
1680 *
1681 * @param array<string, mixed> $settings Widget settings.
1682 *
1683 * @return string
1684 */
1685 public function get_wrapper_style_attributes(array $settings): string
1686 {
1687 // CSS variables for pagination offset, pagination gap, and navigation gap
1688 // are now handled via Elementor selectors in the control definitions.
1689 // This ensures proper responsive behavior and avoids conflicts with
1690 // Elementor's built-in style handling.
1691 return '';
1692 }
1693
1694 /**
1695 * Render button element.
1696 *
1697 * @param string $text Button text.
1698 * @param array<string, mixed> $link Button link array.
1699 *
1700 * @return void
1701 */
1702 public function render_button(string $text, array $link): void
1703 {
1704 $url = $link['url'] ?? '';
1705 $rel = [];
1706
1707 if (!empty($link['nofollow'])) {
1708 $rel[] = 'nofollow';
1709 }
1710
1711 if (!empty($link['is_external'])) {
1712 $rel[] = 'noopener';
1713 $rel[] = 'noreferrer';
1714 }
1715
1716 $attributes = '';
1717
1718 if (!empty($url)) {
1719 $attributes .= ' href="' . esc_url($url) . '"';
1720 }
1721
1722 if (!empty($link['is_external'])) {
1723 $attributes .= ' target="_blank"';
1724 }
1725
1726 if (!empty($rel)) {
1727 $attributes .= ' rel="' . esc_attr(implode(' ', array_unique($rel))) . '"';
1728 }
1729
1730 ?>
1731 <a class="king-addons-card-slider__button"<?php echo $attributes; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped ?>>
1732 <?php echo esc_html($text); ?>
1733 </a>
1734 <?php
1735 }
1736
1737 /**
1738 * Get card image HTML.
1739 *
1740 * @param array<string, mixed> $card Card data.
1741 *
1742 * @return string
1743 */
1744 public function get_card_image(array $card): string
1745 {
1746 if (empty($card['kng_card_image']['id']) && empty($card['kng_card_image']['url'])) {
1747 return '';
1748 }
1749
1750 return Group_Control_Image_Size::get_attachment_image_html($card, 'kng_card_image');
1751 }
1752
1753 /**
1754 * Get slide classes.
1755 *
1756 * @param array<string, mixed> $card Card data.
1757 *
1758 * @return string
1759 */
1760 public function get_slide_classes(array $card): string
1761 {
1762 $classes = ['king-addons-card-slider__slide-inner'];
1763
1764 $classes = array_merge($classes, $this->get_additional_slide_classes($card));
1765
1766 return implode(' ', array_filter($classes));
1767 }
1768
1769 /**
1770 * Build data attributes for card-level navigation.
1771 *
1772 * @param bool $enabled Whether link is enabled.
1773 * @param array<string, mixed> $link Link data.
1774 *
1775 * @return string
1776 */
1777 public function get_card_link_attributes(bool $enabled, array $link): string
1778 {
1779 if (!$enabled || empty($link['url'])) {
1780 return '';
1781 }
1782
1783 $attrs = [
1784 'data-card-link' => esc_url_raw($link['url']),
1785 ];
1786
1787 if (!empty($link['is_external'])) {
1788 $attrs['data-card-link-target'] = '_blank';
1789 }
1790
1791 if (!empty($link['nofollow'])) {
1792 $attrs['data-card-link-rel'] = 'nofollow';
1793 }
1794
1795 $attributes = [];
1796 foreach ($attrs as $key => $value) {
1797 $attributes[] = esc_attr($key) . '="' . esc_attr((string) $value) . '"';
1798 }
1799
1800 return implode(' ', $attributes);
1801 }
1802
1803 /**
1804 * Format data attributes array into HTML attributes string.
1805 *
1806 * @param array<string, string|int> $attributes Attributes to format.
1807 *
1808 * @return string
1809 */
1810 public function format_data_attributes(array $attributes): string
1811 {
1812 $output = [];
1813
1814 foreach ($attributes as $key => $value) {
1815 $output[] = esc_attr($key) . '="' . esc_attr((string) $value) . '"';
1816 }
1817
1818 return implode(' ', $output);
1819 }
1820
1821 /**
1822 * Placeholder for additional wrapper classes (Pro overrides).
1823 *
1824 * @param array<string, mixed> $settings Widget settings.
1825 *
1826 * @return array<int, string>
1827 */
1828 public function get_additional_wrapper_classes(array $settings): array
1829 {
1830 unset($settings);
1831 return [];
1832 }
1833
1834 /**
1835 * Placeholder for additional slide classes (Pro overrides).
1836 *
1837 * @param array<string, mixed> $card Card data.
1838 *
1839 * @return array<int, string>
1840 */
1841 public function get_additional_slide_classes(array $card): array
1842 {
1843 unset($card);
1844 return [];
1845 }
1846
1847 /**
1848 * Placeholder for navigation pro controls.
1849 *
1850 * @return void
1851 */
1852 public function add_pro_navigation_controls(): void
1853 {
1854 // Premium navigation style controls are added in Pro.
1855 $this->add_control(
1856 'kng_navigation_skin',
1857 [
1858 'label' => sprintf(__('Arrow Style %s', 'king-addons'), '<i class="eicon-pro-icon"></i>'),
1859 'type' => Controls_Manager::SELECT,
1860 'default' => 'elevated',
1861 'options' => [
1862 'elevated' => esc_html__('Elevated', 'king-addons'),
1863 'pro-solid' => esc_html__('Solid (Pro)', 'king-addons'),
1864 'pro-ghost' => esc_html__('Ghost (Pro)', 'king-addons'),
1865 'pro-minimal' => esc_html__('Minimal (Pro)', 'king-addons'),
1866 ],
1867 'condition' => [
1868 'kng_show_navigation' => 'yes',
1869 ],
1870 ]
1871 );
1872 }
1873
1874 /**
1875 * Placeholder for pagination pro controls.
1876 *
1877 * @return void
1878 */
1879 public function add_pro_pagination_controls(): void
1880 {
1881 // Premium pagination style controls are added in Pro.
1882 $this->add_control(
1883 'kng_pagination_skin',
1884 [
1885 'label' => sprintf(__('Dots Style %s', 'king-addons'), '<i class="eicon-pro-icon"></i>'),
1886 'type' => Controls_Manager::SELECT,
1887 'default' => 'dot',
1888 'options' => [
1889 'dot' => esc_html__('Dots', 'king-addons'),
1890 'pro-pill' => esc_html__('Pill (Pro)', 'king-addons'),
1891 'pro-outlined' => esc_html__('Outlined (Pro)', 'king-addons'),
1892 ],
1893 'condition' => [
1894 'kng_show_pagination' => 'yes',
1895 ],
1896 ]
1897 );
1898 }
1899
1900 /**
1901 * Placeholder for rendering badges (Pro overrides).
1902 *
1903 * @param array<string, mixed> $card Card data.
1904 *
1905 * @return void
1906 */
1907 public function render_card_badge(array $card): void
1908 {
1909 unset($card);
1910 // Premium badge rendering is handled in Pro.
1911 }
1912
1913 /**
1914 * Register upgrade notice section for premium features.
1915 *
1916 * @return void
1917 */
1918 public function register_pro_notice_controls(): void
1919 {
1920 if (!king_addons_freemius()->can_use_premium_code__premium_only()) {
1921 Core::renderProFeaturesSection($this, '', Controls_Manager::RAW_HTML, 'quick-card-slider', [
1922 'Per-card badges and ribbons',
1923 'Advanced hover and entrance animations',
1924 'Navigation and pagination style presets',
1925 'Extended placement and offset controls',
1926 'Badge typography and color styling',
1927 ]);
1928 }
1929 }
1930 }
1931
1932
1933
1934
1935
1936
1937
1938
1939