PluginProbe ʕ •ᴥ•ʔ
Elementor Website Builder – more than just a page builder / 4.0.0-dev3
Elementor Website Builder – more than just a page builder v4.0.0-dev3
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 5 months ago accordion.php 9 months ago alert.php 9 months ago audio.php 1 year ago button.php 9 months ago common-base.php 8 months ago common-optimized.php 1 year ago common.php 1 year ago counter.php 5 months ago divider.php 7 months ago google-maps.php 1 year ago heading.php 4 months ago html.php 1 year ago icon-box.php 5 months ago icon-list.php 5 months ago icon.php 5 months ago image-box.php 5 months ago image-carousel.php 5 months ago image-gallery.php 5 months ago image.php 5 months ago inner-section.php 2 years ago menu-anchor.php 1 year ago progress.php 11 months ago rating.php 9 months ago read-more.php 1 year ago shortcode.php 1 year ago sidebar.php 1 year ago social-icons.php 2 months ago spacer.php 1 year ago star-rating.php 5 months ago tabs.php 5 months ago testimonial.php 5 months ago text-editor.php 5 months ago toggle.php 9 months ago video.php 7 months ago wordpress.php 1 year ago
image-carousel.php
1147 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 /**
96 * Get script dependencies.
97 *
98 * Retrieve the list of script dependencies the widget requires.
99 *
100 * @since 3.27.0
101 * @access public
102 *
103 * @return array Widget script dependencies.
104 */
105 public function get_script_depends(): array {
106 return [ 'swiper' ];
107 }
108
109 public function has_widget_inner_wrapper(): bool {
110 return ! Plugin::$instance->experiments->is_feature_active( 'e_optimized_markup' );
111 }
112
113 /**
114 * Get widget upsale data.
115 *
116 * Retrieve the widget promotion data.
117 *
118 * @since 3.18.0
119 * @access protected
120 *
121 * @return array Widget promotion data.
122 */
123 protected function get_upsale_data() {
124 return [
125 'condition' => ! Utils::has_pro(),
126 'image' => esc_url( ELEMENTOR_ASSETS_URL . 'images/go-pro.svg' ),
127 'image_alt' => esc_attr__( 'Upgrade', 'elementor' ),
128 'description' => esc_html__( 'Gain complete freedom to design every slide with Elementor"s Pro Carousel.', 'elementor' ),
129 'upgrade_url' => esc_url( 'https://go.elementor.com/go-pro-image-carousel-widget/' ),
130 'upgrade_text' => esc_html__( 'Upgrade Now', 'elementor' ),
131 ];
132 }
133
134 /**
135 * Register image carousel widget controls.
136 *
137 * Adds different input fields to allow the user to change and customize the widget settings.
138 *
139 * @since 3.1.0
140 * @access protected
141 */
142 protected function register_controls() {
143 $this->start_controls_section(
144 'section_image_carousel',
145 [
146 'label' => esc_html__( 'Image Carousel', 'elementor' ),
147 ]
148 );
149
150 $this->add_control(
151 'carousel_name',
152 [
153 'label' => esc_html__( 'Carousel Name', 'elementor' ),
154 'type' => Controls_Manager::TEXT,
155 'default' => esc_html__( 'Image Carousel', 'elementor' ),
156 ]
157 );
158
159 $this->add_control(
160 'carousel',
161 [
162 'label' => esc_html__( 'Add Images', 'elementor' ),
163 'type' => Controls_Manager::GALLERY,
164 'default' => [],
165 'show_label' => false,
166 'dynamic' => [
167 'active' => true,
168 ],
169 ]
170 );
171
172 $this->add_group_control(
173 Group_Control_Image_Size::get_type(),
174 [
175 'name' => 'thumbnail', // Usage: `{name}_size` and `{name}_custom_dimension`, in this case `thumbnail_size` and `thumbnail_custom_dimension`.
176 ]
177 );
178
179 $slides_to_show = range( 1, 10 );
180 $slides_to_show = array_combine( $slides_to_show, $slides_to_show );
181
182 $this->add_responsive_control(
183 'slides_to_show',
184 [
185 'label' => esc_html__( 'Slides to Show', 'elementor' ),
186 'type' => Controls_Manager::SELECT,
187 'options' => [
188 '' => esc_html__( 'Default', 'elementor' ),
189 ] + $slides_to_show,
190 'frontend_available' => true,
191 'render_type' => 'template',
192 'selectors' => [
193 '{{WRAPPER}}' => '--e-image-carousel-slides-to-show: {{VALUE}}',
194 ],
195 'content_classes' => 'elementor-control-field-select-small',
196 ]
197 );
198
199 $this->add_responsive_control(
200 'slides_to_scroll',
201 [
202 'label' => esc_html__( 'Slides to Scroll', 'elementor' ),
203 'type' => Controls_Manager::SELECT,
204 'description' => esc_html__( 'Set how many slides are scrolled per swipe.', 'elementor' ),
205 'options' => [
206 '' => esc_html__( 'Default', 'elementor' ),
207 ] + $slides_to_show,
208 'condition' => [
209 'slides_to_show!' => '1',
210 ],
211 'frontend_available' => true,
212 'content_classes' => 'elementor-control-field-select-small',
213 ]
214 );
215
216 $this->add_control(
217 'image_stretch',
218 [
219 'label' => esc_html__( 'Image Stretch', 'elementor' ),
220 'type' => Controls_Manager::SELECT,
221 'default' => 'no',
222 'options' => [
223 'no' => esc_html__( 'No', 'elementor' ),
224 'yes' => esc_html__( 'Yes', 'elementor' ),
225 ],
226 ]
227 );
228
229 $this->add_control(
230 'navigation',
231 [
232 'label' => esc_html__( 'Navigation', 'elementor' ),
233 'type' => Controls_Manager::SELECT,
234 'default' => 'both',
235 'options' => [
236 'both' => esc_html__( 'Arrows and Dots', 'elementor' ),
237 'arrows' => esc_html__( 'Arrows', 'elementor' ),
238 'dots' => esc_html__( 'Dots', 'elementor' ),
239 'none' => esc_html__( 'None', 'elementor' ),
240 ],
241 'frontend_available' => true,
242 ]
243 );
244
245 $this->add_control(
246 'navigation_previous_icon',
247 [
248 'label' => esc_html__( 'Previous Arrow Icon', 'elementor' ),
249 'type' => Controls_Manager::ICONS,
250 'fa4compatibility' => 'icon',
251 'skin' => 'inline',
252 'label_block' => false,
253 'skin_settings' => [
254 'inline' => [
255 'none' => [
256 'label' => 'Default',
257 'icon' => 'eicon-chevron-left',
258 ],
259 'icon' => [
260 'icon' => 'eicon-star',
261 ],
262 ],
263 ],
264 'recommended' => [
265 'fa-regular' => [
266 'arrow-alt-circle-left',
267 'caret-square-left',
268 ],
269 'fa-solid' => [
270 'angle-double-left',
271 'angle-left',
272 'arrow-alt-circle-left',
273 'arrow-circle-left',
274 'arrow-left',
275 'caret-left',
276 'caret-square-left',
277 'chevron-circle-left',
278 'chevron-left',
279 'long-arrow-alt-left',
280 ],
281 ],
282 'conditions' => [
283 'relation' => 'or',
284 'terms' => [
285 [
286 'name' => 'navigation',
287 'operator' => '=',
288 'value' => 'both',
289 ],
290 [
291 'name' => 'navigation',
292 'operator' => '=',
293 'value' => 'arrows',
294 ],
295 ],
296 ],
297 ]
298 );
299
300 $this->add_control(
301 'navigation_next_icon',
302 [
303 'label' => esc_html__( 'Next Arrow Icon', 'elementor' ),
304 'type' => Controls_Manager::ICONS,
305 'fa4compatibility' => 'icon',
306 'skin' => 'inline',
307 'label_block' => false,
308 'skin_settings' => [
309 'inline' => [
310 'none' => [
311 'label' => 'Default',
312 'icon' => 'eicon-chevron-right',
313 ],
314 'icon' => [
315 'icon' => 'eicon-star',
316 ],
317 ],
318 ],
319 'recommended' => [
320 'fa-regular' => [
321 'arrow-alt-circle-right',
322 'caret-square-right',
323 ],
324 'fa-solid' => [
325 'angle-double-right',
326 'angle-right',
327 'arrow-alt-circle-right',
328 'arrow-circle-right',
329 'arrow-right',
330 'caret-right',
331 'caret-square-right',
332 'chevron-circle-right',
333 'chevron-right',
334 'long-arrow-alt-right',
335 ],
336 ],
337 'conditions' => [
338 'relation' => 'or',
339 'terms' => [
340 [
341 'name' => 'navigation',
342 'operator' => '=',
343 'value' => 'both',
344 ],
345 [
346 'name' => 'navigation',
347 'operator' => '=',
348 'value' => 'arrows',
349 ],
350 ],
351 ],
352 ]
353 );
354
355 $this->add_control(
356 'link_to',
357 [
358 'label' => esc_html__( 'Link', 'elementor' ),
359 'type' => Controls_Manager::SELECT,
360 'default' => 'none',
361 'options' => [
362 'none' => esc_html__( 'None', 'elementor' ),
363 'file' => esc_html__( 'Media File', 'elementor' ),
364 'custom' => esc_html__( 'Custom URL', 'elementor' ),
365 ],
366 ]
367 );
368
369 $this->add_control(
370 'link',
371 [
372 'label' => esc_html__( 'Link', 'elementor' ),
373 'type' => Controls_Manager::URL,
374 'condition' => [
375 'link_to' => 'custom',
376 ],
377 'show_label' => false,
378 'dynamic' => [
379 'active' => true,
380 ],
381 ]
382 );
383
384 $this->add_control(
385 'open_lightbox',
386 [
387 'label' => esc_html__( 'Lightbox', 'elementor' ),
388 'type' => Controls_Manager::SELECT,
389 'description' => sprintf(
390 /* translators: 1: Link open tag, 2: Link close tag. */
391 esc_html__( 'Manage your site’s lightbox settings in the %1$sLightbox panel%2$s.', 'elementor' ),
392 '<a href="javascript: $e.run( \'panel/global/open\' ).then( () => $e.route( \'panel/global/settings-lightbox\' ) )">',
393 '</a>'
394 ),
395 'default' => 'default',
396 'options' => [
397 'default' => esc_html__( 'Default', 'elementor' ),
398 'yes' => esc_html__( 'Yes', 'elementor' ),
399 'no' => esc_html__( 'No', 'elementor' ),
400 ],
401 'condition' => [
402 'link_to' => 'file',
403 ],
404 ]
405 );
406
407 $this->add_control(
408 'caption_type',
409 [
410 'label' => esc_html__( 'Caption', 'elementor' ),
411 'type' => Controls_Manager::SELECT,
412 'default' => '',
413 'options' => [
414 '' => esc_html__( 'None', 'elementor' ),
415 'title' => esc_html__( 'Title', 'elementor' ),
416 'caption' => esc_html__( 'Caption', 'elementor' ),
417 'description' => esc_html__( 'Description', 'elementor' ),
418 ],
419 ]
420 );
421
422 $this->end_controls_section();
423
424 $this->start_controls_section(
425 'section_additional_options',
426 [
427 'label' => esc_html__( 'Additional Options', 'elementor' ),
428 ]
429 );
430
431 $this->add_control(
432 'lazyload',
433 [
434 'label' => esc_html__( 'Lazyload', 'elementor' ),
435 'type' => Controls_Manager::SWITCHER,
436 'frontend_available' => true,
437 ]
438 );
439
440 $this->add_control(
441 'autoplay',
442 [
443 'label' => esc_html__( 'Autoplay', 'elementor' ),
444 'type' => Controls_Manager::SWITCHER,
445 'label_on' => esc_html__( 'Yes', 'elementor' ),
446 'label_off' => esc_html__( 'No', 'elementor' ),
447 'return_value' => 'yes',
448 'default' => 'yes',
449 'frontend_available' => true,
450 ]
451 );
452
453 $this->add_control(
454 'pause_on_hover',
455 [
456 'label' => esc_html__( 'Pause on Hover', 'elementor' ),
457 'type' => Controls_Manager::SWITCHER,
458 'label_on' => esc_html__( 'Yes', 'elementor' ),
459 'label_off' => esc_html__( 'No', 'elementor' ),
460 'return_value' => 'yes',
461 'default' => 'yes',
462 'condition' => [
463 'autoplay' => 'yes',
464 ],
465 'render_type' => 'none',
466 'frontend_available' => true,
467 ]
468 );
469
470 $this->add_control(
471 'pause_on_interaction',
472 [
473 'label' => esc_html__( 'Pause on Interaction', 'elementor' ),
474 'type' => Controls_Manager::SWITCHER,
475 'label_on' => esc_html__( 'Yes', 'elementor' ),
476 'label_off' => esc_html__( 'No', 'elementor' ),
477 'return_value' => 'yes',
478 'default' => 'yes',
479 'condition' => [
480 'autoplay' => 'yes',
481 ],
482 'frontend_available' => true,
483 ]
484 );
485
486 $this->add_control(
487 'autoplay_speed',
488 [
489 'label' => esc_html__( 'Autoplay Speed', 'elementor' ),
490 'type' => Controls_Manager::NUMBER,
491 'default' => 5000,
492 'condition' => [
493 'autoplay' => 'yes',
494 ],
495 'render_type' => 'none',
496 'frontend_available' => true,
497 ]
498 );
499
500 // Loop requires a re-render so no 'render_type = none'
501 $this->add_control(
502 'infinite',
503 [
504 'label' => esc_html__( 'Infinite Loop', 'elementor' ),
505 'type' => Controls_Manager::SWITCHER,
506 'label_on' => esc_html__( 'Yes', 'elementor' ),
507 'label_off' => esc_html__( 'No', 'elementor' ),
508 'return_value' => 'yes',
509 'default' => 'yes',
510 'frontend_available' => true,
511 ]
512 );
513
514 $this->add_control(
515 'effect',
516 [
517 'label' => esc_html__( 'Effect', 'elementor' ),
518 'type' => Controls_Manager::SELECT,
519 'default' => 'slide',
520 'options' => [
521 'slide' => esc_html__( 'Slide', 'elementor' ),
522 'fade' => esc_html__( 'Fade', 'elementor' ),
523 ],
524 'condition' => [
525 'slides_to_show' => '1',
526 ],
527 'frontend_available' => true,
528 ]
529 );
530
531 $this->add_control(
532 'speed',
533 [
534 'label' => esc_html__( 'Animation Speed', 'elementor' ),
535 'type' => Controls_Manager::NUMBER,
536 'default' => 500,
537 'render_type' => 'none',
538 'frontend_available' => true,
539 ]
540 );
541
542 $this->add_control(
543 'direction',
544 [
545 'label' => esc_html__( 'Direction', 'elementor' ),
546 'type' => Controls_Manager::SELECT,
547 'default' => 'ltr',
548 'options' => [
549 'ltr' => esc_html__( 'Left', 'elementor' ),
550 'rtl' => esc_html__( 'Right', 'elementor' ),
551 ],
552 ]
553 );
554
555 $this->end_controls_section();
556
557 $this->start_controls_section(
558 'section_style_navigation',
559 [
560 'label' => esc_html__( 'Navigation', 'elementor' ),
561 'tab' => Controls_Manager::TAB_STYLE,
562 'condition' => [
563 'navigation' => [ 'arrows', 'dots', 'both' ],
564 ],
565 ]
566 );
567
568 $this->add_control(
569 'heading_style_arrows',
570 [
571 'label' => esc_html__( 'Arrows', 'elementor' ),
572 'type' => Controls_Manager::HEADING,
573 'separator' => 'before',
574 'condition' => [
575 'navigation' => [ 'arrows', 'both' ],
576 ],
577 ]
578 );
579
580 $this->add_control(
581 'arrows_position',
582 [
583 'label' => esc_html__( 'Position', 'elementor' ),
584 'type' => Controls_Manager::SELECT,
585 'default' => 'inside',
586 'options' => [
587 'inside' => esc_html__( 'Inside', 'elementor' ),
588 'outside' => esc_html__( 'Outside', 'elementor' ),
589 ],
590 'prefix_class' => 'elementor-arrows-position-',
591 'condition' => [
592 'navigation' => [ 'arrows', 'both' ],
593 ],
594 ]
595 );
596
597 $this->add_responsive_control(
598 'arrows_size',
599 [
600 'label' => esc_html__( 'Size', 'elementor' ),
601 'type' => Controls_Manager::SLIDER,
602 'size_units' => [ 'px', 'em', 'rem', 'custom' ],
603 'range' => [
604 'px' => [
605 'max' => 100,
606 ],
607 ],
608 'selectors' => [
609 '{{WRAPPER}} .elementor-swiper-button.elementor-swiper-button-prev, {{WRAPPER}} .elementor-swiper-button.elementor-swiper-button-next' => 'font-size: {{SIZE}}{{UNIT}};',
610 ],
611 'condition' => [
612 'navigation' => [ 'arrows', 'both' ],
613 ],
614 ]
615 );
616
617 $this->add_control(
618 'arrows_color',
619 [
620 'label' => esc_html__( 'Color', 'elementor' ),
621 'type' => Controls_Manager::COLOR,
622 'selectors' => [
623 '{{WRAPPER}} .elementor-swiper-button.elementor-swiper-button-prev, {{WRAPPER}} .elementor-swiper-button.elementor-swiper-button-next' => 'color: {{VALUE}};',
624 '{{WRAPPER}} .elementor-swiper-button.elementor-swiper-button-prev svg, {{WRAPPER}} .elementor-swiper-button.elementor-swiper-button-next svg' => 'fill: {{VALUE}};',
625 ],
626 'condition' => [
627 'navigation' => [ 'arrows', 'both' ],
628 ],
629 ]
630 );
631
632 $this->add_control(
633 'heading_style_dots',
634 [
635 'label' => esc_html__( 'Pagination', 'elementor' ),
636 'type' => Controls_Manager::HEADING,
637 'separator' => 'before',
638 'condition' => [
639 'navigation' => [ 'dots', 'both' ],
640 ],
641 ]
642 );
643
644 $this->add_control(
645 'dots_position',
646 [
647 'label' => esc_html__( 'Position', 'elementor' ),
648 'type' => Controls_Manager::SELECT,
649 'default' => 'outside',
650 'options' => [
651 'outside' => esc_html__( 'Outside', 'elementor' ),
652 'inside' => esc_html__( 'Inside', 'elementor' ),
653 ],
654 'prefix_class' => 'elementor-pagination-position-',
655 'condition' => [
656 'navigation' => [ 'dots', 'both' ],
657 ],
658 ]
659 );
660
661 $this->add_responsive_control(
662 'dots_gap',
663 [
664 'label' => esc_html__( 'Space Between Dots', 'elementor' ),
665 'type' => Controls_Manager::SLIDER,
666 'size_units' => [ 'px', 'em', 'rem', 'custom' ],
667 'range' => [
668 'px' => [
669 'max' => 20,
670 ],
671 ],
672 'selectors' => [
673 '{{WRAPPER}} .swiper-pagination-bullet' => '--swiper-pagination-bullet-horizontal-gap: {{SIZE}}{{UNIT}}; --swiper-pagination-bullet-vertical-gap: {{SIZE}}{{UNIT}};',
674 ],
675 'condition' => [
676 'navigation' => [ 'dots', 'both' ],
677 ],
678 ]
679 );
680
681 $this->add_responsive_control(
682 'dots_size',
683 [
684 'label' => esc_html__( 'Size', 'elementor' ),
685 'type' => Controls_Manager::SLIDER,
686 'size_units' => [ 'px', 'em', 'rem', 'custom' ],
687 'range' => [
688 'px' => [
689 'max' => 20,
690 ],
691 ],
692 'selectors' => [
693 '{{WRAPPER}} .swiper-pagination-bullet' => 'width: {{SIZE}}{{UNIT}}; height: {{SIZE}}{{UNIT}};',
694 ],
695 'condition' => [
696 'navigation' => [ 'dots', 'both' ],
697 ],
698 ]
699 );
700
701 $this->add_control(
702 'dots_inactive_color',
703 [
704 'label' => esc_html__( 'Color', 'elementor' ),
705 'type' => Controls_Manager::COLOR,
706 'selectors' => [
707 // The opacity property will override the default inactive dot color which is opacity 0.2.
708 '{{WRAPPER}} .swiper-pagination-bullet:not(.swiper-pagination-bullet-active)' => 'background: {{VALUE}}; opacity: 1',
709 ],
710 'condition' => [
711 'navigation' => [ 'dots', 'both' ],
712 ],
713 ]
714 );
715
716 $this->add_control(
717 'dots_color',
718 [
719 'label' => esc_html__( 'Active Color', 'elementor' ),
720 'type' => Controls_Manager::COLOR,
721 'selectors' => [
722 '{{WRAPPER}} .swiper-pagination-bullet' => 'background: {{VALUE}};',
723 ],
724 'condition' => [
725 'navigation' => [ 'dots', 'both' ],
726 ],
727 ]
728 );
729
730 $this->end_controls_section();
731
732 $this->start_controls_section(
733 'section_style_image',
734 [
735 'label' => esc_html__( 'Image', 'elementor' ),
736 'tab' => Controls_Manager::TAB_STYLE,
737 ]
738 );
739
740 $this->add_responsive_control(
741 'gallery_vertical_align',
742 [
743 'label' => esc_html__( 'Vertical Align', 'elementor' ),
744 'type' => Controls_Manager::CHOOSE,
745 'options' => [
746 'flex-start' => [
747 'title' => esc_html__( 'Start', 'elementor' ),
748 'icon' => 'eicon-v-align-top',
749 ],
750 'center' => [
751 'title' => esc_html__( 'Center', 'elementor' ),
752 'icon' => 'eicon-v-align-middle',
753 ],
754 'flex-end' => [
755 'title' => esc_html__( 'End', 'elementor' ),
756 'icon' => 'eicon-v-align-bottom',
757 ],
758 ],
759 'condition' => [
760 'slides_to_show!' => '1',
761 ],
762 'selectors' => [
763 '{{WRAPPER}} .swiper-wrapper' => 'display: flex; align-items: {{VALUE}};',
764 ],
765 ]
766 );
767
768 $this->add_control(
769 'image_spacing',
770 [
771 'label' => esc_html__( 'Spacing', 'elementor' ),
772 'type' => Controls_Manager::SELECT,
773 'options' => [
774 '' => esc_html__( 'Default', 'elementor' ),
775 'custom' => esc_html__( 'Custom', 'elementor' ),
776 ],
777 'default' => '',
778 'condition' => [
779 'slides_to_show!' => '1',
780 ],
781 ]
782 );
783
784 $this->add_responsive_control(
785 'image_spacing_custom',
786 [
787 'label' => esc_html__( 'Image Spacing', 'elementor' ),
788 'type' => Controls_Manager::SLIDER,
789 'size_units' => [ 'px' ],
790 'range' => [
791 'px' => [
792 'max' => 100,
793 ],
794 ],
795 'default' => [
796 'size' => 20,
797 ],
798 'condition' => [
799 'image_spacing' => 'custom',
800 'slides_to_show!' => '1',
801 ],
802 'frontend_available' => true,
803 'render_type' => 'none',
804 'separator' => 'after',
805 ]
806 );
807
808 $this->add_group_control(
809 Group_Control_Border::get_type(),
810 [
811 'name' => 'image_border',
812 'selector' => '{{WRAPPER}} .elementor-image-carousel-wrapper .elementor-image-carousel .swiper-slide-image',
813 ]
814 );
815
816 $this->add_responsive_control(
817 'image_border_radius',
818 [
819 'label' => esc_html__( 'Border Radius', 'elementor' ),
820 'type' => Controls_Manager::DIMENSIONS,
821 'size_units' => [ 'px', '%', 'em', 'rem', 'custom' ],
822 'selectors' => [
823 '{{WRAPPER}} .elementor-image-carousel-wrapper .elementor-image-carousel .swiper-slide-image' => 'border-radius: {{TOP}}{{UNIT}} {{RIGHT}}{{UNIT}} {{BOTTOM}}{{UNIT}} {{LEFT}}{{UNIT}};',
824 ],
825 ]
826 );
827
828 $this->end_controls_section();
829
830 $this->start_controls_section(
831 'section_caption',
832 [
833 'label' => esc_html__( 'Caption', 'elementor' ),
834 'tab' => Controls_Manager::TAB_STYLE,
835 'condition' => [
836 'caption_type!' => '',
837 ],
838 ]
839 );
840
841 $this->add_responsive_control(
842 'caption_align',
843 [
844 'label' => esc_html__( 'Alignment', 'elementor' ),
845 'type' => Controls_Manager::CHOOSE,
846 'options' => [
847 'start' => [
848 'title' => esc_html__( 'Start', 'elementor' ),
849 'icon' => 'eicon-text-align-left',
850 ],
851 'center' => [
852 'title' => esc_html__( 'Center', 'elementor' ),
853 'icon' => 'eicon-text-align-center',
854 ],
855 'end' => [
856 'title' => esc_html__( 'End', 'elementor' ),
857 'icon' => 'eicon-text-align-right',
858 ],
859 'justify' => [
860 'title' => esc_html__( 'Justified', 'elementor' ),
861 'icon' => 'eicon-text-align-justify',
862 ],
863 ],
864 'classes' => 'elementor-control-start-end',
865 'selectors_dictionary' => [
866 'left' => is_rtl() ? 'end' : 'start',
867 'right' => is_rtl() ? 'start' : 'end',
868 ],
869 'default' => 'center',
870 'selectors' => [
871 '{{WRAPPER}} .elementor-image-carousel-caption' => 'text-align: {{VALUE}};',
872 ],
873 ]
874 );
875
876 $this->add_control(
877 'caption_text_color',
878 [
879 'label' => esc_html__( 'Text Color', 'elementor' ),
880 'type' => Controls_Manager::COLOR,
881 'default' => '',
882 'selectors' => [
883 '{{WRAPPER}} .elementor-image-carousel-caption' => 'color: {{VALUE}};',
884 ],
885 ]
886 );
887
888 $this->add_group_control(
889 Group_Control_Typography::get_type(),
890 [
891 'name' => 'caption_typography',
892 'global' => [
893 'default' => Global_Colors::COLOR_ACCENT,
894 ],
895 'selector' => '{{WRAPPER}} .elementor-image-carousel-caption',
896 ]
897 );
898
899 $this->add_group_control(
900 Group_Control_Text_Shadow::get_type(),
901 [
902 'name' => 'caption_shadow',
903 'selector' => '{{WRAPPER}} .elementor-image-carousel-caption',
904 ]
905 );
906
907 $this->add_responsive_control(
908 'caption_space',
909 [
910 'label' => esc_html__( 'Spacing', 'elementor' ),
911 'type' => Controls_Manager::SLIDER,
912 'size_units' => [ 'px', '%', 'em', 'rem', 'custom' ],
913 'selectors' => [
914 '{{WRAPPER}} .elementor-image-carousel-caption' => 'margin-block-start: {{SIZE}}{{UNIT}};',
915 ],
916 ]
917 );
918
919 $this->end_controls_section();
920 }
921
922 /**
923 * Render image carousel widget output on the frontend.
924 *
925 * Written in PHP and used to generate the final HTML.
926 *
927 * @since 1.0.0
928 * @access protected
929 */
930 protected function render() {
931 $settings = $this->get_settings_for_display();
932
933 $lazyload = 'yes' === $settings['lazyload'];
934
935 if ( empty( $settings['carousel'] ) ) {
936 return;
937 }
938
939 $slides = [];
940
941 foreach ( $settings['carousel'] as $index => $attachment ) {
942 $image_url = Group_Control_Image_Size::get_attachment_image_src( $attachment['id'], 'thumbnail', $settings );
943
944 if ( ! $image_url && isset( $attachment['url'] ) ) {
945 $image_url = $attachment['url'];
946 }
947
948 if ( $lazyload ) {
949 $image_html = '<img class="swiper-slide-image swiper-lazy" data-src="' . esc_attr( $image_url ) . '" alt="' . esc_attr( Control_Media::get_image_alt( $attachment ) ) . '" />';
950 } else {
951 $image_html = '<img class="swiper-slide-image" src="' . esc_attr( $image_url ) . '" alt="' . esc_attr( Control_Media::get_image_alt( $attachment ) ) . '" />';
952 }
953
954 $link_tag = '';
955
956 $link = $this->get_link_url( $attachment, $settings );
957
958 if ( $link ) {
959 $link_key = 'link_' . $index;
960
961 $this->add_lightbox_data_attributes( $link_key, $attachment['id'], $settings['open_lightbox'], $this->get_id() );
962
963 if ( Plugin::$instance->editor->is_edit_mode() ) {
964 $this->add_render_attribute( $link_key, [
965 'class' => 'elementor-clickable',
966 ] );
967 }
968
969 $this->add_link_attributes( $link_key, $link );
970
971 $link_tag = '<a ' . $this->get_render_attribute_string( $link_key ) . '>';
972 }
973
974 $image_caption = $this->get_image_caption( $attachment );
975
976 $slide_count = $index + 1;
977 $slide_setting_key = 'swiper_slide_' . $index;
978
979 $this->add_render_attribute( $slide_setting_key, [
980 'class' => 'swiper-slide',
981 'role' => 'group',
982 'aria-roledescription' => 'slide',
983 'aria-label' => sprintf(
984 /* translators: 1: Slide count, 2: Total slides count. */
985 esc_html__( '%1$s of %2$s', 'elementor' ),
986 $slide_count,
987 count( $settings['carousel'] )
988 ),
989 ] );
990
991 $slide_html = '<div ' . $this->get_render_attribute_string( $slide_setting_key ) . '>' . $link_tag . '<figure class="swiper-slide-inner">' . $image_html;
992
993 if ( $lazyload ) {
994 $slide_html .= '<div class="swiper-lazy-preloader"></div>';
995 }
996
997 if ( ! empty( $image_caption ) ) {
998 $slide_html .= '<figcaption class="elementor-image-carousel-caption">' . wp_kses_post( $image_caption ) . '</figcaption>';
999 }
1000
1001 $slide_html .= '</figure>';
1002
1003 if ( $link ) {
1004 $slide_html .= '</a>';
1005 }
1006
1007 $slide_html .= '</div>';
1008
1009 $slides[] = $slide_html;
1010
1011 }
1012
1013 if ( empty( $slides ) ) {
1014 return;
1015 }
1016
1017 $swiper_class = 'swiper';
1018 $has_autoplay_enabled = 'yes' === $this->get_settings_for_display( 'autoplay' );
1019
1020 $this->add_render_attribute( [
1021 'carousel' => [
1022 'class' => 'elementor-image-carousel swiper-wrapper',
1023 'aria-live' => $has_autoplay_enabled ? 'off' : 'polite',
1024 ],
1025 'carousel-wrapper' => [
1026 'class' => 'elementor-image-carousel-wrapper ' . $swiper_class,
1027 'role' => 'region',
1028 'aria-roledescription' => 'carousel',
1029 'aria-label' => $settings['carousel_name'],
1030 'dir' => $settings['direction'],
1031 ],
1032 ] );
1033
1034 $show_dots = ( in_array( $settings['navigation'], [ 'dots', 'both' ] ) );
1035 $show_arrows = ( in_array( $settings['navigation'], [ 'arrows', 'both' ] ) );
1036
1037 if ( 'yes' === $settings['image_stretch'] ) {
1038 $this->add_render_attribute( 'carousel', 'class', 'swiper-image-stretch' );
1039 }
1040
1041 $slides_count = count( $settings['carousel'] );
1042 ?>
1043 <div <?php $this->print_render_attribute_string( 'carousel-wrapper' ); ?>>
1044 <div <?php $this->print_render_attribute_string( 'carousel' ); ?>>
1045 <?php // PHPCS - $slides contains the slides content, all the relevant content is escaped above. ?>
1046 <?php echo implode( '', $slides ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped ?>
1047 </div>
1048 <?php if ( 1 < $slides_count ) : ?>
1049 <?php if ( $show_arrows ) : ?>
1050 <div class="elementor-swiper-button elementor-swiper-button-prev" role="button" tabindex="0">
1051 <?php $this->render_swiper_button( 'previous' ); ?>
1052 </div>
1053 <div class="elementor-swiper-button elementor-swiper-button-next" role="button" tabindex="0">
1054 <?php $this->render_swiper_button( 'next' ); ?>
1055 </div>
1056 <?php endif; ?>
1057
1058 <?php if ( $show_dots ) : ?>
1059 <div class="swiper-pagination"></div>
1060 <?php endif; ?>
1061 <?php endif; ?>
1062 </div>
1063 <?php
1064 }
1065
1066 /**
1067 * Retrieve image carousel link URL.
1068 *
1069 * @since 1.0.0
1070 * @access private
1071 *
1072 * @param array $attachment
1073 * @param object $instance
1074 *
1075 * @return array|string|false An array/string containing the attachment URL, or false if no link.
1076 */
1077 private function get_link_url( $attachment, $instance ) {
1078 if ( 'none' === $instance['link_to'] ) {
1079 return false;
1080 }
1081
1082 if ( 'custom' === $instance['link_to'] ) {
1083 if ( empty( $instance['link']['url'] ) ) {
1084 return false;
1085 }
1086
1087 return $instance['link'];
1088 }
1089
1090 return [
1091 'url' => wp_get_attachment_url( $attachment['id'] ),
1092 ];
1093 }
1094
1095 /**
1096 * Retrieve image carousel caption.
1097 *
1098 * @since 1.2.0
1099 * @access private
1100 *
1101 * @param array $attachment
1102 *
1103 * @return string The caption of the image.
1104 */
1105 private function get_image_caption( $attachment ) {
1106 $caption_type = $this->get_settings_for_display( 'caption_type' );
1107
1108 if ( empty( $caption_type ) ) {
1109 return '';
1110 }
1111
1112 $attachment_post = get_post( $attachment['id'] );
1113
1114 if ( Utils::has_invalid_post_permissions( $attachment_post ) ) {
1115 return '';
1116 }
1117
1118 if ( 'caption' === $caption_type ) {
1119 return $attachment_post->post_excerpt;
1120 }
1121
1122 if ( 'title' === $caption_type ) {
1123 return $attachment_post->post_title;
1124 }
1125
1126 if ( empty( $attachment_post->post_content ) ) {
1127 return '';
1128 }
1129
1130 return $attachment_post->post_content;
1131 }
1132
1133 private function render_swiper_button( $type ) {
1134 $direction = 'next' === $type ? 'right' : 'left';
1135 $icon_settings = $this->get_settings_for_display( 'navigation_' . $type . '_icon' );
1136
1137 if ( empty( $icon_settings['value'] ) ) {
1138 $icon_settings = [
1139 'library' => 'eicons',
1140 'value' => 'eicon-chevron-' . $direction,
1141 ];
1142 }
1143
1144 Icons_Manager::render_icon( $icon_settings, [ 'aria-hidden' => 'true' ] );
1145 }
1146 }
1147