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

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

1,323 lines 40.9 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * Interactive Image Sheen Widget (Free).
4 *
5 * Creates a premium "silk" sheen effect overlay on images/cards
6 * that activates on hover for a high-end product presentation.
7 *
8 * @package King_Addons
9 */
10
11 namespace King_Addons;
12
13 use Elementor\Controls_Manager;
14 use Elementor\Group_Control_Background;
15 use Elementor\Group_Control_Border;
16 use Elementor\Group_Control_Box_Shadow;
17 use Elementor\Group_Control_Image_Size;
18 use Elementor\Group_Control_Typography;
19 use Elementor\Plugin;
20 use Elementor\Utils;
21 use Elementor\Widget_Base;
22
23 if (!defined('ABSPATH')) {
24 exit;
25 }
26
27 /**
28 * Class Interactive_Image_Sheen
29 */
30 class Interactive_Image_Sheen extends Widget_Base
31 {
32 /**
33 * Get widget name.
34 *
35 * @return string
36 */
37 public function get_name(): string
38 {
39 return 'king-addons-interactive-image-sheen';
40 }
41
42 /**
43 * Get widget title.
44 *
45 * @return string
46 */
47 public function get_title(): string
48 {
49 return esc_html__('Interactive Image Sheen', 'king-addons');
50 }
51
52 /**
53 * Get widget icon.
54 *
55 * @return string
56 */
57 public function get_icon(): string
58 {
59 return 'king-addons-icon king-addons-interactive-image-sheen';
60 }
61
62 /**
63 * Get widget categories.
64 *
65 * @return array
66 */
67 public function get_categories(): array
68 {
69 return ['king-addons'];
70 }
71
72 /**
73 * Get widget keywords.
74 *
75 * @return array
76 */
77 public function get_keywords(): array
78 {
79 return [
80 'sheen',
81 'shine',
82 'gloss',
83 'hover',
84 'image',
85 'card',
86 'premium',
87 'silk',
88 'reflection',
89 'highlight',
90 'king addons',
91 'kingaddons',
92 'king-addons',
93 ];
94 }
95
96 /**
97 * Get style dependencies.
98 *
99 * @return array
100 */
101 public function get_style_depends(): array
102 {
103 return [KING_ADDONS_ASSETS_UNIQUE_KEY . '-interactive-image-sheen-style'];
104 }
105
106 /**
107 * Get script dependencies.
108 *
109 * @return array
110 */
111 public function get_script_depends(): array
112 {
113 return [KING_ADDONS_ASSETS_UNIQUE_KEY . '-interactive-image-sheen-script'];
114 }
115
116 /**
117 * Register widget controls.
118 *
119 * @return void
120 */
121 protected function register_controls(): void
122 {
123 // Content Tab
124 $this->register_content_source_controls();
125 $this->register_content_card_controls();
126 $this->register_content_sheen_controls();
127
128 // Pro notice
129 $this->register_pro_notice_controls();
130
131 // Style Tab
132 $this->register_style_container_controls();
133 $this->register_style_sheen_controls();
134 $this->register_style_card_controls();
135 $this->register_style_hover_controls();
136 }
137
138 /**
139 * Register source content controls.
140 *
141 * @return void
142 */
143 protected function register_content_source_controls(): void
144 {
145 $this->start_controls_section(
146 'kng_iis_source_section',
147 [
148 'label' => KING_ADDONS_ELEMENTOR_ICON . esc_html__('Source', 'king-addons'),
149 'tab' => Controls_Manager::TAB_CONTENT,
150 ]
151 );
152
153 $this->add_control(
154 'kng_iis_mode',
155 [
156 'label' => esc_html__('Mode', 'king-addons'),
157 'type' => Controls_Manager::SELECT,
158 'default' => 'image',
159 'options' => [
160 'image' => esc_html__('Image Only', 'king-addons'),
161 'card' => esc_html__('Card (Image + Content)', 'king-addons'),
162 ],
163 ]
164 );
165
166 $this->add_control(
167 'kng_iis_image',
168 [
169 'label' => esc_html__('Image', 'king-addons'),
170 'type' => Controls_Manager::MEDIA,
171 'default' => [
172 'url' => Utils::get_placeholder_image_src(),
173 ],
174 'dynamic' => ['active' => true],
175 ]
176 );
177
178 $this->add_group_control(
179 Group_Control_Image_Size::get_type(),
180 [
181 'name' => 'kng_iis_image_size',
182 'default' => 'large',
183 ]
184 );
185
186 $this->add_control(
187 'kng_iis_image_fit',
188 [
189 'label' => esc_html__('Image Fit', 'king-addons'),
190 'type' => Controls_Manager::SELECT,
191 'default' => 'cover',
192 'options' => [
193 'cover' => esc_html__('Cover', 'king-addons'),
194 'contain' => esc_html__('Contain', 'king-addons'),
195 'fill' => esc_html__('Fill', 'king-addons'),
196 'none' => esc_html__('None (Original)', 'king-addons'),
197 ],
198 'selectors' => [
199 '{{WRAPPER}} .kng-iis__image' => 'object-fit: {{VALUE}};',
200 ],
201 ]
202 );
203
204 $this->add_control(
205 'kng_iis_link',
206 [
207 'label' => esc_html__('Link', 'king-addons'),
208 'type' => Controls_Manager::URL,
209 'placeholder' => esc_html__('https://your-link.com', 'king-addons'),
210 'dynamic' => ['active' => true],
211 ]
212 );
213
214 $this->end_controls_section();
215 }
216
217 /**
218 * Register card content controls.
219 *
220 * @return void
221 */
222 protected function register_content_card_controls(): void
223 {
224 $this->start_controls_section(
225 'kng_iis_card_section',
226 [
227 'label' => KING_ADDONS_ELEMENTOR_ICON . esc_html__('Card Content', 'king-addons'),
228 'tab' => Controls_Manager::TAB_CONTENT,
229 'condition' => [
230 'kng_iis_mode' => 'card',
231 ],
232 ]
233 );
234
235 $this->add_control(
236 'kng_iis_card_title',
237 [
238 'label' => esc_html__('Title', 'king-addons'),
239 'type' => Controls_Manager::TEXT,
240 'default' => esc_html__('Card Title', 'king-addons'),
241 'label_block' => true,
242 'dynamic' => ['active' => true],
243 ]
244 );
245
246 $this->add_control(
247 'kng_iis_card_title_tag',
248 [
249 'label' => esc_html__('Title HTML Tag', 'king-addons'),
250 'type' => Controls_Manager::SELECT,
251 'default' => 'h3',
252 'options' => [
253 'h1' => 'H1',
254 'h2' => 'H2',
255 'h3' => 'H3',
256 'h4' => 'H4',
257 'h5' => 'H5',
258 'h6' => 'H6',
259 'p' => 'p',
260 'div' => 'div',
261 'span' => 'span',
262 ],
263 ]
264 );
265
266 $this->add_control(
267 'kng_iis_card_description',
268 [
269 'label' => esc_html__('Description', 'king-addons'),
270 'type' => Controls_Manager::TEXTAREA,
271 'default' => esc_html__('A short description for the card.', 'king-addons'),
272 'rows' => 3,
273 'dynamic' => ['active' => true],
274 ]
275 );
276
277 $this->add_control(
278 'kng_iis_card_button_heading',
279 [
280 'label' => esc_html__('Button', 'king-addons'),
281 'type' => Controls_Manager::HEADING,
282 'separator' => 'before',
283 ]
284 );
285
286 $this->add_control(
287 'kng_iis_card_button_show',
288 [
289 'label' => esc_html__('Show Button', 'king-addons'),
290 'type' => Controls_Manager::SWITCHER,
291 'default' => 'yes',
292 ]
293 );
294
295 $this->add_control(
296 'kng_iis_card_button_text',
297 [
298 'label' => esc_html__('Button Text', 'king-addons'),
299 'type' => Controls_Manager::TEXT,
300 'default' => esc_html__('Learn More', 'king-addons'),
301 'condition' => [
302 'kng_iis_card_button_show' => 'yes',
303 ],
304 ]
305 );
306
307 $this->add_control(
308 'kng_iis_card_button_link',
309 [
310 'label' => esc_html__('Button Link', 'king-addons'),
311 'type' => Controls_Manager::URL,
312 'placeholder' => esc_html__('https://your-link.com', 'king-addons'),
313 'dynamic' => ['active' => true],
314 'condition' => [
315 'kng_iis_card_button_show' => 'yes',
316 ],
317 ]
318 );
319
320 $this->add_control(
321 'kng_iis_card_layout',
322 [
323 'label' => esc_html__('Content Position', 'king-addons'),
324 'type' => Controls_Manager::SELECT,
325 'default' => 'below',
326 'separator' => 'before',
327 'options' => [
328 'below' => esc_html__('Below Image', 'king-addons'),
329 'overlay' => esc_html__('Overlay on Image', 'king-addons'),
330 ],
331 ]
332 );
333
334 $this->add_control(
335 'kng_iis_card_overlay_position',
336 [
337 'label' => esc_html__('Overlay Alignment', 'king-addons'),
338 'type' => Controls_Manager::CHOOSE,
339 'default' => 'bottom',
340 'options' => [
341 'top' => [
342 'title' => esc_html__('Top', 'king-addons'),
343 'icon' => 'eicon-v-align-top',
344 ],
345 'center' => [
346 'title' => esc_html__('Center', 'king-addons'),
347 'icon' => 'eicon-v-align-middle',
348 ],
349 'bottom' => [
350 'title' => esc_html__('Bottom', 'king-addons'),
351 'icon' => 'eicon-v-align-bottom',
352 ],
353 ],
354 'condition' => [
355 'kng_iis_card_layout' => 'overlay',
356 ],
357 ]
358 );
359
360 $this->end_controls_section();
361 }
362
363 /**
364 * Register sheen content controls.
365 *
366 * @return void
367 */
368 protected function register_content_sheen_controls(): void
369 {
370 $this->start_controls_section(
371 'kng_iis_sheen_section',
372 [
373 'label' => KING_ADDONS_ELEMENTOR_ICON . esc_html__('Sheen Settings', 'king-addons'),
374 'tab' => Controls_Manager::TAB_CONTENT,
375 ]
376 );
377
378 $this->add_control(
379 'kng_iis_sheen_preset',
380 [
381 'label' => esc_html__('Preset', 'king-addons'),
382 'type' => Controls_Manager::SELECT,
383 'default' => 'silk-soft',
384 'options' => [
385 'silk-soft' => esc_html__('Silk Soft (Wide & Subtle)', 'king-addons'),
386 'gloss-sharp' => esc_html__('Gloss Sharp (Narrow & Bright)', 'king-addons'),
387 'dual-streak' => esc_html__('Dual Streak (Two Lines)', 'king-addons'),
388 ],
389 ]
390 );
391
392 $this->add_control(
393 'kng_iis_sheen_angle',
394 [
395 'label' => esc_html__('Angle', 'king-addons'),
396 'type' => Controls_Manager::SLIDER,
397 'range' => [
398 'px' => ['min' => -90, 'max' => 90, 'step' => 1],
399 ],
400 'default' => ['size' => 25, 'unit' => 'px'],
401 'selectors' => [
402 '{{WRAPPER}} .kng-iis' => '--kng-iis-angle: {{SIZE}}deg;',
403 ],
404 ]
405 );
406
407 $this->add_control(
408 'kng_iis_sheen_intensity',
409 [
410 'label' => esc_html__('Intensity', 'king-addons'),
411 'type' => Controls_Manager::SLIDER,
412 'range' => [
413 'px' => ['min' => 0, 'max' => 100, 'step' => 1],
414 ],
415 'default' => ['size' => 60, 'unit' => 'px'],
416 'selectors' => [
417 '{{WRAPPER}} .kng-iis' => '--kng-iis-intensity: {{SIZE}};',
418 ],
419 ]
420 );
421
422 $this->add_control(
423 'kng_iis_sheen_duration',
424 [
425 'label' => esc_html__('Animation Duration (ms)', 'king-addons'),
426 'type' => Controls_Manager::SLIDER,
427 'range' => [
428 'px' => ['min' => 150, 'max' => 2000, 'step' => 50],
429 ],
430 'default' => ['size' => 600, 'unit' => 'px'],
431 'selectors' => [
432 '{{WRAPPER}} .kng-iis' => '--kng-iis-duration: {{SIZE}}ms;',
433 ],
434 ]
435 );
436
437 $this->add_control(
438 'kng_iis_sheen_easing',
439 [
440 'label' => esc_html__('Animation Easing', 'king-addons'),
441 'type' => Controls_Manager::SELECT,
442 'default' => 'ease-out',
443 'options' => [
444 'linear' => esc_html__('Linear', 'king-addons'),
445 'ease' => esc_html__('Ease', 'king-addons'),
446 'ease-in' => esc_html__('Ease In', 'king-addons'),
447 'ease-out' => esc_html__('Ease Out', 'king-addons'),
448 'ease-in-out' => esc_html__('Ease In-Out', 'king-addons'),
449 ],
450 'selectors' => [
451 '{{WRAPPER}} .kng-iis__sheen' => 'animation-timing-function: {{VALUE}};',
452 ],
453 ]
454 );
455
456 $this->add_control(
457 'kng_iis_sheen_direction',
458 [
459 'label' => esc_html__('Animation Direction', 'king-addons'),
460 'type' => Controls_Manager::SELECT,
461 'default' => 'left-right',
462 'options' => [
463 'left-right' => esc_html__('Left to Right', 'king-addons'),
464 'right-left' => esc_html__('Right to Left', 'king-addons'),
465 'top-bottom' => esc_html__('Top to Bottom', 'king-addons'),
466 'bottom-top' => esc_html__('Bottom to Top', 'king-addons'),
467 ],
468 ]
469 );
470
471 $this->add_control(
472 'kng_iis_sheen_repeat',
473 [
474 'label' => esc_html__('Animation Mode', 'king-addons'),
475 'type' => Controls_Manager::SELECT,
476 'default' => 'once',
477 'options' => [
478 'once' => esc_html__('Play Once on Hover', 'king-addons'),
479 'loop' => esc_html__('Loop While Hovering', 'king-addons'),
480 ],
481 ]
482 );
483
484 $this->add_control(
485 'kng_iis_sheen_trigger',
486 [
487 'label' => esc_html__('Trigger', 'king-addons'),
488 'type' => Controls_Manager::SELECT,
489 'default' => 'hover',
490 'options' => [
491 'hover' => esc_html__('On Hover', 'king-addons'),
492 'always' => esc_html__('Always Playing', 'king-addons'),
493 ],
494 ]
495 );
496
497 $this->end_controls_section();
498 }
499
500 /**
501 * Register Pro features notice.
502 *
503 * @return void
504 */
505 protected function register_pro_notice_controls(): void
506 {
507 if (!$this->is_pro_enabled()) {
508 Core::renderProFeaturesSection($this, '', Controls_Manager::RAW_HTML, 'interactive-image-sheen', [
509 'Follow cursor (sheen follows mouse)',
510 'Layered sheen (2-3 layers)',
511 'Mask by shape (circle, rounded rect)',
512 'Mobile fallback controls',
513 'Per-layer opacity & size',
514 ]);
515 }
516 }
517
518 /**
519 * Register container style controls.
520 *
521 * @return void
522 */
523 protected function register_style_container_controls(): void
524 {
525 $this->start_controls_section(
526 'kng_iis_style_container_section',
527 [
528 'label' => KING_ADDONS_ELEMENTOR_ICON . esc_html__('Container', 'king-addons'),
529 'tab' => Controls_Manager::TAB_STYLE,
530 ]
531 );
532
533 $this->add_responsive_control(
534 'kng_iis_container_width',
535 [
536 'label' => esc_html__('Width', 'king-addons'),
537 'type' => Controls_Manager::SLIDER,
538 'size_units' => ['px', '%', 'vw'],
539 'range' => [
540 'px' => ['min' => 100, 'max' => 1200],
541 '%' => ['min' => 10, 'max' => 100],
542 'vw' => ['min' => 10, 'max' => 100],
543 ],
544 'selectors' => [
545 '{{WRAPPER}} .kng-iis' => 'width: {{SIZE}}{{UNIT}};',
546 ],
547 ]
548 );
549
550 $this->add_responsive_control(
551 'kng_iis_container_height',
552 [
553 'label' => esc_html__('Height', 'king-addons'),
554 'type' => Controls_Manager::SLIDER,
555 'size_units' => ['px', 'vh'],
556 'range' => [
557 'px' => ['min' => 100, 'max' => 800],
558 'vh' => ['min' => 10, 'max' => 100],
559 ],
560 'selectors' => [
561 '{{WRAPPER}} .kng-iis__media' => 'height: {{SIZE}}{{UNIT}};',
562 ],
563 ]
564 );
565
566 $this->add_responsive_control(
567 'kng_iis_container_radius',
568 [
569 'label' => esc_html__('Border Radius', 'king-addons'),
570 'type' => Controls_Manager::DIMENSIONS,
571 'size_units' => ['px', '%'],
572 'selectors' => [
573 '{{WRAPPER}} .kng-iis' => 'border-radius: {{TOP}}{{UNIT}} {{RIGHT}}{{UNIT}} {{BOTTOM}}{{UNIT}} {{LEFT}}{{UNIT}};',
574 '{{WRAPPER}} .kng-iis__media' => 'border-radius: {{TOP}}{{UNIT}} {{RIGHT}}{{UNIT}} {{BOTTOM}}{{UNIT}} {{LEFT}}{{UNIT}};',
575 ],
576 ]
577 );
578
579 $this->add_group_control(
580 Group_Control_Border::get_type(),
581 [
582 'name' => 'kng_iis_container_border',
583 'selector' => '{{WRAPPER}} .kng-iis',
584 ]
585 );
586
587 $this->add_group_control(
588 Group_Control_Box_Shadow::get_type(),
589 [
590 'name' => 'kng_iis_container_shadow',
591 'selector' => '{{WRAPPER}} .kng-iis',
592 ]
593 );
594
595 $this->add_group_control(
596 Group_Control_Background::get_type(),
597 [
598 'name' => 'kng_iis_container_bg',
599 'types' => ['classic', 'gradient'],
600 'selector' => '{{WRAPPER}} .kng-iis',
601 'condition' => [
602 'kng_iis_mode' => 'card',
603 ],
604 ]
605 );
606
607 $this->end_controls_section();
608 }
609
610 /**
611 * Register sheen style controls.
612 *
613 * @return void
614 */
615 protected function register_style_sheen_controls(): void
616 {
617 $this->start_controls_section(
618 'kng_iis_style_sheen_section',
619 [
620 'label' => KING_ADDONS_ELEMENTOR_ICON . esc_html__('Sheen', 'king-addons'),
621 'tab' => Controls_Manager::TAB_STYLE,
622 ]
623 );
624
625 $this->add_control(
626 'kng_iis_sheen_color',
627 [
628 'label' => esc_html__('Sheen Color', 'king-addons'),
629 'type' => Controls_Manager::COLOR,
630 'default' => '#ffffff',
631 'selectors' => [
632 '{{WRAPPER}} .kng-iis' => '--kng-iis-sheen-color: {{VALUE}};',
633 ],
634 ]
635 );
636
637 $this->add_control(
638 'kng_iis_sheen_opacity',
639 [
640 'label' => esc_html__('Base Opacity', 'king-addons'),
641 'type' => Controls_Manager::SLIDER,
642 'range' => [
643 'px' => ['min' => 0, 'max' => 1, 'step' => 0.05],
644 ],
645 'default' => ['size' => 0.6],
646 'selectors' => [
647 '{{WRAPPER}} .kng-iis' => '--kng-iis-sheen-opacity: {{SIZE}};',
648 ],
649 ]
650 );
651
652 $this->add_control(
653 'kng_iis_sheen_softness',
654 [
655 'label' => esc_html__('Gradient Softness', 'king-addons'),
656 'type' => Controls_Manager::SLIDER,
657 'range' => [
658 'px' => ['min' => 0, 'max' => 100, 'step' => 1],
659 ],
660 'default' => ['size' => 30],
661 'selectors' => [
662 '{{WRAPPER}} .kng-iis' => '--kng-iis-softness: {{SIZE}}%;',
663 ],
664 ]
665 );
666
667 $this->add_control(
668 'kng_iis_sheen_width',
669 [
670 'label' => esc_html__('Sheen Width', 'king-addons'),
671 'type' => Controls_Manager::SLIDER,
672 'range' => [
673 'px' => ['min' => 10, 'max' => 100, 'step' => 1],
674 ],
675 'default' => ['size' => 50],
676 'selectors' => [
677 '{{WRAPPER}} .kng-iis' => '--kng-iis-sheen-width: {{SIZE}}%;',
678 ],
679 ]
680 );
681
682 $this->end_controls_section();
683 }
684
685 /**
686 * Register card style controls.
687 *
688 * @return void
689 */
690 protected function register_style_card_controls(): void
691 {
692 $this->start_controls_section(
693 'kng_iis_style_card_section',
694 [
695 'label' => KING_ADDONS_ELEMENTOR_ICON . esc_html__('Card Content', 'king-addons'),
696 'tab' => Controls_Manager::TAB_STYLE,
697 'condition' => [
698 'kng_iis_mode' => 'card',
699 ],
700 ]
701 );
702
703 $this->add_responsive_control(
704 'kng_iis_card_padding',
705 [
706 'label' => esc_html__('Padding', 'king-addons'),
707 'type' => Controls_Manager::DIMENSIONS,
708 'size_units' => ['px', 'em'],
709 'selectors' => [
710 '{{WRAPPER}} .kng-iis__content' => 'padding: {{TOP}}{{UNIT}} {{RIGHT}}{{UNIT}} {{BOTTOM}}{{UNIT}} {{LEFT}}{{UNIT}};',
711 ],
712 ]
713 );
714
715 $this->add_control(
716 'kng_iis_card_text_align',
717 [
718 'label' => esc_html__('Text Alignment', 'king-addons'),
719 'type' => Controls_Manager::CHOOSE,
720 'default' => 'left',
721 'options' => [
722 'left' => [
723 'title' => esc_html__('Left', 'king-addons'),
724 'icon' => 'eicon-text-align-left',
725 ],
726 'center' => [
727 'title' => esc_html__('Center', 'king-addons'),
728 'icon' => 'eicon-text-align-center',
729 ],
730 'right' => [
731 'title' => esc_html__('Right', 'king-addons'),
732 'icon' => 'eicon-text-align-right',
733 ],
734 ],
735 'selectors' => [
736 '{{WRAPPER}} .kng-iis__content' => 'text-align: {{VALUE}};',
737 ],
738 ]
739 );
740
741 // Title
742 $this->add_control(
743 'kng_iis_card_title_heading',
744 [
745 'label' => esc_html__('Title', 'king-addons'),
746 'type' => Controls_Manager::HEADING,
747 'separator' => 'before',
748 ]
749 );
750
751 $this->add_group_control(
752 Group_Control_Typography::get_type(),
753 [
754 'name' => 'kng_iis_card_title_typography',
755 'selector' => '{{WRAPPER}} .kng-iis__title',
756 ]
757 );
758
759 $this->add_control(
760 'kng_iis_card_title_color',
761 [
762 'label' => esc_html__('Title Color', 'king-addons'),
763 'type' => Controls_Manager::COLOR,
764 'selectors' => [
765 '{{WRAPPER}} .kng-iis__title' => 'color: {{VALUE}};',
766 ],
767 ]
768 );
769
770 $this->add_responsive_control(
771 'kng_iis_card_title_spacing',
772 [
773 'label' => esc_html__('Title Spacing', 'king-addons'),
774 'type' => Controls_Manager::SLIDER,
775 'size_units' => ['px'],
776 'range' => [
777 'px' => ['min' => 0, 'max' => 40],
778 ],
779 'selectors' => [
780 '{{WRAPPER}} .kng-iis__title' => 'margin-bottom: {{SIZE}}{{UNIT}};',
781 ],
782 ]
783 );
784
785 // Description
786 $this->add_control(
787 'kng_iis_card_desc_heading',
788 [
789 'label' => esc_html__('Description', 'king-addons'),
790 'type' => Controls_Manager::HEADING,
791 'separator' => 'before',
792 ]
793 );
794
795 $this->add_group_control(
796 Group_Control_Typography::get_type(),
797 [
798 'name' => 'kng_iis_card_desc_typography',
799 'selector' => '{{WRAPPER}} .kng-iis__description',
800 ]
801 );
802
803 $this->add_control(
804 'kng_iis_card_desc_color',
805 [
806 'label' => esc_html__('Description Color', 'king-addons'),
807 'type' => Controls_Manager::COLOR,
808 'selectors' => [
809 '{{WRAPPER}} .kng-iis__description' => 'color: {{VALUE}};',
810 ],
811 ]
812 );
813
814 $this->add_responsive_control(
815 'kng_iis_card_desc_spacing',
816 [
817 'label' => esc_html__('Description Spacing', 'king-addons'),
818 'type' => Controls_Manager::SLIDER,
819 'size_units' => ['px'],
820 'range' => [
821 'px' => ['min' => 0, 'max' => 40],
822 ],
823 'selectors' => [
824 '{{WRAPPER}} .kng-iis__description' => 'margin-bottom: {{SIZE}}{{UNIT}};',
825 ],
826 ]
827 );
828
829 // Button
830 $this->add_control(
831 'kng_iis_card_button_heading_style',
832 [
833 'label' => esc_html__('Button', 'king-addons'),
834 'type' => Controls_Manager::HEADING,
835 'separator' => 'before',
836 'condition' => [
837 'kng_iis_card_button_show' => 'yes',
838 ],
839 ]
840 );
841
842 $this->add_group_control(
843 Group_Control_Typography::get_type(),
844 [
845 'name' => 'kng_iis_card_button_typography',
846 'selector' => '{{WRAPPER}} .kng-iis__button',
847 'condition' => [
848 'kng_iis_card_button_show' => 'yes',
849 ],
850 ]
851 );
852
853 $this->start_controls_tabs(
854 'kng_iis_card_button_tabs',
855 [
856 'condition' => [
857 'kng_iis_card_button_show' => 'yes',
858 ],
859 ]
860 );
861
862 $this->start_controls_tab(
863 'kng_iis_card_button_normal',
864 ['label' => esc_html__('Normal', 'king-addons')]
865 );
866
867 $this->add_control(
868 'kng_iis_card_button_color',
869 [
870 'label' => esc_html__('Text Color', 'king-addons'),
871 'type' => Controls_Manager::COLOR,
872 'selectors' => [
873 '{{WRAPPER}} .kng-iis__button' => 'color: {{VALUE}};',
874 ],
875 ]
876 );
877
878 $this->add_control(
879 'kng_iis_card_button_bg',
880 [
881 'label' => esc_html__('Background', 'king-addons'),
882 'type' => Controls_Manager::COLOR,
883 'selectors' => [
884 '{{WRAPPER}} .kng-iis__button' => 'background-color: {{VALUE}};',
885 ],
886 ]
887 );
888
889 $this->end_controls_tab();
890
891 $this->start_controls_tab(
892 'kng_iis_card_button_hover',
893 ['label' => esc_html__('Hover', 'king-addons')]
894 );
895
896 $this->add_control(
897 'kng_iis_card_button_hover_color',
898 [
899 'label' => esc_html__('Text Color', 'king-addons'),
900 'type' => Controls_Manager::COLOR,
901 'selectors' => [
902 '{{WRAPPER}} .kng-iis__button:hover' => 'color: {{VALUE}};',
903 ],
904 ]
905 );
906
907 $this->add_control(
908 'kng_iis_card_button_hover_bg',
909 [
910 'label' => esc_html__('Background', 'king-addons'),
911 'type' => Controls_Manager::COLOR,
912 'selectors' => [
913 '{{WRAPPER}} .kng-iis__button:hover' => 'background-color: {{VALUE}};',
914 ],
915 ]
916 );
917
918 $this->end_controls_tab();
919
920 $this->end_controls_tabs();
921
922 $this->add_responsive_control(
923 'kng_iis_card_button_padding',
924 [
925 'label' => esc_html__('Button Padding', 'king-addons'),
926 'type' => Controls_Manager::DIMENSIONS,
927 'size_units' => ['px', 'em'],
928 'separator' => 'before',
929 'selectors' => [
930 '{{WRAPPER}} .kng-iis__button' => 'padding: {{TOP}}{{UNIT}} {{RIGHT}}{{UNIT}} {{BOTTOM}}{{UNIT}} {{LEFT}}{{UNIT}};',
931 ],
932 'condition' => [
933 'kng_iis_card_button_show' => 'yes',
934 ],
935 ]
936 );
937
938 $this->add_responsive_control(
939 'kng_iis_card_button_radius',
940 [
941 'label' => esc_html__('Button Border Radius', 'king-addons'),
942 'type' => Controls_Manager::DIMENSIONS,
943 'size_units' => ['px'],
944 'selectors' => [
945 '{{WRAPPER}} .kng-iis__button' => 'border-radius: {{TOP}}{{UNIT}} {{RIGHT}}{{UNIT}} {{BOTTOM}}{{UNIT}} {{LEFT}}{{UNIT}};',
946 ],
947 'condition' => [
948 'kng_iis_card_button_show' => 'yes',
949 ],
950 ]
951 );
952
953 $this->add_group_control(
954 Group_Control_Border::get_type(),
955 [
956 'name' => 'kng_iis_card_button_border',
957 'selector' => '{{WRAPPER}} .kng-iis__button',
958 'condition' => [
959 'kng_iis_card_button_show' => 'yes',
960 ],
961 ]
962 );
963
964 $this->end_controls_section();
965
966 // =====================================================================
967 // Style: Overlay Background (for Card mode)
968 // =====================================================================
969 $this->start_controls_section(
970 'kng_iis_style_overlay_section',
971 [
972 'label' => KING_ADDONS_ELEMENTOR_ICON . esc_html__('Overlay Background', 'king-addons'),
973 'tab' => Controls_Manager::TAB_STYLE,
974 'condition' => [
975 'kng_iis_mode' => 'card',
976 'kng_iis_card_layout' => 'overlay',
977 ],
978 ]
979 );
980
981 $this->add_group_control(
982 Group_Control_Background::get_type(),
983 [
984 'name' => 'kng_iis_overlay_bg',
985 'types' => ['classic', 'gradient'],
986 'selector' => '{{WRAPPER}} .kng-iis__content--overlay',
987 ]
988 );
989
990 $this->add_responsive_control(
991 'kng_iis_overlay_opacity',
992 [
993 'label' => esc_html__('Background Opacity', 'king-addons'),
994 'type' => Controls_Manager::SLIDER,
995 'range' => [
996 'px' => ['min' => 0, 'max' => 1, 'step' => 0.05],
997 ],
998 'selectors' => [
999 '{{WRAPPER}} .kng-iis__content--overlay' => 'background-color: rgba(0, 0, 0, {{SIZE}});',
1000 ],
1001 'condition' => [
1002 'kng_iis_overlay_bg_background' => '',
1003 ],
1004 ]
1005 );
1006
1007 $this->end_controls_section();
1008 }
1009
1010 /**
1011 * Register hover state style controls.
1012 *
1013 * @return void
1014 */
1015 protected function register_style_hover_controls(): void
1016 {
1017 $this->start_controls_section(
1018 'kng_iis_style_hover_section',
1019 [
1020 'label' => KING_ADDONS_ELEMENTOR_ICON . esc_html__('Hover Effects', 'king-addons'),
1021 'tab' => Controls_Manager::TAB_STYLE,
1022 ]
1023 );
1024
1025 $this->add_control(
1026 'kng_iis_hover_scale',
1027 [
1028 'label' => esc_html__('Scale on Hover', 'king-addons'),
1029 'type' => Controls_Manager::SWITCHER,
1030 'default' => '',
1031 ]
1032 );
1033
1034 $this->add_control(
1035 'kng_iis_hover_scale_value',
1036 [
1037 'label' => esc_html__('Scale Amount', 'king-addons'),
1038 'type' => Controls_Manager::SLIDER,
1039 'range' => [
1040 'px' => ['min' => 1, 'max' => 1.2, 'step' => 0.01],
1041 ],
1042 'default' => ['size' => 1.03],
1043 'selectors' => [
1044 '{{WRAPPER}} .kng-iis:hover .kng-iis__media' => 'transform: scale({{SIZE}});',
1045 ],
1046 'condition' => [
1047 'kng_iis_hover_scale' => 'yes',
1048 ],
1049 ]
1050 );
1051
1052 $this->add_control(
1053 'kng_iis_hover_shadow',
1054 [
1055 'label' => esc_html__('Increase Shadow on Hover', 'king-addons'),
1056 'type' => Controls_Manager::SWITCHER,
1057 'default' => '',
1058 ]
1059 );
1060
1061 $this->add_group_control(
1062 Group_Control_Box_Shadow::get_type(),
1063 [
1064 'name' => 'kng_iis_hover_shadow_value',
1065 'selector' => '{{WRAPPER}} .kng-iis:hover',
1066 'condition' => [
1067 'kng_iis_hover_shadow' => 'yes',
1068 ],
1069 ]
1070 );
1071
1072 $this->end_controls_section();
1073 }
1074
1075 /**
1076 * Render widget output.
1077 *
1078 * @return void
1079 */
1080 protected function render(): void
1081 {
1082 $settings = $this->get_settings_for_display();
1083
1084 $mode = $settings['kng_iis_mode'] ?? 'image';
1085 $preset = $settings['kng_iis_sheen_preset'] ?? 'silk-soft';
1086 $repeat = $settings['kng_iis_sheen_repeat'] ?? 'once';
1087 $trigger = $settings['kng_iis_sheen_trigger'] ?? 'hover';
1088
1089 $wrapper_classes = $this->get_wrapper_classes($settings);
1090 $data_settings = $this->get_data_settings($settings);
1091
1092 $this->add_render_attribute('wrapper', [
1093 'class' => implode(' ', $wrapper_classes),
1094 'data-settings' => wp_json_encode($data_settings),
1095 ]);
1096
1097 $link = $settings['kng_iis_link'] ?? [];
1098 $has_wrapper_link = !empty($link['url']) && 'image' === $mode;
1099
1100 echo '<div ' . $this->get_render_attribute_string('wrapper') . '>';
1101
1102 // Sheen overlay
1103 echo '<div class="kng-iis__sheen" aria-hidden="true"></div>';
1104
1105 // Media container
1106 $this->render_media($settings, $has_wrapper_link);
1107
1108 // Card content
1109 if ('card' === $mode) {
1110 $this->render_card_content($settings);
1111 }
1112
1113 echo '</div>';
1114 }
1115
1116 /**
1117 * Render media (image).
1118 *
1119 * @param array $settings Widget settings.
1120 * @param bool $has_link Whether image has a link.
1121 * @return void
1122 */
1123 protected function render_media(array $settings, bool $has_link): void
1124 {
1125 $image = $settings['kng_iis_image'] ?? [];
1126 $image_url = Group_Control_Image_Size::get_attachment_image_src(
1127 $image['id'] ?? 0,
1128 'kng_iis_image_size',
1129 $settings
1130 );
1131
1132 if (empty($image_url)) {
1133 $image_url = $image['url'] ?? Utils::get_placeholder_image_src();
1134 }
1135
1136 $link = $settings['kng_iis_link'] ?? [];
1137
1138 echo '<div class="kng-iis__media">';
1139
1140 if ($has_link && !empty($link['url'])) {
1141 $link_attrs = $this->get_link_attributes($link);
1142 echo '<a ' . $link_attrs . ' class="kng-iis__link">';
1143 }
1144
1145 echo '<img src="' . esc_url($image_url) . '" alt="" class="kng-iis__image" loading="lazy">';
1146
1147 if ($has_link && !empty($link['url'])) {
1148 echo '</a>';
1149 }
1150
1151 echo '</div>';
1152 }
1153
1154 /**
1155 * Render card content.
1156 *
1157 * @param array $settings Widget settings.
1158 * @return void
1159 */
1160 protected function render_card_content(array $settings): void
1161 {
1162 $title = $settings['kng_iis_card_title'] ?? '';
1163 $title_tag = $settings['kng_iis_card_title_tag'] ?? 'h3';
1164 $description = $settings['kng_iis_card_description'] ?? '';
1165 $layout = $settings['kng_iis_card_layout'] ?? 'below';
1166 $position = $settings['kng_iis_card_overlay_position'] ?? 'bottom';
1167 $show_button = 'yes' === ($settings['kng_iis_card_button_show'] ?? '');
1168
1169 $content_classes = ['kng-iis__content'];
1170 if ('overlay' === $layout) {
1171 $content_classes[] = 'kng-iis__content--overlay';
1172 $content_classes[] = 'kng-iis__content--' . $position;
1173 }
1174
1175 echo '<div class="' . esc_attr(implode(' ', $content_classes)) . '">';
1176
1177 // Title
1178 if (!empty($title)) {
1179 $allowed_tags = ['h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'p', 'div', 'span'];
1180 $title_tag = in_array($title_tag, $allowed_tags, true) ? $title_tag : 'h3';
1181 echo '<' . esc_attr($title_tag) . ' class="kng-iis__title">' . esc_html($title) . '</' . esc_attr($title_tag) . '>';
1182 }
1183
1184 // Description
1185 if (!empty($description)) {
1186 echo '<p class="kng-iis__description">' . esc_html($description) . '</p>';
1187 }
1188
1189 // Button
1190 if ($show_button) {
1191 $this->render_button($settings);
1192 }
1193
1194 echo '</div>';
1195 }
1196
1197 /**
1198 * Render button.
1199 *
1200 * @param array $settings Widget settings.
1201 * @return void
1202 */
1203 protected function render_button(array $settings): void
1204 {
1205 $button_text = $settings['kng_iis_card_button_text'] ?? '';
1206 $button_link = $settings['kng_iis_card_button_link'] ?? [];
1207
1208 if (empty($button_text)) {
1209 return;
1210 }
1211
1212 $tag = 'span';
1213 $attrs = '';
1214
1215 if (!empty($button_link['url'])) {
1216 $tag = 'a';
1217 $attrs = $this->get_link_attributes($button_link);
1218 }
1219
1220 echo '<' . esc_attr($tag) . ' ' . $attrs . ' class="kng-iis__button">' . esc_html($button_text) . '</' . esc_attr($tag) . '>';
1221 }
1222
1223 /**
1224 * Get wrapper CSS classes.
1225 *
1226 * @param array $settings Widget settings.
1227 * @return array
1228 */
1229 protected function get_wrapper_classes(array $settings): array
1230 {
1231 $classes = ['kng-iis'];
1232
1233 $mode = $settings['kng_iis_mode'] ?? 'image';
1234 $classes[] = 'kng-iis--mode-' . $mode;
1235
1236 $preset = $settings['kng_iis_sheen_preset'] ?? 'silk-soft';
1237 $classes[] = 'kng-iis--preset-' . $preset;
1238
1239 $repeat = $settings['kng_iis_sheen_repeat'] ?? 'once';
1240 $classes[] = 'kng-iis--repeat-' . $repeat;
1241
1242 $trigger = $settings['kng_iis_sheen_trigger'] ?? 'hover';
1243 $classes[] = 'kng-iis--trigger-' . $trigger;
1244
1245 $direction = $settings['kng_iis_sheen_direction'] ?? 'left-right';
1246 $classes[] = 'kng-iis--direction-' . $direction;
1247
1248 if ($this->is_pro_enabled()) {
1249 $classes[] = 'kng-iis--pro';
1250 }
1251
1252 return $classes;
1253 }
1254
1255 /**
1256 * Get data settings for JS.
1257 *
1258 * @param array $settings Widget settings.
1259 * @return array
1260 */
1261 protected function get_data_settings(array $settings): array
1262 {
1263 return [
1264 'preset' => $settings['kng_iis_sheen_preset'] ?? 'silk-soft',
1265 'trigger' => $settings['kng_iis_sheen_trigger'] ?? 'hover',
1266 'repeat' => $settings['kng_iis_sheen_repeat'] ?? 'once',
1267 ];
1268 }
1269
1270 /**
1271 * Get link attributes string.
1272 *
1273 * @param array $link Link data.
1274 * @return string
1275 */
1276 protected function get_link_attributes(array $link): string
1277 {
1278 if (empty($link['url'])) {
1279 return '';
1280 }
1281
1282 $attributes = [
1283 'href' => esc_url($link['url']),
1284 ];
1285
1286 if (!empty($link['is_external'])) {
1287 $attributes['target'] = '_blank';
1288 $attributes['rel'] = 'noopener noreferrer';
1289 }
1290
1291 if (!empty($link['nofollow'])) {
1292 $attributes['rel'] = isset($attributes['rel']) ? $attributes['rel'] . ' nofollow' : 'nofollow';
1293 }
1294
1295 $output = [];
1296 foreach ($attributes as $key => $value) {
1297 $output[] = esc_attr($key) . '="' . esc_attr((string) $value) . '"';
1298 }
1299
1300 return implode(' ', $output);
1301 }
1302
1303 /**
1304 * Check if Pro features are enabled.
1305 *
1306 * @return bool
1307 */
1308 protected function is_pro_enabled(): bool
1309 {
1310 return function_exists('king_addons_freemius') && king_addons_freemius()->can_use_premium_code__premium_only();
1311 }
1312
1313 /**
1314 * Check if in editor mode.
1315 *
1316 * @return bool
1317 */
1318 protected function is_editor(): bool
1319 {
1320 return class_exists(Plugin::class) && Plugin::$instance->editor->is_edit_mode();
1321 }
1322 }
1323