PluginProbe ʕ •ᴥ•ʔ
Elementor Website Builder – more than just a page builder / 3.26.0-beta5
Elementor Website Builder – more than just a page builder v3.26.0-beta5
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 4.0.6 4.0.5 4.0.4 4.0.3 3.22.0-dev1 4.0.0-beta3 3.22.0-dev2 4.0.0-beta4 3.22.0-dev3 4.0.0-beta5 3.22.0-dev4 4.0.0-dev1 3.22.0-dev5 4.0.0-dev2 3.22.0-dev6 4.0.0-dev3 3.22.1 4.0.0-dev4 3.22.2 4.0.0-dev5 3.22.3 4.0.1 3.23.0 4.0.2 3.23.0-beta1 3.23.0-beta2 3.23.0-beta3 3.23.0-beta4 3.23.0-beta5 3.23.0-beta6 3.23.0-dev1 3.23.0-dev2 3.23.0-dev3 3.23.0-dev4 3.23.0-dev5 3.23.0-dev6 3.23.1 3.23.2 3.23.3 3.23.4 3.24.0 3.24.0-beta1 3.24.0-beta2 3.24.0-beta3 3.24.0-dev1 3.24.0-dev2 3.24.0-dev3 3.24.1 3.24.2 3.24.3 3.24.4 3.24.5 3.24.6 3.24.7 3.24.8 3.25.0 3.25.0-beta1 3.25.0-beta2 3.25.0-beta3 3.25.0-dev1 3.25.0-dev2 3.25.0-dev3 3.25.1 3.25.10 3.25.11 3.25.2 3.25.3 3.25.4 3.25.5 3.25.6 3.25.7 3.25.8 3.25.9 3.26.0 3.26.0-beta1 3.26.0-beta2 3.26.0-beta3 3.26.0-beta4 3.26.0-beta5 3.26.0-dev1 3.26.0-dev2 3.26.0-dev3 3.26.0-dev4 3.26.0-dev5 3.26.1 3.26.2 3.26.3 3.26.4 3.26.5 3.27.0 3.27.0-beta1 3.27.0-beta2 3.27.0-dev1 3.27.0-dev2 3.27.1 3.27.2 3.27.3 3.27.4 3.27.5 3.27.6 3.27.7 3.28.0 3.28.0-beta1 3.28.0-beta2 3.28.0-beta3 3.28.0-dev1 3.28.0-dev2 3.28.0-dev3 3.28.1 3.28.2 3.28.3 3.28.4 3.29.0 3.29.0-beta1 trunk 3.29.0-beta2 3.0.0 3.29.0-beta3 3.0.1 3.29.0-beta4 3.0.10 3.29.0-dev1 3.0.11 3.29.0-dev2 3.0.12 3.29.0-dev3 3.0.13 3.29.0-dev4 3.0.14 3.29.1 3.0.15 3.29.2 3.0.16 3.3.0 3.0.2 3.3.1 3.0.3 3.30.0 3.0.4 3.30.0-beta1 3.0.5 3.30.0-beta2 3.0.6 3.30.0-beta3 3.0.7 3.30.0-dev1 3.0.8 3.30.0-dev2 3.0.8.1 3.30.0-dev3 3.0.9 3.30.1 3.1.0 3.30.2 3.1.0-beta1 3.30.3 3.1.0-beta2 3.30.4 3.1.0-beta3 3.31.0 3.1.0-beta4 3.31.0-beta1 3.1.0-dev1 3.31.0-beta2 3.1.0-dev2 3.31.0-dev1 3.1.0-dev3 3.31.0-dev2 3.1.1 3.31.1 3.1.2 3.31.2 3.1.3 3.31.3 3.1.4 3.31.4 3.10.0 3.31.5 3.10.0-dev1 3.32.0 3.10.1 3.32.0-beta1 3.10.2 3.32.0-beta2 3.11.0 3.32.0-beta3 3.11.0-beta1 3.32.0-dev1 3.11.0-beta2 3.32.0-dev2 3.11.0-beta3 3.32.0-dev3 3.11.0-dev1 3.32.1 3.11.0-dev2 3.32.2 3.11.0-dev3 3.32.3 3.11.1 3.32.4 3.11.2 3.32.5 3.11.3 3.33.0 3.11.4 3.33.0-beta1 3.11.5 3.33.0-beta2 3.12.0 3.33.0-beta3 3.12.1 3.33.0-beta4 3.12.2 3.33.0-dev1 3.13.0 3.33.0-dev2 3.13.0-beta1 3.33.0-dev3 3.13.0-beta2 3.33.0-dev4 3.13.0-beta3 3.33.1 3.13.0-dev3 3.33.2 3.13.0-dev4 3.33.3 3.13.1 3.33.4 3.13.2 3.33.5 3.13.3 3.33.6 3.13.4 3.34.0 3.14.0 3.34.0-beta1 3.14.0-beta1 3.34.0-beta2 3.14.0-beta2 3.34.0-beta3 3.14.0-beta3 3.34.0-dev1 3.14.0-beta4 3.34.0-dev2 3.14.0-beta5 3.34.1 3.14.1 3.34.2 3.15.0 3.34.3 3.15.1 3.34.4 3.15.2 3.35.0 3.15.3 3.35.0-beta1 3.16.0 3.35.0-beta2 3.16.0-beta3 3.35.0-beta3 3.16.0-beta4 3.35.0-beta4 3.16.0-dev1 3.35.0-dev1 3.16.0-dev2 3.35.0-dev2 3.16.1 3.35.0-dev3 3.16.2 3.35.0-dev4 3.16.3 3.35.1 3.16.4 3.35.2 3.16.5 3.35.3 3.16.6 3.35.4 3.17.0 3.35.5 3.17.0-dev2 3.35.6 3.17.0-dev3 3.35.7 3.17.0-dev4 3.35.8 3.17.1 3.35.9 3.17.2 3.4.0 3.17.3 3.4.0-dev7 3.18.0 3.4.0-dev8 3.18.0-beta1 3.4.0-dev9 3.18.0-beta2 3.4.1 3.18.0-beta3 3.4.2 3.18.0-beta4 3.4.3 3.18.0-dev1 3.4.4 3.18.1 3.4.5 3.18.2 3.4.6 3.18.3 3.4.7 3.19.0 3.4.8 3.19.0-beta1 3.5.0 3.19.0-beta2 3.5.0-beta1 3.19.0-beta3 3.5.0-beta2 3.19.0-beta4 3.5.0-beta3 3.19.0-beta5 3.5.0-beta4 3.19.0-beta6 3.5.0-beta5 3.19.0-dev1 3.5.0-beta7 3.19.0-dev2 3.5.0-beta8 3.19.0-dev3 3.5.0-dev8 3.19.0-dev4 3.5.0-dev9 3.19.0-dev5 3.5.1 3.19.0-dev6 3.5.2 3.19.1 3.5.3 3.19.2 3.5.4 3.19.3 3.5.5 3.19.4 3.5.6 3.2.0 3.6.0 3.2.1 3.6.0-beta1 3.2.2 3.6.0-beta2 3.2.3 3.6.0-beta3 3.2.4 3.6.0-beta4 3.2.5 3.6.0-beta5 3.20.0 3.6.0-dev1 3.20.0-beta1 3.6.0-dev10 3.20.0-beta2 3.6.1 3.20.0-beta3 3.6.2 3.20.0-beta4 3.6.3 3.20.0-dev1 3.6.4 3.20.0-dev2 3.6.5 3.20.0-dev3 3.6.6 3.20.0-dev4 3.6.7 3.20.1 3.6.8 3.20.2 3.7.0 3.20.3 3.7.0-beta1 3.20.4 3.7.0-beta2 3.21.0 3.7.0-beta3 3.21.0-beta1 3.7.0-beta4 3.21.0-beta2 3.7.0-dev1 3.21.0-beta3 3.7.1 3.21.0-dev1 3.7.2 3.21.0-dev2 3.7.3 3.21.0-dev3 3.7.4 3.21.1 3.7.5 3.21.2 3.7.6 3.21.3 3.7.7 3.21.4 3.7.8 3.21.5 3.8.0 3.21.6 3.8.0-beta1 3.21.7 3.8.0-beta2 3.21.8 3.8.0-beta3 3.22.0 3.8.1 3.22.0-beta1 3.9.0 3.22.0-beta2 3.9.1 3.22.0-beta3 3.9.2 3.22.0-beta4 4.0.0 3.22.0-beta5 4.0.0-beta1 3.22.0-beta6 4.0.0-beta2
elementor / includes / widgets / image-carousel.php
elementor / includes / widgets Last commit date
traits 1 year ago accordion.php 1 year ago alert.php 1 year ago audio.php 1 year ago button.php 1 year ago common-base.php 1 year ago common-optimized.php 1 year ago common.php 1 year ago counter.php 1 year ago divider.php 1 year ago google-maps.php 1 year ago heading.php 1 year ago html.php 1 year ago icon-box.php 1 year ago icon-list.php 1 year ago icon.php 1 year ago image-box.php 1 year ago image-carousel.php 1 year ago image-gallery.php 1 year ago image.php 1 year ago inner-section.php 2 years ago menu-anchor.php 1 year ago progress.php 1 year ago rating.php 1 year ago read-more.php 1 year ago shortcode.php 1 year ago sidebar.php 1 year ago social-icons.php 1 year ago spacer.php 1 year ago star-rating.php 1 year ago tabs.php 1 year ago testimonial.php 1 year ago text-editor.php 1 year ago toggle.php 1 year ago video.php 1 year ago wordpress.php 1 year ago
image-carousel.php
1117 lines
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 use Elementor\Modules\Promotions\Controls\Promotion_Control;
10
11 /**
12 * Elementor image carousel widget.
13 *
14 * Elementor widget that displays a set of images in a rotating carousel or
15 * slider.
16 *
17 * @since 1.0.0
18 */
19 class Widget_Image_Carousel extends Widget_Base {
20
21 /**
22 * Get widget name.
23 *
24 * Retrieve image carousel widget name.
25 *
26 * @since 1.0.0
27 * @access public
28 *
29 * @return string Widget name.
30 */
31 public function get_name() {
32 return 'image-carousel';
33 }
34
35 /**
36 * Get widget title.
37 *
38 * Retrieve image carousel widget title.
39 *
40 * @since 1.0.0
41 * @access public
42 *
43 * @return string Widget title.
44 */
45 public function get_title() {
46 return esc_html__( 'Image Carousel', 'elementor' );
47 }
48
49 /**
50 * Get widget icon.
51 *
52 * Retrieve image carousel widget icon.
53 *
54 * @since 1.0.0
55 * @access public
56 *
57 * @return string Widget icon.
58 */
59 public function get_icon() {
60 return 'eicon-slider-push';
61 }
62
63 /**
64 * Get widget keywords.
65 *
66 * Retrieve the list of keywords the widget belongs to.
67 *
68 * @since 2.1.0
69 * @access public
70 *
71 * @return array Widget keywords.
72 */
73 public function get_keywords() {
74 return [ 'image', 'photo', 'visual', 'carousel', 'slider' ];
75 }
76
77 protected function is_dynamic_content(): bool {
78 return false;
79 }
80
81 /**
82 * Get style dependencies.
83 *
84 * Retrieve the list of style dependencies the widget requires.
85 *
86 * @since 3.24.0
87 * @access public
88 *
89 * @return array Widget style dependencies.
90 */
91 public function get_style_depends(): array {
92 return [ 'e-swiper', 'widget-image-carousel' ];
93 }
94
95 public function has_widget_inner_wrapper(): bool {
96 return ! Plugin::$instance->experiments->is_feature_active( 'e_optimized_markup' );
97 }
98
99 /**
100 * Register image carousel widget controls.
101 *
102 * Adds different input fields to allow the user to change and customize the widget settings.
103 *
104 * @since 3.1.0
105 * @access protected
106 */
107 protected function register_controls() {
108 $this->start_controls_section(
109 'section_image_carousel',
110 [
111 'label' => esc_html__( 'Image Carousel', 'elementor' ),
112 ]
113 );
114
115 $this->add_control(
116 'carousel_name',
117 [
118 'label' => esc_html__( 'Carousel Name', 'elementor' ),
119 'type' => Controls_Manager::TEXT,
120 'default' => esc_html__( 'Image Carousel', 'elementor' ),
121 ]
122 );
123
124 $this->add_control(
125 'carousel',
126 [
127 'label' => esc_html__( 'Add Images', 'elementor' ),
128 'type' => Controls_Manager::GALLERY,
129 'default' => [],
130 'show_label' => false,
131 'dynamic' => [
132 'active' => true,
133 ],
134 ]
135 );
136
137 $this->add_group_control(
138 Group_Control_Image_Size::get_type(),
139 [
140 'name' => 'thumbnail', // Usage: `{name}_size` and `{name}_custom_dimension`, in this case `thumbnail_size` and `thumbnail_custom_dimension`.
141 ]
142 );
143
144 $slides_to_show = range( 1, 10 );
145 $slides_to_show = array_combine( $slides_to_show, $slides_to_show );
146
147 $this->add_responsive_control(
148 'slides_to_show',
149 [
150 'label' => esc_html__( 'Slides to Show', 'elementor' ),
151 'type' => Controls_Manager::SELECT,
152 'options' => [
153 '' => esc_html__( 'Default', 'elementor' ),
154 ] + $slides_to_show,
155 'frontend_available' => true,
156 'render_type' => 'template',
157 'selectors' => [
158 '{{WRAPPER}}' => '--e-image-carousel-slides-to-show: {{VALUE}}',
159 ],
160 'content_classes' => 'elementor-control-field-select-small',
161 ]
162 );
163
164 $this->add_responsive_control(
165 'slides_to_scroll',
166 [
167 'label' => esc_html__( 'Slides to Scroll', 'elementor' ),
168 'type' => Controls_Manager::SELECT,
169 'description' => esc_html__( 'Set how many slides are scrolled per swipe.', 'elementor' ),
170 'options' => [
171 '' => esc_html__( 'Default', 'elementor' ),
172 ] + $slides_to_show,
173 'condition' => [
174 'slides_to_show!' => '1',
175 ],
176 'frontend_available' => true,
177 'content_classes' => 'elementor-control-field-select-small',
178 ]
179 );
180
181 $this->add_control(
182 'image_stretch',
183 [
184 'label' => esc_html__( 'Image Stretch', 'elementor' ),
185 'type' => Controls_Manager::SELECT,
186 'default' => 'no',
187 'options' => [
188 'no' => esc_html__( 'No', 'elementor' ),
189 'yes' => esc_html__( 'Yes', 'elementor' ),
190 ],
191 ]
192 );
193
194 $this->add_control(
195 'navigation',
196 [
197 'label' => esc_html__( 'Navigation', 'elementor' ),
198 'type' => Controls_Manager::SELECT,
199 'default' => 'both',
200 'options' => [
201 'both' => esc_html__( 'Arrows and Dots', 'elementor' ),
202 'arrows' => esc_html__( 'Arrows', 'elementor' ),
203 'dots' => esc_html__( 'Dots', 'elementor' ),
204 'none' => esc_html__( 'None', 'elementor' ),
205 ],
206 'frontend_available' => true,
207 ]
208 );
209
210 $this->add_control(
211 'navigation_previous_icon',
212 [
213 'label' => esc_html__( 'Previous Arrow Icon', 'elementor' ),
214 'type' => Controls_Manager::ICONS,
215 'fa4compatibility' => 'icon',
216 'skin' => 'inline',
217 'label_block' => false,
218 'skin_settings' => [
219 'inline' => [
220 'none' => [
221 'label' => 'Default',
222 'icon' => 'eicon-chevron-left',
223 ],
224 'icon' => [
225 'icon' => 'eicon-star',
226 ],
227 ],
228 ],
229 'recommended' => [
230 'fa-regular' => [
231 'arrow-alt-circle-left',
232 'caret-square-left',
233 ],
234 'fa-solid' => [
235 'angle-double-left',
236 'angle-left',
237 'arrow-alt-circle-left',
238 'arrow-circle-left',
239 'arrow-left',
240 'caret-left',
241 'caret-square-left',
242 'chevron-circle-left',
243 'chevron-left',
244 'long-arrow-alt-left',
245 ],
246 ],
247 'conditions' => [
248 'relation' => 'or',
249 'terms' => [
250 [
251 'name' => 'navigation',
252 'operator' => '=',
253 'value' => 'both',
254 ],
255 [
256 'name' => 'navigation',
257 'operator' => '=',
258 'value' => 'arrows',
259 ],
260 ],
261 ],
262 ]
263 );
264
265 $this->add_control(
266 'navigation_next_icon',
267 [
268 'label' => esc_html__( 'Next Arrow Icon', 'elementor' ),
269 'type' => Controls_Manager::ICONS,
270 'fa4compatibility' => 'icon',
271 'skin' => 'inline',
272 'label_block' => false,
273 'skin_settings' => [
274 'inline' => [
275 'none' => [
276 'label' => 'Default',
277 'icon' => 'eicon-chevron-right',
278 ],
279 'icon' => [
280 'icon' => 'eicon-star',
281 ],
282 ],
283 ],
284 'recommended' => [
285 'fa-regular' => [
286 'arrow-alt-circle-right',
287 'caret-square-right',
288 ],
289 'fa-solid' => [
290 'angle-double-right',
291 'angle-right',
292 'arrow-alt-circle-right',
293 'arrow-circle-right',
294 'arrow-right',
295 'caret-right',
296 'caret-square-right',
297 'chevron-circle-right',
298 'chevron-right',
299 'long-arrow-alt-right',
300 ],
301 ],
302 'conditions' => [
303 'relation' => 'or',
304 'terms' => [
305 [
306 'name' => 'navigation',
307 'operator' => '=',
308 'value' => 'both',
309 ],
310 [
311 'name' => 'navigation',
312 'operator' => '=',
313 'value' => 'arrows',
314 ],
315 ],
316 ],
317 ]
318 );
319
320 $this->add_control(
321 'link_to',
322 [
323 'label' => esc_html__( 'Link', 'elementor' ),
324 'type' => Controls_Manager::SELECT,
325 'default' => 'none',
326 'options' => [
327 'none' => esc_html__( 'None', 'elementor' ),
328 'file' => esc_html__( 'Media File', 'elementor' ),
329 'custom' => esc_html__( 'Custom URL', 'elementor' ),
330 ],
331 ]
332 );
333
334 $this->add_control(
335 'link',
336 [
337 'label' => esc_html__( 'Link', 'elementor' ),
338 'type' => Controls_Manager::URL,
339 'condition' => [
340 'link_to' => 'custom',
341 ],
342 'show_label' => false,
343 'dynamic' => [
344 'active' => true,
345 ],
346 ]
347 );
348
349 $this->add_control(
350 'open_lightbox',
351 [
352 'label' => esc_html__( 'Lightbox', 'elementor' ),
353 'type' => Controls_Manager::SELECT,
354 'description' => sprintf(
355 /* translators: 1: Link open tag, 2: Link close tag. */
356 esc_html__( 'Manage your site’s lightbox settings in the %1$sLightbox panel%2$s.', 'elementor' ),
357 '<a href="javascript: $e.run( \'panel/global/open\' ).then( () => $e.route( \'panel/global/settings-lightbox\' ) )">',
358 '</a>'
359 ),
360 'default' => 'default',
361 'options' => [
362 'default' => esc_html__( 'Default', 'elementor' ),
363 'yes' => esc_html__( 'Yes', 'elementor' ),
364 'no' => esc_html__( 'No', 'elementor' ),
365 ],
366 'condition' => [
367 'link_to' => 'file',
368 ],
369 ]
370 );
371
372 $this->add_control(
373 'caption_type',
374 [
375 'label' => esc_html__( 'Caption', 'elementor' ),
376 'type' => Controls_Manager::SELECT,
377 'default' => '',
378 'options' => [
379 '' => esc_html__( 'None', 'elementor' ),
380 'title' => esc_html__( 'Title', 'elementor' ),
381 'caption' => esc_html__( 'Caption', 'elementor' ),
382 'description' => esc_html__( 'Description', 'elementor' ),
383 ],
384 ]
385 );
386
387 if ( ! Utils::has_pro() ) {
388 $this->add_control(
389 Utils::IMAGE_CAROUSEL . '_promotion',
390 [
391 'label' => esc_html__( 'Carousel PRO widget', 'elementor' ),
392 'type' => Promotion_Control::TYPE,
393 ]
394 );
395 }
396
397 $this->end_controls_section();
398
399 $this->start_controls_section(
400 'section_additional_options',
401 [
402 'label' => esc_html__( 'Additional Options', 'elementor' ),
403 ]
404 );
405
406 $this->add_control(
407 'lazyload',
408 [
409 'label' => esc_html__( 'Lazyload', 'elementor' ),
410 'type' => Controls_Manager::SWITCHER,
411 'frontend_available' => true,
412 ]
413 );
414
415 $this->add_control(
416 'autoplay',
417 [
418 'label' => esc_html__( 'Autoplay', 'elementor' ),
419 'type' => Controls_Manager::SWITCHER,
420 'label_on' => esc_html__( 'Yes', 'elementor' ),
421 'label_off' => esc_html__( 'No', 'elementor' ),
422 'return_value' => 'yes',
423 'default' => 'yes',
424 'frontend_available' => true,
425 ]
426 );
427
428 $this->add_control(
429 'pause_on_hover',
430 [
431 'label' => esc_html__( 'Pause on Hover', 'elementor' ),
432 'type' => Controls_Manager::SWITCHER,
433 'label_on' => esc_html__( 'Yes', 'elementor' ),
434 'label_off' => esc_html__( 'No', 'elementor' ),
435 'return_value' => 'yes',
436 'default' => 'yes',
437 'condition' => [
438 'autoplay' => 'yes',
439 ],
440 'render_type' => 'none',
441 'frontend_available' => true,
442 ]
443 );
444
445 $this->add_control(
446 'pause_on_interaction',
447 [
448 'label' => esc_html__( 'Pause on Interaction', 'elementor' ),
449 'type' => Controls_Manager::SWITCHER,
450 'label_on' => esc_html__( 'Yes', 'elementor' ),
451 'label_off' => esc_html__( 'No', 'elementor' ),
452 'return_value' => 'yes',
453 'default' => 'yes',
454 'condition' => [
455 'autoplay' => 'yes',
456 ],
457 'frontend_available' => true,
458 ]
459 );
460
461 $this->add_control(
462 'autoplay_speed',
463 [
464 'label' => esc_html__( 'Autoplay Speed', 'elementor' ),
465 'type' => Controls_Manager::NUMBER,
466 'default' => 5000,
467 'condition' => [
468 'autoplay' => 'yes',
469 ],
470 'render_type' => 'none',
471 'frontend_available' => true,
472 ]
473 );
474
475 // Loop requires a re-render so no 'render_type = none'
476 $this->add_control(
477 'infinite',
478 [
479 'label' => esc_html__( 'Infinite Loop', 'elementor' ),
480 'type' => Controls_Manager::SWITCHER,
481 'label_on' => esc_html__( 'Yes', 'elementor' ),
482 'label_off' => esc_html__( 'No', 'elementor' ),
483 'return_value' => 'yes',
484 'default' => 'yes',
485 'frontend_available' => true,
486 ]
487 );
488
489 $this->add_control(
490 'effect',
491 [
492 'label' => esc_html__( 'Effect', 'elementor' ),
493 'type' => Controls_Manager::SELECT,
494 'default' => 'slide',
495 'options' => [
496 'slide' => esc_html__( 'Slide', 'elementor' ),
497 'fade' => esc_html__( 'Fade', 'elementor' ),
498 ],
499 'condition' => [
500 'slides_to_show' => '1',
501 ],
502 'frontend_available' => true,
503 ]
504 );
505
506 $this->add_control(
507 'speed',
508 [
509 'label' => esc_html__( 'Animation Speed', 'elementor' ),
510 'type' => Controls_Manager::NUMBER,
511 'default' => 500,
512 'render_type' => 'none',
513 'frontend_available' => true,
514 ]
515 );
516
517 $this->add_control(
518 'direction',
519 [
520 'label' => esc_html__( 'Direction', 'elementor' ),
521 'type' => Controls_Manager::SELECT,
522 'default' => 'ltr',
523 'options' => [
524 'ltr' => esc_html__( 'Left', 'elementor' ),
525 'rtl' => esc_html__( 'Right', 'elementor' ),
526 ],
527 ]
528 );
529
530 $this->end_controls_section();
531
532 $this->start_controls_section(
533 'section_style_navigation',
534 [
535 'label' => esc_html__( 'Navigation', 'elementor' ),
536 'tab' => Controls_Manager::TAB_STYLE,
537 'condition' => [
538 'navigation' => [ 'arrows', 'dots', 'both' ],
539 ],
540 ]
541 );
542
543 $this->add_control(
544 'heading_style_arrows',
545 [
546 'label' => esc_html__( 'Arrows', 'elementor' ),
547 'type' => Controls_Manager::HEADING,
548 'separator' => 'before',
549 'condition' => [
550 'navigation' => [ 'arrows', 'both' ],
551 ],
552 ]
553 );
554
555 $this->add_control(
556 'arrows_position',
557 [
558 'label' => esc_html__( 'Position', 'elementor' ),
559 'type' => Controls_Manager::SELECT,
560 'default' => 'inside',
561 'options' => [
562 'inside' => esc_html__( 'Inside', 'elementor' ),
563 'outside' => esc_html__( 'Outside', 'elementor' ),
564 ],
565 'prefix_class' => 'elementor-arrows-position-',
566 'condition' => [
567 'navigation' => [ 'arrows', 'both' ],
568 ],
569 ]
570 );
571
572 $this->add_responsive_control(
573 'arrows_size',
574 [
575 'label' => esc_html__( 'Size', 'elementor' ),
576 'type' => Controls_Manager::SLIDER,
577 'size_units' => [ 'px', 'em', 'rem', 'custom' ],
578 'range' => [
579 'px' => [
580 'max' => 100,
581 ],
582 ],
583 'selectors' => [
584 '{{WRAPPER}} .elementor-swiper-button.elementor-swiper-button-prev, {{WRAPPER}} .elementor-swiper-button.elementor-swiper-button-next' => 'font-size: {{SIZE}}{{UNIT}};',
585 ],
586 'condition' => [
587 'navigation' => [ 'arrows', 'both' ],
588 ],
589 ]
590 );
591
592 $this->add_control(
593 'arrows_color',
594 [
595 'label' => esc_html__( 'Color', 'elementor' ),
596 'type' => Controls_Manager::COLOR,
597 'selectors' => [
598 '{{WRAPPER}} .elementor-swiper-button.elementor-swiper-button-prev, {{WRAPPER}} .elementor-swiper-button.elementor-swiper-button-next' => 'color: {{VALUE}};',
599 '{{WRAPPER}} .elementor-swiper-button.elementor-swiper-button-prev svg, {{WRAPPER}} .elementor-swiper-button.elementor-swiper-button-next svg' => 'fill: {{VALUE}};',
600 ],
601 'condition' => [
602 'navigation' => [ 'arrows', 'both' ],
603 ],
604 ]
605 );
606
607 $this->add_control(
608 'heading_style_dots',
609 [
610 'label' => esc_html__( 'Pagination', 'elementor' ),
611 'type' => Controls_Manager::HEADING,
612 'separator' => 'before',
613 'condition' => [
614 'navigation' => [ 'dots', 'both' ],
615 ],
616 ]
617 );
618
619 $this->add_control(
620 'dots_position',
621 [
622 'label' => esc_html__( 'Position', 'elementor' ),
623 'type' => Controls_Manager::SELECT,
624 'default' => 'outside',
625 'options' => [
626 'outside' => esc_html__( 'Outside', 'elementor' ),
627 'inside' => esc_html__( 'Inside', 'elementor' ),
628 ],
629 'prefix_class' => 'elementor-pagination-position-',
630 'condition' => [
631 'navigation' => [ 'dots', 'both' ],
632 ],
633 ]
634 );
635
636 $this->add_responsive_control(
637 'dots_gap',
638 [
639 'label' => esc_html__( 'Space Between Dots', 'elementor' ),
640 'type' => Controls_Manager::SLIDER,
641 'size_units' => [ 'px', 'em', 'rem', 'custom' ],
642 'range' => [
643 'px' => [
644 'max' => 20,
645 ],
646 ],
647 'selectors' => [
648 '{{WRAPPER}} .swiper-pagination-bullet' => '--swiper-pagination-bullet-horizontal-gap: {{SIZE}}{{UNIT}}; --swiper-pagination-bullet-vertical-gap: {{SIZE}}{{UNIT}};',
649 ],
650 'condition' => [
651 'navigation' => [ 'dots', 'both' ],
652 ],
653 ]
654 );
655
656 $this->add_responsive_control(
657 'dots_size',
658 [
659 'label' => esc_html__( 'Size', 'elementor' ),
660 'type' => Controls_Manager::SLIDER,
661 'size_units' => [ 'px', 'em', 'rem', 'custom' ],
662 'range' => [
663 'px' => [
664 'max' => 20,
665 ],
666 ],
667 'selectors' => [
668 '{{WRAPPER}} .swiper-pagination-bullet' => 'width: {{SIZE}}{{UNIT}}; height: {{SIZE}}{{UNIT}};',
669 ],
670 'condition' => [
671 'navigation' => [ 'dots', 'both' ],
672 ],
673 ]
674 );
675
676 $this->add_control(
677 'dots_inactive_color',
678 [
679 'label' => esc_html__( 'Color', 'elementor' ),
680 'type' => Controls_Manager::COLOR,
681 'selectors' => [
682 // The opacity property will override the default inactive dot color which is opacity 0.2.
683 '{{WRAPPER}} .swiper-pagination-bullet:not(.swiper-pagination-bullet-active)' => 'background: {{VALUE}}; opacity: 1',
684 ],
685 'condition' => [
686 'navigation' => [ 'dots', 'both' ],
687 ],
688 ]
689 );
690
691 $this->add_control(
692 'dots_color',
693 [
694 'label' => esc_html__( 'Active Color', 'elementor' ),
695 'type' => Controls_Manager::COLOR,
696 'selectors' => [
697 '{{WRAPPER}} .swiper-pagination-bullet' => 'background: {{VALUE}};',
698 ],
699 'condition' => [
700 'navigation' => [ 'dots', 'both' ],
701 ],
702 ]
703 );
704
705 $this->end_controls_section();
706
707 $this->start_controls_section(
708 'section_style_image',
709 [
710 'label' => esc_html__( 'Image', 'elementor' ),
711 'tab' => Controls_Manager::TAB_STYLE,
712 ]
713 );
714
715 $this->add_responsive_control(
716 'gallery_vertical_align',
717 [
718 'label' => esc_html__( 'Vertical Align', 'elementor' ),
719 'type' => Controls_Manager::CHOOSE,
720 'options' => [
721 'flex-start' => [
722 'title' => esc_html__( 'Start', 'elementor' ),
723 'icon' => 'eicon-v-align-top',
724 ],
725 'center' => [
726 'title' => esc_html__( 'Center', 'elementor' ),
727 'icon' => 'eicon-v-align-middle',
728 ],
729 'flex-end' => [
730 'title' => esc_html__( 'End', 'elementor' ),
731 'icon' => 'eicon-v-align-bottom',
732 ],
733 ],
734 'condition' => [
735 'slides_to_show!' => '1',
736 ],
737 'selectors' => [
738 '{{WRAPPER}} .swiper-wrapper' => 'display: flex; align-items: {{VALUE}};',
739 ],
740 ]
741 );
742
743 $this->add_control(
744 'image_spacing',
745 [
746 'label' => esc_html__( 'Spacing', 'elementor' ),
747 'type' => Controls_Manager::SELECT,
748 'options' => [
749 '' => esc_html__( 'Default', 'elementor' ),
750 'custom' => esc_html__( 'Custom', 'elementor' ),
751 ],
752 'default' => '',
753 'condition' => [
754 'slides_to_show!' => '1',
755 ],
756 ]
757 );
758
759 $this->add_responsive_control(
760 'image_spacing_custom',
761 [
762 'label' => esc_html__( 'Image Spacing', 'elementor' ),
763 'type' => Controls_Manager::SLIDER,
764 'size_units' => [ 'px' ],
765 'range' => [
766 'px' => [
767 'max' => 100,
768 ],
769 ],
770 'default' => [
771 'size' => 20,
772 ],
773 'condition' => [
774 'image_spacing' => 'custom',
775 'slides_to_show!' => '1',
776 ],
777 'frontend_available' => true,
778 'render_type' => 'none',
779 'separator' => 'after',
780 ]
781 );
782
783 $this->add_group_control(
784 Group_Control_Border::get_type(),
785 [
786 'name' => 'image_border',
787 'selector' => '{{WRAPPER}} .elementor-image-carousel-wrapper .elementor-image-carousel .swiper-slide-image',
788 ]
789 );
790
791 $this->add_responsive_control(
792 'image_border_radius',
793 [
794 'label' => esc_html__( 'Border Radius', 'elementor' ),
795 'type' => Controls_Manager::DIMENSIONS,
796 'size_units' => [ 'px', '%', 'em', 'rem', 'custom' ],
797 'selectors' => [
798 '{{WRAPPER}} .elementor-image-carousel-wrapper .elementor-image-carousel .swiper-slide-image' => 'border-radius: {{TOP}}{{UNIT}} {{RIGHT}}{{UNIT}} {{BOTTOM}}{{UNIT}} {{LEFT}}{{UNIT}};',
799 ],
800 ]
801 );
802
803 $this->end_controls_section();
804
805 $this->start_controls_section(
806 'section_caption',
807 [
808 'label' => esc_html__( 'Caption', 'elementor' ),
809 'tab' => Controls_Manager::TAB_STYLE,
810 'condition' => [
811 'caption_type!' => '',
812 ],
813 ]
814 );
815
816 $this->add_responsive_control(
817 'caption_align',
818 [
819 'label' => esc_html__( 'Alignment', 'elementor' ),
820 'type' => Controls_Manager::CHOOSE,
821 'options' => [
822 'left' => [
823 'title' => esc_html__( 'Left', 'elementor' ),
824 'icon' => 'eicon-text-align-left',
825 ],
826 'center' => [
827 'title' => esc_html__( 'Center', 'elementor' ),
828 'icon' => 'eicon-text-align-center',
829 ],
830 'right' => [
831 'title' => esc_html__( 'Right', 'elementor' ),
832 'icon' => 'eicon-text-align-right',
833 ],
834 'justify' => [
835 'title' => esc_html__( 'Justified', 'elementor' ),
836 'icon' => 'eicon-text-align-justify',
837 ],
838 ],
839 'default' => 'center',
840 'selectors' => [
841 '{{WRAPPER}} .elementor-image-carousel-caption' => 'text-align: {{VALUE}};',
842 ],
843 ]
844 );
845
846 $this->add_control(
847 'caption_text_color',
848 [
849 'label' => esc_html__( 'Text Color', 'elementor' ),
850 'type' => Controls_Manager::COLOR,
851 'default' => '',
852 'selectors' => [
853 '{{WRAPPER}} .elementor-image-carousel-caption' => 'color: {{VALUE}};',
854 ],
855 ]
856 );
857
858 $this->add_group_control(
859 Group_Control_Typography::get_type(),
860 [
861 'name' => 'caption_typography',
862 'global' => [
863 'default' => Global_Colors::COLOR_ACCENT,
864 ],
865 'selector' => '{{WRAPPER}} .elementor-image-carousel-caption',
866 ]
867 );
868
869 $this->add_group_control(
870 Group_Control_Text_Shadow::get_type(),
871 [
872 'name' => 'caption_shadow',
873 'selector' => '{{WRAPPER}} .elementor-image-carousel-caption',
874 ]
875 );
876
877 $this->add_responsive_control(
878 'caption_space',
879 [
880 'label' => esc_html__( 'Spacing', 'elementor' ),
881 'type' => Controls_Manager::SLIDER,
882 'size_units' => [ 'px', '%', 'em', 'rem', 'custom' ],
883 'selectors' => [
884 '{{WRAPPER}} .elementor-image-carousel-caption' => 'margin-block-start: {{SIZE}}{{UNIT}};',
885 ],
886 ]
887 );
888
889 $this->end_controls_section();
890 }
891
892 /**
893 * Render image carousel widget output on the frontend.
894 *
895 * Written in PHP and used to generate the final HTML.
896 *
897 * @since 1.0.0
898 * @access protected
899 */
900 protected function render() {
901 $settings = $this->get_settings_for_display();
902
903 $lazyload = 'yes' === $settings['lazyload'];
904
905 if ( empty( $settings['carousel'] ) ) {
906 return;
907 }
908
909 $slides = [];
910
911 foreach ( $settings['carousel'] as $index => $attachment ) {
912 $image_url = Group_Control_Image_Size::get_attachment_image_src( $attachment['id'], 'thumbnail', $settings );
913
914 if ( ! $image_url && isset( $attachment['url'] ) ) {
915 $image_url = $attachment['url'];
916 }
917
918 if ( $lazyload ) {
919 $image_html = '<img class="swiper-slide-image swiper-lazy" data-src="' . esc_attr( $image_url ) . '" alt="' . esc_attr( Control_Media::get_image_alt( $attachment ) ) . '" />';
920 } else {
921 $image_html = '<img class="swiper-slide-image" src="' . esc_attr( $image_url ) . '" alt="' . esc_attr( Control_Media::get_image_alt( $attachment ) ) . '" />';
922 }
923
924 $link_tag = '';
925
926 $link = $this->get_link_url( $attachment, $settings );
927
928 if ( $link ) {
929 $link_key = 'link_' . $index;
930
931 $this->add_lightbox_data_attributes( $link_key, $attachment['id'], $settings['open_lightbox'], $this->get_id() );
932
933 if ( Plugin::$instance->editor->is_edit_mode() ) {
934 $this->add_render_attribute( $link_key, [
935 'class' => 'elementor-clickable',
936 ] );
937 }
938
939 $this->add_link_attributes( $link_key, $link );
940
941 $link_tag = '<a ' . $this->get_render_attribute_string( $link_key ) . '>';
942 }
943
944 $image_caption = $this->get_image_caption( $attachment );
945
946 $slide_count = $index + 1;
947 $slide_setting_key = 'swiper_slide_' . $index;
948
949 $this->add_render_attribute( $slide_setting_key, [
950 'class' => 'swiper-slide',
951 'role' => 'group',
952 'aria-roledescription' => 'slide',
953 'aria-label' => sprintf(
954 /* translators: 1: Slide count, 2: Total slides count. */
955 esc_html__( '%1$s of %2$s', 'elementor' ),
956 $slide_count,
957 count( $settings['carousel'] )
958 ),
959 ] );
960
961 $slide_html = '<div ' . $this->get_render_attribute_string( $slide_setting_key ) . '>' . $link_tag . '<figure class="swiper-slide-inner">' . $image_html;
962
963 if ( $lazyload ) {
964 $slide_html .= '<div class="swiper-lazy-preloader"></div>';
965 }
966
967 if ( ! empty( $image_caption ) ) {
968 $slide_html .= '<figcaption class="elementor-image-carousel-caption">' . wp_kses_post( $image_caption ) . '</figcaption>';
969 }
970
971 $slide_html .= '</figure>';
972
973 if ( $link ) {
974 $slide_html .= '</a>';
975 }
976
977 $slide_html .= '</div>';
978
979 $slides[] = $slide_html;
980
981 }
982
983 if ( empty( $slides ) ) {
984 return;
985 }
986
987 $swiper_class = 'swiper';
988 $has_autoplay_enabled = 'yes' === $this->get_settings_for_display( 'autoplay' );
989
990 $this->add_render_attribute( [
991 'carousel' => [
992 'class' => 'elementor-image-carousel swiper-wrapper',
993 'aria-live' => $has_autoplay_enabled ? 'off' : 'polite',
994 ],
995 'carousel-wrapper' => [
996 'class' => 'elementor-image-carousel-wrapper ' . $swiper_class,
997 'role' => 'region',
998 'aria-roledescription' => 'carousel',
999 'aria-label' => $settings['carousel_name'],
1000 'dir' => $settings['direction'],
1001 ],
1002 ] );
1003
1004 $show_dots = ( in_array( $settings['navigation'], [ 'dots', 'both' ] ) );
1005 $show_arrows = ( in_array( $settings['navigation'], [ 'arrows', 'both' ] ) );
1006
1007 if ( 'yes' === $settings['image_stretch'] ) {
1008 $this->add_render_attribute( 'carousel', 'class', 'swiper-image-stretch' );
1009 }
1010
1011 $slides_count = count( $settings['carousel'] );
1012 ?>
1013 <div <?php $this->print_render_attribute_string( 'carousel-wrapper' ); ?>>
1014 <div <?php $this->print_render_attribute_string( 'carousel' ); ?>>
1015 <?php // PHPCS - $slides contains the slides content, all the relevant content is escaped above. ?>
1016 <?php echo implode( '', $slides ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped ?>
1017 </div>
1018 <?php if ( 1 < $slides_count ) : ?>
1019 <?php if ( $show_arrows ) : ?>
1020 <div class="elementor-swiper-button elementor-swiper-button-prev" role="button" tabindex="0">
1021 <?php $this->render_swiper_button( 'previous' ); ?>
1022 </div>
1023 <div class="elementor-swiper-button elementor-swiper-button-next" role="button" tabindex="0">
1024 <?php $this->render_swiper_button( 'next' ); ?>
1025 </div>
1026 <?php endif; ?>
1027
1028 <?php if ( $show_dots ) : ?>
1029 <div class="swiper-pagination"></div>
1030 <?php endif; ?>
1031 <?php endif; ?>
1032 </div>
1033 <?php
1034 }
1035
1036 /**
1037 * Retrieve image carousel link URL.
1038 *
1039 * @since 1.0.0
1040 * @access private
1041 *
1042 * @param array $attachment
1043 * @param object $instance
1044 *
1045 * @return array|string|false An array/string containing the attachment URL, or false if no link.
1046 */
1047 private function get_link_url( $attachment, $instance ) {
1048 if ( 'none' === $instance['link_to'] ) {
1049 return false;
1050 }
1051
1052 if ( 'custom' === $instance['link_to'] ) {
1053 if ( empty( $instance['link']['url'] ) ) {
1054 return false;
1055 }
1056
1057 return $instance['link'];
1058 }
1059
1060 return [
1061 'url' => wp_get_attachment_url( $attachment['id'] ),
1062 ];
1063 }
1064
1065 /**
1066 * Retrieve image carousel caption.
1067 *
1068 * @since 1.2.0
1069 * @access private
1070 *
1071 * @param array $attachment
1072 *
1073 * @return string The caption of the image.
1074 */
1075 private function get_image_caption( $attachment ) {
1076 $caption_type = $this->get_settings_for_display( 'caption_type' );
1077
1078 if ( empty( $caption_type ) ) {
1079 return '';
1080 }
1081
1082 $attachment_post = get_post( $attachment['id'] );
1083
1084 if ( Utils::has_invalid_post_permissions( $attachment_post ) ) {
1085 return '';
1086 }
1087
1088 if ( 'caption' === $caption_type ) {
1089 return $attachment_post->post_excerpt;
1090 }
1091
1092 if ( 'title' === $caption_type ) {
1093 return $attachment_post->post_title;
1094 }
1095
1096 if ( empty( $attachment_post->post_content ) ) {
1097 return '';
1098 }
1099
1100 return $attachment_post->post_content;
1101 }
1102
1103 private function render_swiper_button( $type ) {
1104 $direction = 'next' === $type ? 'right' : 'left';
1105 $icon_settings = $this->get_settings_for_display( 'navigation_' . $type . '_icon' );
1106
1107 if ( empty( $icon_settings['value'] ) ) {
1108 $icon_settings = [
1109 'library' => 'eicons',
1110 'value' => 'eicon-chevron-' . $direction,
1111 ];
1112 }
1113
1114 Icons_Manager::render_icon( $icon_settings, [ 'aria-hidden' => 'true' ] );
1115 }
1116 }
1117