PluginProbe
UiCore Elements – Free widgets and templates for Elementor / 1.3.18
UiCore Elements – Free widgets and templates for Elementor v1.3.18
1.3.18 1.3.17 1.3.16 trunk 1.0.0 1.0.1 1.0.10 1.0.11 1.0.12 1.0.13 1.0.14 1.0.15 1.0.16 1.0.2 1.0.3 1.0.4 1.0.5 1.0.6 1.0.7 1.0.8 1.0.9 1.2.0 1.2.1 1.2.2 1.2.3 All 42 releases
← All changes | includes/widgets/custom-carousel.php +192 -167 1.2.3 → 1.3.18 View file →
@@ -1,6 +1,8 @@
1 1 <?php
2 +
2 3 namespace UiCoreElements;
4 +
3 5 use Elementor\Plugin;
4 6 use Elementor\Controls_Manager;
5 7 use Elementor\Repeater;
6 8 use Elementor\Modules\NestedElements\Controls\Control_Nested_Repeater;
@@ -16,9 +18,10 @@
16 18 * @author Lucas Marini Falbo <[email protected]>
17 19 * @since 1.0.7
18 20 */
19 21
20 -class CustomCarousel extends UiCoreNestedWidget {
22 +class CustomCarousel extends UiCoreNestedWidget
23 +{
21 24
22 25 use Carousel_Trait;
23 26 use Animation_Trait;
24 27 use Item_Style_Component;
@@ -54,43 +57,49 @@
54 57 public function get_scripts()
55 58 {
56 59 return $this->TRAIT_get_carousel_scripts(false);
57 60 }
58 - public function has_widget_inner_wrapper(): bool {
59 - // TODO: remove after 3.30, when the full deprecation of widget innet wrapper is ready
60 - return ! \Elementor\Plugin::$instance->experiments->is_feature_active( 'e_optimized_markup' );
61 - }
61 + public function has_widget_inner_wrapper(): bool
62 + {
63 + // TODO: remove after Optmized Markup experiment is merged to the core
64 + return ! \Elementor\Plugin::$instance->experiments->is_feature_active('e_optimized_markup');
65 + }
62 66
63 67 // Nested required functions
64 - protected function carousel_content_container( int $index ) {
65 - return [
66 - 'elType' => 'container',
67 - 'settings' => [
68 + protected function carousel_content_container(int $index)
69 + {
70 + return [
71 + 'elType' => 'container',
72 + 'settings' => [
68 73 /* translators: %s: Item number */
69 - '_title' => sprintf( esc_html__( 'Item #%s', 'uicore-elements' ), $index ),
70 - 'content_width' => 'full',
74 + '_title' => sprintf(esc_html__('Item #%s', 'uicore-elements'), $index),
75 + 'content_width' => 'full',
71 76 'flex_justify_content' => 'center',
72 77 'flex_align_items' => 'center',
73 - ],
74 - ];
75 - }
76 - protected function get_default_children_elements() {
77 - return [
78 - $this->carousel_content_container( 1 ),
79 - $this->carousel_content_container( 2 ),
80 - $this->carousel_content_container( 3 ),
81 - ];
82 - }
83 - protected function get_default_repeater_title_setting_key() {
84 - return 'carousel_item_title';
85 - }
86 - protected function get_default_children_title() {
78 + ],
79 + ];
80 + }
81 + protected function get_default_children_elements()
82 + {
83 + return [
84 + $this->carousel_content_container(1),
85 + $this->carousel_content_container(2),
86 + $this->carousel_content_container(3),
87 + ];
88 + }
89 + protected function get_default_repeater_title_setting_key()
90 + {
91 + return 'carousel_item_title';
92 + }
93 + protected function get_default_children_title()
94 + {
87 95 /* translators: %d: Item number */
88 - return esc_html__( 'Item #%d', 'uicore-elements' );
89 - }
90 - protected function get_default_children_placeholder_selector() {
91 - return '.swiper-wrapper';
92 - }
96 + return esc_html__('Item #%d', 'uicore-elements');
97 + }
98 + protected function get_default_children_placeholder_selector()
99 + {
100 + return '.swiper-wrapper';
101 + }
93 102
94 103 /**
95 104 * We've set a bool variable to this function because Custom Slider extends this widget and requires one extra control.
96 105 *
@@ -98,12 +107,12 @@
98 107 */
99 108 protected function register_controls(bool $is_slider = false)
100 109 {
101 110
102 - if( !Plugin::$instance->experiments->is_feature_active('nested-elements') ){
103 - $this->nesting_fallback('controls');
104 - return;
105 - }
111 + if (!Plugin::$instance->experiments->is_feature_active('nested-elements')) {
112 + $this->nesting_fallback('controls');
113 + return;
114 + }
106 115
107 116 $this->start_controls_section(
108 117 'section_content',
109 118 [
@@ -111,34 +120,34 @@
111 120 'tab' => Controls_Manager::TAB_CONTENT,
112 121 ]
113 122 );
114 123
115 - $repeater = new Repeater();
124 + $repeater = new Repeater();
116 125
117 - $repeater->add_control(
118 - 'carousel_item_title',
119 - [
120 - 'label' => __('Title', 'uicore-elements'),
121 - 'type' => Controls_Manager::TEXT,
122 - 'render_type' => 'template',
123 - 'dynamic' => [
124 - 'active' => true,
125 - ],
126 - ]
127 - );
126 + $repeater->add_control(
127 + 'carousel_item_title',
128 + [
129 + 'label' => __('Title', 'uicore-elements'),
130 + 'type' => Controls_Manager::TEXT,
131 + 'render_type' => 'template',
132 + 'dynamic' => [
133 + 'active' => true,
134 + ],
135 + ]
136 + );
128 137
129 - $this->add_control(
130 - 'carousel_items',
131 - [
132 - 'type' => Control_Nested_Repeater::CONTROL_TYPE,
133 - 'fields' => $repeater->get_controls(),
134 - 'default' => [
135 - [ 'carousel_item_title' => __( 'Item #1', 'uicore-elements' ) ],
136 - [ 'carousel_item_title' => __( 'Item #2', 'uicore-elements' ) ],
137 - [ 'carousel_item_title' => __( 'Item #3', 'uicore-elements' ) ],
138 - ]
138 + $this->add_control(
139 + 'carousel_items',
140 + [
141 + 'type' => Control_Nested_Repeater::CONTROL_TYPE,
142 + 'fields' => $repeater->get_controls(),
143 + 'default' => [
144 + ['carousel_item_title' => __('Item #1', 'uicore-elements')],
145 + ['carousel_item_title' => __('Item #2', 'uicore-elements')],
146 + ['carousel_item_title' => __('Item #3', 'uicore-elements')],
139 147 ]
140 - );
148 + ]
149 + );
141 150
142 151 $this->end_controls_section();
143 152
144 153 // Additional Carousel Controls
@@ -149,20 +158,20 @@
149 158 'tab' => Controls_Manager::TAB_CONTENT,
150 159 ]
151 160 );
152 161
153 - $this->TRAIT_register_carousel_additional_controls($is_slider); // Carousel Additionals
162 + $this->TRAIT_register_carousel_additional_controls($is_slider); // Carousel Additionals
154 163
155 164 $this->end_controls_section();
156 165
157 166 $this->start_controls_section(
158 - 'section_carousel_settings',
159 - [
160 - 'label' => __('Carousel Settings', 'uicore-elements'),
161 - ]
162 - );
167 + 'section_carousel_settings',
168 + [
169 + 'label' => __('Carousel Settings', 'uicore-elements'),
170 + ]
171 + );
163 172
164 - $this->TRAIT_register_carousel_settings_controls(); // Carousel settings
173 + $this->TRAIT_register_carousel_settings_controls(); // Carousel settings
165 174
166 175 $this->end_controls_section();
167 176
168 177 $this->TRAIT_register_navigation_controls(); // Navigation settings
@@ -167,16 +176,16 @@
167 176
168 177 $this->TRAIT_register_navigation_controls(); // Navigation settings
169 178
170 179 $this->start_controls_section(
171 - 'section_style_review_items',
172 - [
173 - 'label' => esc_html__( 'Items', 'uicore-elements' ),
174 - 'tab' => Controls_Manager::TAB_STYLE,
175 - ]
176 - );
180 + 'section_style_review_items',
181 + [
182 + 'label' => esc_html__('Items', 'uicore-elements'),
183 + 'tab' => Controls_Manager::TAB_STYLE,
184 + ]
185 + );
177 186
178 - $this->TRAIT_register_all_item_style_controls();
187 + $this->TRAIT_register_all_item_style_controls();
179 188
180 189 $this->end_controls_section();
181 190
182 191 $this->TRAIT_register_navigation_style_controls(); // Carousel Navigation Styles
@@ -196,86 +205,75 @@
196 205 // Adds description to loop
197 206 $this->update_control('loop', [
198 207 'description' => esc_html__('Loop preview is disabled here on the editor, due to compatibility issues. But you can test on the front-end, since it works outside the editor.', 'uicore-elements'),
199 208 ]);
200 -
201 209 }
202 210
203 211 public function render()
204 212 {
205 - if( Plugin::$instance->experiments->is_feature_active('nested-elements') == false ){
206 - $this->nesting_fallback();
207 - return;
208 - }
213 + if (Plugin::$instance->experiments->is_feature_active('nested-elements') == false) {
214 + $this->nesting_fallback();
215 + return;
216 + }
209 217
210 218 $items = $this->get_settings_for_display('carousel_items');
211 219 $carousel_items = '';
212 220
213 221 $total_slides = count($items);
214 - $should_duplicate = $this->TRAIT_should_duplicate_slides($total_slides);
215 - $duplicated_slides = [];
222 + $this->TRAIT_render_center_loop_warning($total_slides);
216 223
217 - foreach ( $items as $index => $item ) {
224 + foreach ($items as $index => $item) {
218 225 ob_start();
219 226 $this->render_item($index);
220 227 $current_slide = ob_get_clean();
221 228
222 - if($should_duplicate){
223 - $duplicated_slides[$index] = $current_slide;
224 - }
225 -
226 229 $carousel_items .= $current_slide;
227 230 }
228 231
229 - // Most recent swiper versions requires, if loop, at least one extra slide compared to visible slides
230 - if($should_duplicate) {
231 - $diff = $this->TRAIT_get_duplication_diff($total_slides);
232 - for($i = 0; $i <= $diff; $i++){
233 - $carousel_items .= $duplicated_slides[$i];
234 - }
235 - }
232 +?>
233 + <div class="ui-e-carousel ui-e-nested swiper">
236 234
237 - ?>
238 - <div class="ui-e-carousel swiper">
235 + <div class='swiper-wrapper'>
236 + <?php echo $carousel_items; //phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
237 + ?>
238 + </div>
239 239
240 - <div class='swiper-wrapper'>
241 - <?php echo $carousel_items; //phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped ?>
242 - </div>
240 + </div>
243 241
244 - </div>
245 -
246 - <?php $this->TRAIT_render_carousel_navigations(); ?>
247 - <?php
242 + <?php $this->TRAIT_render_carousel_navigations($total_slides); ?>
243 + <?php
248 244 }
249 245
250 - public function render_item( $index ) {
251 - ?>
252 - <div class="ui-e-wrp swiper-slide" data-hash="<?php echo esc_html($index);?>">
253 - <?php $this->print_child( $index ); ?>
254 - </div>
255 - <?php
246 + public function render_item($index)
247 + {
248 + ?>
249 + <div class="ui-e-wrp swiper-slide" data-hash="<?php echo esc_html($index); ?>">
250 + <?php $this->print_child($index); ?>
251 + </div>
252 + <?php
256 253 }
257 254
258 - public function print_child( $index ) {
259 - $children = $this->get_children();
260 - $child_ids = [];
255 + public function print_child($index)
256 + {
257 + $children = $this->get_children();
258 + $child_ids = [];
261 259
262 - if( empty( $children )){
263 - return;
264 - }
260 + if (empty($children) || ! isset($children[$index])) {
261 + return;
262 + }
265 263
266 - foreach ( $children as $child ) {
267 - $child_ids[] = $child->get_id();
268 - }
264 + foreach ($children as $child) {
265 + $child_ids[] = $child->get_id();
266 + }
269 267
270 - add_filter( 'elementor/frontend/container/should_render', function( $should_render, $container ) use ($child_ids) {
268 + add_filter('elementor/frontend/container/should_render', function ($should_render, $container) use ($child_ids) {
271 269 return $this->add_child_attributes($should_render, $container, $child_ids);
272 - }, 10, 3 );
270 + }, 10, 3);
273 271
274 - $children[ $index ]->print_element();
272 + $children[$index]->print_element();
275 273
276 - remove_filter( 'elementor/frontend/container/should_render', [$this, 'add_child_attributes'] );
277 - }
274 + remove_filter('elementor/frontend/container/should_render', [$this, 'add_child_attributes']);
275 + }
278 276
279 277 /**
280 278 * Adds attributes to child elements containers.
281 279 */
@@ -283,69 +281,96 @@
283 281 {
284 282
285 283 // custom cases may be added here
286 284
287 - if ( in_array( $container->get_id(), $child_ids ) ) {
288 - $container->add_render_attribute( '_wrapper', [
285 + if (in_array($container->get_id(), $child_ids)) {
286 + $container->add_render_attribute('_wrapper', [
289 287 'class' => $classnames,
290 288 ]);
291 289 }
292 290
293 - return $should_render;
291 + return $should_render;
294 292 }
295 293
296 - protected function get_initial_config(): array {
297 - if ( Plugin::$instance->experiments->is_feature_active( 'e_nested_atomic_repeaters' ) ) {
298 - return array_merge( parent::get_initial_config(), [
299 - 'support_improved_repeaters' => true,
300 - 'node' => 'button',
301 - ] );
302 - }
294 + protected function get_initial_config(): array
295 + {
296 + if (Plugin::$instance->experiments->is_feature_active('e_nested_atomic_repeaters')) {
297 + return array_merge(parent::get_initial_config(), [
298 + 'support_improved_repeaters' => true,
299 + 'node' => 'button',
300 + ]);
301 + }
303 302
304 - return parent::get_initial_config();
305 - }
303 + return parent::get_initial_config();
304 + }
306 305
307 - protected function content_template() {
306 + protected function content_template()
307 + {
308 308
309 - if( Plugin::$instance->experiments->is_feature_active('nested-elements') == false ){
310 - return;
311 - }
309 + if (Plugin::$instance->experiments->is_feature_active('nested-elements') == false) {
310 + return;
311 + }
312 312
313 - ?>
314 - <#
315 - var carouselItems = settings.carousel_items,
316 - hideNavigation = settings.animation_style.includes('marquee'),
317 - navigationDots = settings.navigation.includes('dots') && !hideNavigation,
318 - navigationArrows = settings.navigation.includes('arrows') && !hideNavigation,
319 - navigationFraction = settings.navigation.includes('fraction') && !hideNavigation;
313 + ?>
314 + <#
315 + var carouselItems=settings.carousel_items || [],
316 + hideNavigation=settings.animation_style && settings.animation_style.includes('marquee'),
317 + navigationDots=settings.navigation && settings.navigation.includes('dots') && !hideNavigation,
318 + navigationArrows=settings.navigation && settings.navigation.includes('arrows') && !hideNavigation,
319 + navigationFraction=settings.navigation && settings.navigation.includes('fraction') && !hideNavigation,
320 + totalSlides=carouselItems.length,
321 + perView=parseInt(settings.slides_per_view, 10) || 0,
322 + needsCenterLoopWarning=settings.center_slides &&
323 + settings.loop &&
324 + perView % 2===0 &&
325 + totalSlides < (perView + 2),
326 + missingSlides=(perView + 2) - totalSlides;
320 327
321 - var prev = elementor.helpers.renderIcon( view, settings.previous_arrow, { 'aria-hidden': true }, 'i' , 'object' ),
322 - next = elementor.helpers.renderIcon( view, settings.next_arrow, { 'aria-hidden': true }, 'i' , 'object' );
328 + var prev=elementor.helpers.renderIcon(view, settings.previous_arrow, { 'aria-hidden' : true }, 'i' , 'object' ),
329 + next=elementor.helpers.renderIcon(view, settings.next_arrow, { 'aria-hidden' : true }, 'i' , 'object' );
323 330 #>
324 331
325 - <div class="ui-e-carousel swiper {{ elementorFrontend.config.swiperClass }}">
326 - <div class='swiper-wrapper'> </div>
327 - </div>
332 + <# if ( needsCenterLoopWarning ) { #>
333 + <div style="background: red; mix-blend-mode: difference; padding: 15px; border-radius: 5px;">
334 + <span style="color: white; font-size: 1.2em; font-weight: bold;">
335 + <?php echo esc_html__('Warning', 'uicore-elements'); ?>
336 + </span>
328 337
329 - <# if ( navigationDots ) { #>
330 - <div class="swiper-pagination ui-e-dots ui-e-carousel-dots"></div>
338 + <p style="color: white; margin-bottom: 0px;">
339 + <?php echo esc_html__('You enabled centered slides, loop, and have an even number of slides per view', 'uicore-elements'); ?>
340 + ({{{ perView }}} <?php echo esc_html__('slides per view', 'uicore-elements'); ?>).
341 + <?php echo esc_html__('For this configuration to work properly, you need to have', 'uicore-elements'); ?>
342 + {{{ missingSlides }}}
343 + <?php echo esc_html__('more slide(s) or disable one of the mentioned features.', 'uicore-elements'); ?>
344 + </p>
345 + </div>
331 346 <# } #>
332 - <# if ( navigationArrows ) { #>
333 - <div class="ui-e-button ui-e-carousel-button ui-e-previous" role="button" aria-label="Previous slide">
334 - {{{ prev.value }}}
347 +
348 + <div class="ui-e-carousel ui-e-nested swiper {{ elementorFrontend.config.swiperClass }}">
349 + <div class='swiper-wrapper'> </div>
335 350 </div>
336 - <div class="ui-e-button ui-e-carousel-button ui-e-next" role="button" aria-label="Next slide">
337 - {{{ next.value }}}
338 - </div>
339 - <# } #>
340 - <# if ( navigationFraction ) { #>
341 - <div class="ui-e-fraction ui-e-carousel-fraction">
342 - <span class="ui-e-current"></span>
343 - /
344 - <span class="ui-e-total"></span>
345 - </div>
346 - <# } #>
347 - <?php
348 - }
349 351
350 -}
351 -\Elementor\Plugin::instance()->widgets_manager->register(new CustomCarousel());
352 + <# if ( navigationDots ) { #>
353 + <div class="swiper-pagination ui-e-dots ui-e-carousel-dots"></div>
354 + <# } #>
355 +
356 + <# if ( navigationArrows ) { #>
357 + <div class="ui-e-button ui-e-carousel-button ui-e-previous" role="button" aria-label="Previous slide">
358 + {{{ prev.value }}}
359 + </div>
360 + <div class="ui-e-button ui-e-carousel-button ui-e-next" role="button" aria-label="Next slide">
361 + {{{ next.value }}}
362 + </div>
363 + <# } #>
364 +
365 + <# if ( navigationFraction ) { #>
366 + <div class="ui-e-fraction ui-e-carousel-fraction">
367 + <span class="ui-e-current"></span>
368 + /
369 + <span class="ui-e-total"></span>
370 + </div>
371 + <# } #>
372 + <?php
373 + }
374 + }
375 +
376 + \Elementor\Plugin::instance()->widgets_manager->register(new CustomCarousel());