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

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