PluginProbe
Elementor Website Builder – more than just a page builder / 3.13.1
Elementor Website Builder – more than just a page builder v3.13.1
4.3.0-beta2 4.3.0-beta1 4.2.4 4.2.3 4.2.2 4.2.1 4.2.0 4.1.5 4.2.0-beta2 4.2.0-dev2 4.2.0-beta1 4.1.4 4.1.3 4.1.2 4.1.1 4.1.0 4.1.0-beta3 4.1.0-dev3 4.0.9 4.1.0-beta2 4.1.0-dev2 4.0.8 4.1.0-beta1 4.1.0-dev1 4.0.7 All 451 releases
elementor / includes / widgets / image-carousel.php

image-carousel.php in Elementor Website Builder – more than just a page builder 3.13.1, at includes/widgets/image-carousel.php

1,030 lines 24.8 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 namespace Elementor;
3
4 if ( ! defined( 'ABSPATH' ) ) {
5 exit; // Exit if accessed directly.
6 }
7
8 use Elementor\Core\Kits\Documents\Tabs\Global_Colors;
9
10 /**
11 * Elementor image carousel widget.
12 *
13 * Elementor widget that displays a set of images in a rotating carousel or
14 * slider.
15 *
16 * @since 1.0.0
17 */
18 class Widget_Image_Carousel extends Widget_Base {
19
20 /**
21 * Get widget name.
22 *
23 * Retrieve image carousel widget name.
24 *
25 * @since 1.0.0
26 * @access public
27 *
28 * @return string Widget name.
29 */
30 public function get_name() {
31 return 'image-carousel';
32 }
33
34 /**
35 * Get widget title.
36 *
37 * Retrieve image carousel widget title.
38 *
39 * @since 1.0.0
40 * @access public
41 *
42 * @return string Widget title.
43 */
44 public function get_title() {
45 return esc_html__( 'Image Carousel', 'elementor' );
46 }
47
48 /**
49 * Get widget icon.
50 *
51 * Retrieve image carousel widget icon.
52 *
53 * @since 1.0.0
54 * @access public
55 *
56 * @return string Widget icon.
57 */
58 public function get_icon() {
59 return 'eicon-slider-push';
60 }
61
62 /**
63 * Get widget keywords.
64 *
65 * Retrieve the list of keywords the widget belongs to.
66 *
67 * @since 2.1.0
68 * @access public
69 *
70 * @return array Widget keywords.
71 */
72 public function get_keywords() {
73 return [ 'image', 'photo', 'visual', 'carousel', 'slider' ];
74 }
75
76 /**
77 * Register image carousel widget controls.
78 *
79 * Adds different input fields to allow the user to change and customize the widget settings.
80 *
81 * @since 3.1.0
82 * @access protected
83 */
84 protected function register_controls() {
85 $this->start_controls_section(
86 'section_image_carousel',
87 [
88 'label' => esc_html__( 'Image Carousel', 'elementor' ),
89 ]
90 );
91
92 $this->add_control(
93 'carousel',
94 [
95 'label' => esc_html__( 'Add Images', 'elementor' ),
96 'type' => Controls_Manager::GALLERY,
97 'default' => [],
98 'show_label' => false,
99 'dynamic' => [
100 'active' => true,
101 ],
102 ]
103 );
104
105 $this->add_group_control(
106 Group_Control_Image_Size::get_type(),
107 [
108 'name' => 'thumbnail', // Usage: `{name}_size` and `{name}_custom_dimension`, in this case `thumbnail_size` and `thumbnail_custom_dimension`.
109 'separator' => 'none',
110 ]
111 );
112
113 $slides_to_show = range( 1, 10 );
114 $slides_to_show = array_combine( $slides_to_show, $slides_to_show );
115
116 $this->add_responsive_control(
117 'slides_to_show',
118 [
119 'label' => esc_html__( 'Slides to Show', 'elementor' ),
120 'type' => Controls_Manager::SELECT,
121 'options' => [
122 '' => esc_html__( 'Default', 'elementor' ),
123 ] + $slides_to_show,
124 'frontend_available' => true,
125 'render_type' => 'template',
126 'selectors' => [
127 '{{WRAPPER}}' => '--e-image-carousel-slides-to-show: {{VALUE}}',
128 ],
129 ]
130 );
131
132 $this->add_responsive_control(
133 'slides_to_scroll',
134 [
135 'label' => esc_html__( 'Slides to Scroll', 'elementor' ),
136 'type' => Controls_Manager::SELECT,
137 'description' => esc_html__( 'Set how many slides are scrolled per swipe.', 'elementor' ),
138 'options' => [
139 '' => esc_html__( 'Default', 'elementor' ),
140 ] + $slides_to_show,
141 'condition' => [
142 'slides_to_show!' => '1',
143 ],
144 'frontend_available' => true,
145 ]
146 );
147
148 $this->add_control(
149 'image_stretch',
150 [
151 'label' => esc_html__( 'Image Stretch', 'elementor' ),
152 'type' => Controls_Manager::SELECT,
153 'default' => 'no',
154 'options' => [
155 'no' => esc_html__( 'No', 'elementor' ),
156 'yes' => esc_html__( 'Yes', 'elementor' ),
157 ],
158 ]
159 );
160
161 $this->add_control(
162 'navigation',
163 [
164 'label' => esc_html__( 'Navigation', 'elementor' ),
165 'type' => Controls_Manager::SELECT,
166 'default' => 'both',
167 'options' => [
168 'both' => esc_html__( 'Arrows and Dots', 'elementor' ),
169 'arrows' => esc_html__( 'Arrows', 'elementor' ),
170 'dots' => esc_html__( 'Dots', 'elementor' ),
171 'none' => esc_html__( 'None', 'elementor' ),
172 ],
173 'frontend_available' => true,
174 ]
175 );
176
177 $this->add_control(
178 'navigation_previous_icon',
179 [
180 'label' => esc_html__( 'Previous Arrow Icon', 'elementor' ),
181 'type' => Controls_Manager::ICONS,
182 'fa4compatibility' => 'icon',
183 'skin' => 'inline',
184 'label_block' => false,
185 'skin_settings' => [
186 'inline' => [
187 'none' => [
188 'label' => 'Default',
189 'icon' => 'eicon-chevron-left',
190 ],
191 'icon' => [
192 'icon' => 'eicon-star',
193 ],
194 ],
195 ],
196 'recommended' => [
197 'fa-regular' => [
198 'arrow-alt-circle-left',
199 'caret-square-left',
200 ],
201 'fa-solid' => [
202 'angle-double-left',
203 'angle-left',
204 'arrow-alt-circle-left',
205 'arrow-circle-left',
206 'arrow-left',
207 'caret-left',
208 'caret-square-left',
209 'chevron-circle-left',
210 'chevron-left',
211 'long-arrow-alt-left',
212 ],
213 ],
214 'conditions' => [
215 'relation' => 'or',
216 'terms' => [
217 [
218 'name' => 'navigation',
219 'operator' => '=',
220 'value' => 'both',
221 ],
222 [
223 'name' => 'navigation',
224 'operator' => '=',
225 'value' => 'arrows',
226 ],
227 ],
228 ],
229 ]
230 );
231
232 $this->add_control(
233 'navigation_next_icon',
234 [
235 'label' => esc_html__( 'Next Arrow Icon', 'elementor' ),
236 'type' => Controls_Manager::ICONS,
237 'fa4compatibility' => 'icon',
238 'skin' => 'inline',
239 'label_block' => false,
240 'skin_settings' => [
241 'inline' => [
242 'none' => [
243 'label' => 'Default',
244 'icon' => 'eicon-chevron-right',
245 ],
246 'icon' => [
247 'icon' => 'eicon-star',
248 ],
249 ],
250 ],
251 'recommended' => [
252 'fa-regular' => [
253 'arrow-alt-circle-right',
254 'caret-square-right',
255 ],
256 'fa-solid' => [
257 'angle-double-right',
258 'angle-right',
259 'arrow-alt-circle-right',
260 'arrow-circle-right',
261 'arrow-right',
262 'caret-right',
263 'caret-square-right',
264 'chevron-circle-right',
265 'chevron-right',
266 'long-arrow-alt-right',
267 ],
268 ],
269 'conditions' => [
270 'relation' => 'or',
271 'terms' => [
272 [
273 'name' => 'navigation',
274 'operator' => '=',
275 'value' => 'both',
276 ],
277 [
278 'name' => 'navigation',
279 'operator' => '=',
280 'value' => 'arrows',
281 ],
282 ],
283 ],
284 ]
285 );
286
287 $this->add_control(
288 'link_to',
289 [
290 'label' => esc_html__( 'Link', 'elementor' ),
291 'type' => Controls_Manager::SELECT,
292 'default' => 'none',
293 'options' => [
294 'none' => esc_html__( 'None', 'elementor' ),
295 'file' => esc_html__( 'Media File', 'elementor' ),
296 'custom' => esc_html__( 'Custom URL', 'elementor' ),
297 ],
298 ]
299 );
300
301 $this->add_control(
302 'link',
303 [
304 'label' => esc_html__( 'Link', 'elementor' ),
305 'type' => Controls_Manager::URL,
306 'placeholder' => esc_html__( 'https://your-link.com', 'elementor' ),
307 'condition' => [
308 'link_to' => 'custom',
309 ],
310 'show_label' => false,
311 'dynamic' => [
312 'active' => true,
313 ],
314 ]
315 );
316
317 $this->add_control(
318 'open_lightbox',
319 [
320 'label' => esc_html__( 'Lightbox', 'elementor' ),
321 'type' => Controls_Manager::SELECT,
322 'description' => sprintf(
323 /* translators: 1: Link open tag, 2: Link close tag. */
324 esc_html__( 'Manage your site’s lightbox settings in the %1$sLightbox panel%2$s.', 'elementor' ),
325 '<a href="javascript: $e.run( \'panel/global/open\' ).then( () => $e.route( \'panel/global/settings-lightbox\' ) )">',
326 '</a>'
327 ),
328 'default' => 'default',
329 'options' => [
330 'default' => esc_html__( 'Default', 'elementor' ),
331 'yes' => esc_html__( 'Yes', 'elementor' ),
332 'no' => esc_html__( 'No', 'elementor' ),
333 ],
334 'condition' => [
335 'link_to' => 'file',
336 ],
337 ]
338 );
339
340 $this->add_control(
341 'caption_type',
342 [
343 'label' => esc_html__( 'Caption', 'elementor' ),
344 'type' => Controls_Manager::SELECT,
345 'default' => '',
346 'options' => [
347 '' => esc_html__( 'None', 'elementor' ),
348 'title' => esc_html__( 'Title', 'elementor' ),
349 'caption' => esc_html__( 'Caption', 'elementor' ),
350 'description' => esc_html__( 'Description', 'elementor' ),
351 ],
352 ]
353 );
354
355 $this->add_control(
356 'view',
357 [
358 'label' => esc_html__( 'View', 'elementor' ),
359 'type' => Controls_Manager::HIDDEN,
360 'default' => 'traditional',
361 ]
362 );
363
364 $this->end_controls_section();
365
366 $this->start_controls_section(
367 'section_additional_options',
368 [
369 'label' => esc_html__( 'Additional Options', 'elementor' ),
370 ]
371 );
372
373 $this->add_control(
374 'lazyload',
375 [
376 'label' => esc_html__( 'Lazyload', 'elementor' ),
377 'type' => Controls_Manager::SWITCHER,
378 'frontend_available' => true,
379 ]
380 );
381
382 $this->add_control(
383 'autoplay',
384 [
385 'label' => esc_html__( 'Autoplay', 'elementor' ),
386 'type' => Controls_Manager::SELECT,
387 'default' => 'yes',
388 'options' => [
389 'yes' => esc_html__( 'Yes', 'elementor' ),
390 'no' => esc_html__( 'No', 'elementor' ),
391 ],
392 'frontend_available' => true,
393 ]
394 );
395
396 $this->add_control(
397 'pause_on_hover',
398 [
399 'label' => esc_html__( 'Pause on Hover', 'elementor' ),
400 'type' => Controls_Manager::SELECT,
401 'default' => 'yes',
402 'options' => [
403 'yes' => esc_html__( 'Yes', 'elementor' ),
404 'no' => esc_html__( 'No', 'elementor' ),
405 ],
406 'condition' => [
407 'autoplay' => 'yes',
408 ],
409 'render_type' => 'none',
410 'frontend_available' => true,
411 ]
412 );
413
414 $this->add_control(
415 'pause_on_interaction',
416 [
417 'label' => esc_html__( 'Pause on Interaction', 'elementor' ),
418 'type' => Controls_Manager::SELECT,
419 'default' => 'yes',
420 'options' => [
421 'yes' => esc_html__( 'Yes', 'elementor' ),
422 'no' => esc_html__( 'No', 'elementor' ),
423 ],
424 'condition' => [
425 'autoplay' => 'yes',
426 ],
427 'frontend_available' => true,
428 ]
429 );
430
431 $this->add_control(
432 'autoplay_speed',
433 [
434 'label' => esc_html__( 'Autoplay Speed', 'elementor' ),
435 'type' => Controls_Manager::NUMBER,
436 'default' => 5000,
437 'condition' => [
438 'autoplay' => 'yes',
439 ],
440 'render_type' => 'none',
441 'frontend_available' => true,
442 ]
443 );
444
445 // Loop requires a re-render so no 'render_type = none'
446 $this->add_control(
447 'infinite',
448 [
449 'label' => esc_html__( 'Infinite Loop', 'elementor' ),
450 'type' => Controls_Manager::SELECT,
451 'default' => 'yes',
452 'options' => [
453 'yes' => esc_html__( 'Yes', 'elementor' ),
454 'no' => esc_html__( 'No', 'elementor' ),
455 ],
456 'frontend_available' => true,
457 ]
458 );
459
460 $this->add_control(
461 'effect',
462 [
463 'label' => esc_html__( 'Effect', 'elementor' ),
464 'type' => Controls_Manager::SELECT,
465 'default' => 'slide',
466 'options' => [
467 'slide' => esc_html__( 'Slide', 'elementor' ),
468 'fade' => esc_html__( 'Fade', 'elementor' ),
469 ],
470 'condition' => [
471 'slides_to_show' => '1',
472 ],
473 'frontend_available' => true,
474 ]
475 );
476
477 $this->add_control(
478 'speed',
479 [
480 'label' => esc_html__( 'Animation Speed', 'elementor' ),
481 'type' => Controls_Manager::NUMBER,
482 'default' => 500,
483 'render_type' => 'none',
484 'frontend_available' => true,
485 ]
486 );
487
488 $this->add_control(
489 'direction',
490 [
491 'label' => esc_html__( 'Direction', 'elementor' ),
492 'type' => Controls_Manager::SELECT,
493 'default' => 'ltr',
494 'options' => [
495 'ltr' => esc_html__( 'Left', 'elementor' ),
496 'rtl' => esc_html__( 'Right', 'elementor' ),
497 ],
498 ]
499 );
500
501 $this->end_controls_section();
502
503 $this->start_controls_section(
504 'section_style_navigation',
505 [
506 'label' => esc_html__( 'Navigation', 'elementor' ),
507 'tab' => Controls_Manager::TAB_STYLE,
508 'condition' => [
509 'navigation' => [ 'arrows', 'dots', 'both' ],
510 ],
511 ]
512 );
513
514 $this->add_control(
515 'heading_style_arrows',
516 [
517 'label' => esc_html__( 'Arrows', 'elementor' ),
518 'type' => Controls_Manager::HEADING,
519 'separator' => 'before',
520 'condition' => [
521 'navigation' => [ 'arrows', 'both' ],
522 ],
523 ]
524 );
525
526 $this->add_control(
527 'arrows_position',
528 [
529 'label' => esc_html__( 'Position', 'elementor' ),
530 'type' => Controls_Manager::SELECT,
531 'default' => 'inside',
532 'options' => [
533 'inside' => esc_html__( 'Inside', 'elementor' ),
534 'outside' => esc_html__( 'Outside', 'elementor' ),
535 ],
536 'prefix_class' => 'elementor-arrows-position-',
537 'condition' => [
538 'navigation' => [ 'arrows', 'both' ],
539 ],
540 ]
541 );
542
543 $this->add_control(
544 'arrows_size',
545 [
546 'label' => esc_html__( 'Size', 'elementor' ),
547 'type' => Controls_Manager::SLIDER,
548 'range' => [
549 'px' => [
550 'min' => 20,
551 'max' => 60,
552 ],
553 ],
554 'selectors' => [
555 '{{WRAPPER}} .elementor-swiper-button.elementor-swiper-button-prev, {{WRAPPER}} .elementor-swiper-button.elementor-swiper-button-next' => 'font-size: {{SIZE}}{{UNIT}};',
556 ],
557 'condition' => [
558 'navigation' => [ 'arrows', 'both' ],
559 ],
560 ]
561 );
562
563 $this->add_control(
564 'arrows_color',
565 [
566 'label' => esc_html__( 'Color', 'elementor' ),
567 'type' => Controls_Manager::COLOR,
568 'selectors' => [
569 '{{WRAPPER}} .elementor-swiper-button.elementor-swiper-button-prev, {{WRAPPER}} .elementor-swiper-button.elementor-swiper-button-next' => 'color: {{VALUE}};',
570 '{{WRAPPER}} .elementor-swiper-button.elementor-swiper-button-prev svg, {{WRAPPER}} .elementor-swiper-button.elementor-swiper-button-next svg' => 'fill: {{VALUE}};',
571 ],
572 'condition' => [
573 'navigation' => [ 'arrows', 'both' ],
574 ],
575 ]
576 );
577
578 $this->add_control(
579 'heading_style_dots',
580 [
581 'label' => esc_html__( 'Pagination', 'elementor' ),
582 'type' => Controls_Manager::HEADING,
583 'separator' => 'before',
584 'condition' => [
585 'navigation' => [ 'dots', 'both' ],
586 ],
587 ]
588 );
589
590 $this->add_control(
591 'dots_position',
592 [
593 'label' => esc_html__( 'Position', 'elementor' ),
594 'type' => Controls_Manager::SELECT,
595 'default' => 'outside',
596 'options' => [
597 'outside' => esc_html__( 'Outside', 'elementor' ),
598 'inside' => esc_html__( 'Inside', 'elementor' ),
599 ],
600 'prefix_class' => 'elementor-pagination-position-',
601 'condition' => [
602 'navigation' => [ 'dots', 'both' ],
603 ],
604 ]
605 );
606
607 $this->add_control(
608 'dots_size',
609 [
610 'label' => esc_html__( 'Size', 'elementor' ),
611 'type' => Controls_Manager::SLIDER,
612 'range' => [
613 'px' => [
614 'min' => 5,
615 'max' => 10,
616 ],
617 ],
618 'selectors' => [
619 '{{WRAPPER}} .swiper-pagination-bullet' => 'width: {{SIZE}}{{UNIT}}; height: {{SIZE}}{{UNIT}};',
620 ],
621 'condition' => [
622 'navigation' => [ 'dots', 'both' ],
623 ],
624 ]
625 );
626
627 $this->add_control(
628 'dots_inactive_color',
629 [
630 'label' => esc_html__( 'Color', 'elementor' ),
631 'type' => Controls_Manager::COLOR,
632 'selectors' => [
633 // The opacity property will override the default inactive dot color which is opacity 0.2.
634 '{{WRAPPER}} .swiper-pagination-bullet:not(.swiper-pagination-bullet-active)' => 'background: {{VALUE}}; opacity: 1',
635 ],
636 'condition' => [
637 'navigation' => [ 'dots', 'both' ],
638 ],
639 ]
640 );
641
642 $this->add_control(
643 'dots_color',
644 [
645 'label' => esc_html__( 'Active Color', 'elementor' ),
646 'type' => Controls_Manager::COLOR,
647 'selectors' => [
648 '{{WRAPPER}} .swiper-pagination-bullet' => 'background: {{VALUE}};',
649 ],
650 'condition' => [
651 'navigation' => [ 'dots', 'both' ],
652 ],
653 ]
654 );
655
656 $this->end_controls_section();
657
658 $this->start_controls_section(
659 'section_style_image',
660 [
661 'label' => esc_html__( 'Image', 'elementor' ),
662 'tab' => Controls_Manager::TAB_STYLE,
663 ]
664 );
665
666 $this->add_responsive_control(
667 'gallery_vertical_align',
668 [
669 'label' => esc_html__( 'Vertical Align', 'elementor' ),
670 'type' => Controls_Manager::CHOOSE,
671 'options' => [
672 'flex-start' => [
673 'title' => esc_html__( 'Start', 'elementor' ),
674 'icon' => 'eicon-v-align-top',
675 ],
676 'center' => [
677 'title' => esc_html__( 'Center', 'elementor' ),
678 'icon' => 'eicon-v-align-middle',
679 ],
680 'flex-end' => [
681 'title' => esc_html__( 'End', 'elementor' ),
682 'icon' => 'eicon-v-align-bottom',
683 ],
684 ],
685 'condition' => [
686 'slides_to_show!' => '1',
687 ],
688 'selectors' => [
689 '{{WRAPPER}} .swiper-wrapper' => 'display: flex; align-items: {{VALUE}};',
690 ],
691 ]
692 );
693
694 $this->add_control(
695 'image_spacing',
696 [
697 'label' => esc_html__( 'Spacing', 'elementor' ),
698 'type' => Controls_Manager::SELECT,
699 'options' => [
700 '' => esc_html__( 'Default', 'elementor' ),
701 'custom' => esc_html__( 'Custom', 'elementor' ),
702 ],
703 'default' => '',
704 'condition' => [
705 'slides_to_show!' => '1',
706 ],
707 ]
708 );
709
710 $this->add_responsive_control(
711 'image_spacing_custom',
712 [
713 'label' => esc_html__( 'Image Spacing', 'elementor' ),
714 'type' => Controls_Manager::SLIDER,
715 'range' => [
716 'px' => [
717 'max' => 100,
718 ],
719 ],
720 'default' => [
721 'size' => 20,
722 ],
723 'condition' => [
724 'image_spacing' => 'custom',
725 'slides_to_show!' => '1',
726 ],
727 'frontend_available' => true,
728 'render_type' => 'none',
729 'separator' => 'after',
730 ]
731 );
732
733 $this->add_group_control(
734 Group_Control_Border::get_type(),
735 [
736 'name' => 'image_border',
737 'selector' => '{{WRAPPER}} .elementor-image-carousel-wrapper .elementor-image-carousel .swiper-slide-image',
738 ]
739 );
740
741 $this->add_responsive_control(
742 'image_border_radius',
743 [
744 'label' => esc_html__( 'Border Radius', 'elementor' ),
745 'type' => Controls_Manager::DIMENSIONS,
746 'size_units' => [ 'px', '%', 'em', 'rem', 'custom' ],
747 'selectors' => [
748 '{{WRAPPER}} .elementor-image-carousel-wrapper .elementor-image-carousel .swiper-slide-image' => 'border-radius: {{TOP}}{{UNIT}} {{RIGHT}}{{UNIT}} {{BOTTOM}}{{UNIT}} {{LEFT}}{{UNIT}};',
749 ],
750 ]
751 );
752
753 $this->end_controls_section();
754
755 $this->start_controls_section(
756 'section_caption',
757 [
758 'label' => esc_html__( 'Caption', 'elementor' ),
759 'tab' => Controls_Manager::TAB_STYLE,
760 'condition' => [
761 'caption_type!' => '',
762 ],
763 ]
764 );
765
766 $this->add_responsive_control(
767 'caption_align',
768 [
769 'label' => esc_html__( 'Alignment', 'elementor' ),
770 'type' => Controls_Manager::CHOOSE,
771 'options' => [
772 'left' => [
773 'title' => esc_html__( 'Left', 'elementor' ),
774 'icon' => 'eicon-text-align-left',
775 ],
776 'center' => [
777 'title' => esc_html__( 'Center', 'elementor' ),
778 'icon' => 'eicon-text-align-center',
779 ],
780 'right' => [
781 'title' => esc_html__( 'Right', 'elementor' ),
782 'icon' => 'eicon-text-align-right',
783 ],
784 'justify' => [
785 'title' => esc_html__( 'Justified', 'elementor' ),
786 'icon' => 'eicon-text-align-justify',
787 ],
788 ],
789 'default' => 'center',
790 'selectors' => [
791 '{{WRAPPER}} .elementor-image-carousel-caption' => 'text-align: {{VALUE}};',
792 ],
793 ]
794 );
795
796 $this->add_control(
797 'caption_text_color',
798 [
799 'label' => esc_html__( 'Text Color', 'elementor' ),
800 'type' => Controls_Manager::COLOR,
801 'default' => '',
802 'selectors' => [
803 '{{WRAPPER}} .elementor-image-carousel-caption' => 'color: {{VALUE}};',
804 ],
805 ]
806 );
807
808 $this->add_group_control(
809 Group_Control_Typography::get_type(),
810 [
811 'name' => 'caption_typography',
812 'global' => [
813 'default' => Global_Colors::COLOR_ACCENT,
814 ],
815 'selector' => '{{WRAPPER}} .elementor-image-carousel-caption',
816 ]
817 );
818
819 $this->add_group_control(
820 Group_Control_Text_Shadow::get_type(),
821 [
822 'name' => 'caption_shadow',
823 'selector' => '{{WRAPPER}} .elementor-image-carousel-caption',
824 ]
825 );
826
827 $this->end_controls_section();
828
829 }
830
831 /**
832 * Render image carousel widget output on the frontend.
833 *
834 * Written in PHP and used to generate the final HTML.
835 *
836 * @since 1.0.0
837 * @access protected
838 */
839 protected function render() {
840 $settings = $this->get_settings_for_display();
841
842 $lazyload = 'yes' === $settings['lazyload'];
843
844 if ( empty( $settings['carousel'] ) ) {
845 return;
846 }
847
848 $slides = [];
849
850 foreach ( $settings['carousel'] as $index => $attachment ) {
851 $image_url = Group_Control_Image_Size::get_attachment_image_src( $attachment['id'], 'thumbnail', $settings );
852
853 if ( ! $image_url && isset( $attachment['url'] ) ) {
854 $image_url = $attachment['url'];
855 }
856
857 if ( $lazyload ) {
858 $image_html = '<img class="swiper-slide-image swiper-lazy" data-src="' . esc_attr( $image_url ) . '" alt="' . esc_attr( Control_Media::get_image_alt( $attachment ) ) . '" />';
859 } else {
860 $image_html = '<img class="swiper-slide-image" src="' . esc_attr( $image_url ) . '" alt="' . esc_attr( Control_Media::get_image_alt( $attachment ) ) . '" />';
861 }
862
863 $link_tag = '';
864
865 $link = $this->get_link_url( $attachment, $settings );
866
867 if ( $link ) {
868 $link_key = 'link_' . $index;
869
870 $this->add_lightbox_data_attributes( $link_key, $attachment['id'], $settings['open_lightbox'], $this->get_id() );
871
872 if ( Plugin::$instance->editor->is_edit_mode() ) {
873 $this->add_render_attribute( $link_key, [
874 'class' => 'elementor-clickable',
875 ] );
876 }
877
878 $this->add_link_attributes( $link_key, $link );
879
880 $link_tag = '<a ' . $this->get_render_attribute_string( $link_key ) . '>';
881 }
882
883 $image_caption = $this->get_image_caption( $attachment );
884
885 $slide_html = '<div class="swiper-slide">' . $link_tag . '<figure class="swiper-slide-inner">' . $image_html;
886
887 if ( $lazyload ) {
888 $slide_html .= '<div class="swiper-lazy-preloader"></div>';
889 }
890
891 if ( ! empty( $image_caption ) ) {
892 $slide_html .= '<figcaption class="elementor-image-carousel-caption">' . wp_kses_post( $image_caption ) . '</figcaption>';
893 }
894
895 $slide_html .= '</figure>';
896
897 if ( $link ) {
898 $slide_html .= '</a>';
899 }
900
901 $slide_html .= '</div>';
902
903 $slides[] = $slide_html;
904
905 }
906
907 if ( empty( $slides ) ) {
908 return;
909 }
910
911 $swiper_class = Plugin::$instance->experiments->is_feature_active( 'e_swiper_latest' ) ? 'swiper' : 'swiper-container';
912
913 $this->add_render_attribute( [
914 'carousel' => [
915 'class' => 'elementor-image-carousel swiper-wrapper',
916 ],
917 'carousel-wrapper' => [
918 'class' => 'elementor-image-carousel-wrapper ' . $swiper_class,
919 'dir' => $settings['direction'],
920 ],
921 ] );
922
923 $show_dots = ( in_array( $settings['navigation'], [ 'dots', 'both' ] ) );
924 $show_arrows = ( in_array( $settings['navigation'], [ 'arrows', 'both' ] ) );
925
926 if ( 'yes' === $settings['image_stretch'] ) {
927 $this->add_render_attribute( 'carousel', 'class', 'swiper-image-stretch' );
928 }
929
930 $slides_count = count( $settings['carousel'] );
931
932 ?>
933 <div <?php $this->print_render_attribute_string( 'carousel-wrapper' ); ?>>
934 <div <?php $this->print_render_attribute_string( 'carousel' ); ?>>
935 <?php // PHPCS - $slides contains the slides content, all the relevent content is escaped above. ?>
936 <?php echo implode( '', $slides ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped ?>
937 </div>
938 <?php if ( 1 < $slides_count ) : ?>
939 <?php if ( $show_dots ) : ?>
940 <div class="swiper-pagination"></div>
941 <?php endif; ?>
942 <?php if ( $show_arrows ) : ?>
943 <div class="elementor-swiper-button elementor-swiper-button-prev" role="button" tabindex="0">
944 <?php $this->render_swiper_button( 'previous' ); ?>
945 <span class="elementor-screen-only"><?php echo esc_html__( 'Previous image', 'elementor' ); ?></span>
946 </div>
947 <div class="elementor-swiper-button elementor-swiper-button-next" role="button" tabindex="0">
948 <?php $this->render_swiper_button( 'next' ); ?>
949 <span class="elementor-screen-only"><?php echo esc_html__( 'Next image', 'elementor' ); ?></span>
950 </div>
951 <?php endif; ?>
952 <?php endif; ?>
953 </div>
954 <?php
955 }
956
957 /**
958 * Retrieve image carousel link URL.
959 *
960 * @since 1.0.0
961 * @access private
962 *
963 * @param array $attachment
964 * @param object $instance
965 *
966 * @return array|string|false An array/string containing the attachment URL, or false if no link.
967 */
968 private function get_link_url( $attachment, $instance ) {
969 if ( 'none' === $instance['link_to'] ) {
970 return false;
971 }
972
973 if ( 'custom' === $instance['link_to'] ) {
974 if ( empty( $instance['link']['url'] ) ) {
975 return false;
976 }
977
978 return $instance['link'];
979 }
980
981 return [
982 'url' => wp_get_attachment_url( $attachment['id'] ),
983 ];
984 }
985
986 /**
987 * Retrieve image carousel caption.
988 *
989 * @since 1.2.0
990 * @access private
991 *
992 * @param array $attachment
993 *
994 * @return string The caption of the image.
995 */
996 private function get_image_caption( $attachment ) {
997 $caption_type = $this->get_settings_for_display( 'caption_type' );
998
999 if ( empty( $caption_type ) ) {
1000 return '';
1001 }
1002
1003 $attachment_post = get_post( $attachment['id'] );
1004
1005 if ( 'caption' === $caption_type ) {
1006 return $attachment_post->post_excerpt;
1007 }
1008
1009 if ( 'title' === $caption_type ) {
1010 return $attachment_post->post_title;
1011 }
1012
1013 return $attachment_post->post_content;
1014 }
1015
1016 private function render_swiper_button( $type ) {
1017 $direction = 'next' === $type ? 'right' : 'left';
1018 $icon_settings = $this->get_settings_for_display( 'navigation_' . $type . '_icon' );
1019
1020 if ( empty( $icon_settings['value'] ) ) {
1021 $icon_settings = [
1022 'library' => 'eicons',
1023 'value' => 'eicon-chevron-' . $direction,
1024 ];
1025 }
1026
1027 Icons_Manager::render_icon( $icon_settings, [ 'aria-hidden' => 'true' ] );
1028 }
1029 }
1030