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 +207 -168 1.2.0 → 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,39 +57,49 @@
54 57 public function get_scripts()
55 58 {
56 59 return $this->TRAIT_get_carousel_scripts(false);
57 60 }
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 + }
58 66
59 67 // Nested required functions
60 - protected function carousel_content_container( int $index ) {
61 - return [
62 - 'elType' => 'container',
63 - 'settings' => [
68 + protected function carousel_content_container(int $index)
69 + {
70 + return [
71 + 'elType' => 'container',
72 + 'settings' => [
64 73 /* translators: %s: Item number */
65 - '_title' => sprintf( esc_html__( 'Item #%s', 'uicore-elements' ), $index ),
66 - 'content_width' => 'full',
74 + '_title' => sprintf(esc_html__('Item #%s', 'uicore-elements'), $index),
75 + 'content_width' => 'full',
67 76 'flex_justify_content' => 'center',
68 77 'flex_align_items' => 'center',
69 - ],
70 - ];
71 - }
72 - protected function get_default_children_elements() {
73 - return [
74 - $this->carousel_content_container( 1 ),
75 - $this->carousel_content_container( 2 ),
76 - $this->carousel_content_container( 3 ),
77 - ];
78 - }
79 - protected function get_default_repeater_title_setting_key() {
80 - return 'carousel_item_title';
81 - }
82 - 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 + {
83 95 /* translators: %d: Item number */
84 - return esc_html__( 'Item #%d', 'uicore-elements' );
85 - }
86 - protected function get_default_children_placeholder_selector() {
87 - return '.swiper-wrapper';
88 - }
96 + return esc_html__('Item #%d', 'uicore-elements');
97 + }
98 + protected function get_default_children_placeholder_selector()
99 + {
100 + return '.swiper-wrapper';
101 + }
89 102
90 103 /**
91 104 * We've set a bool variable to this function because Custom Slider extends this widget and requires one extra control.
92 105 *
@@ -94,12 +107,12 @@
94 107 */
95 108 protected function register_controls(bool $is_slider = false)
96 109 {
97 110
98 - if( !Plugin::$instance->experiments->is_feature_active('nested-elements') ){
99 - $this->nesting_fallback('controls');
100 - return;
101 - }
111 + if (!Plugin::$instance->experiments->is_feature_active('nested-elements')) {
112 + $this->nesting_fallback('controls');
113 + return;
114 + }
102 115
103 116 $this->start_controls_section(
104 117 'section_content',
105 118 [
@@ -107,34 +120,34 @@
107 120 'tab' => Controls_Manager::TAB_CONTENT,
108 121 ]
109 122 );
110 123
111 - $repeater = new Repeater();
124 + $repeater = new Repeater();
112 125
113 - $repeater->add_control(
114 - 'carousel_item_title',
115 - [
116 - 'label' => __('Title', 'uicore-elements'),
117 - 'type' => Controls_Manager::TEXT,
118 - 'render_type' => 'template',
119 - 'dynamic' => [
120 - 'active' => true,
121 - ],
122 - ]
123 - );
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 + );
124 137
125 - $this->add_control(
126 - 'carousel_items',
127 - [
128 - 'type' => Control_Nested_Repeater::CONTROL_TYPE,
129 - 'fields' => $repeater->get_controls(),
130 - 'default' => [
131 - [ 'carousel_item_title' => __( 'Item #1', 'uicore-elements' ) ],
132 - [ 'carousel_item_title' => __( 'Item #2', 'uicore-elements' ) ],
133 - [ 'carousel_item_title' => __( 'Item #3', 'uicore-elements' ) ],
134 - ]
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')],
135 147 ]
136 - );
148 + ]
149 + );
137 150
138 151 $this->end_controls_section();
139 152
140 153 // Additional Carousel Controls
@@ -145,20 +158,20 @@
145 158 'tab' => Controls_Manager::TAB_CONTENT,
146 159 ]
147 160 );
148 161
149 - $this->TRAIT_register_carousel_additional_controls($is_slider); // Carousel Additionals
162 + $this->TRAIT_register_carousel_additional_controls($is_slider); // Carousel Additionals
150 163
151 164 $this->end_controls_section();
152 165
153 166 $this->start_controls_section(
154 - 'section_carousel_settings',
155 - [
156 - 'label' => __('Carousel Settings', 'uicore-elements'),
157 - ]
158 - );
167 + 'section_carousel_settings',
168 + [
169 + 'label' => __('Carousel Settings', 'uicore-elements'),
170 + ]
171 + );
159 172
160 - $this->TRAIT_register_carousel_settings_controls(); // Carousel settings
173 + $this->TRAIT_register_carousel_settings_controls(); // Carousel settings
161 174
162 175 $this->end_controls_section();
163 176
164 177 $this->TRAIT_register_navigation_controls(); // Navigation settings
@@ -163,16 +176,16 @@
163 176
164 177 $this->TRAIT_register_navigation_controls(); // Navigation settings
165 178
166 179 $this->start_controls_section(
167 - 'section_style_review_items',
168 - [
169 - 'label' => esc_html__( 'Items', 'uicore-elements' ),
170 - 'tab' => Controls_Manager::TAB_STYLE,
171 - ]
172 - );
180 + 'section_style_review_items',
181 + [
182 + 'label' => esc_html__('Items', 'uicore-elements'),
183 + 'tab' => Controls_Manager::TAB_STYLE,
184 + ]
185 + );
173 186
174 - $this->TRAIT_register_all_item_style_controls();
187 + $this->TRAIT_register_all_item_style_controls();
175 188
176 189 $this->end_controls_section();
177 190
178 191 $this->TRAIT_register_navigation_style_controls(); // Carousel Navigation Styles
@@ -192,146 +205,172 @@
192 205 // Adds description to loop
193 206 $this->update_control('loop', [
194 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'),
195 208 ]);
196 -
197 209 }
198 210
199 211 public function render()
200 212 {
201 - if( Plugin::$instance->experiments->is_feature_active('nested-elements') == false ){
202 - $this->nesting_fallback();
203 - return;
204 - }
213 + if (Plugin::$instance->experiments->is_feature_active('nested-elements') == false) {
214 + $this->nesting_fallback();
215 + return;
216 + }
205 217
206 218 $items = $this->get_settings_for_display('carousel_items');
207 219 $carousel_items = '';
208 220
209 221 $total_slides = count($items);
210 - $should_duplicate = $this->TRAIT_should_duplicate_slides($total_slides);
211 - $duplicated_slides = [];
222 + $this->TRAIT_render_center_loop_warning($total_slides);
212 223
213 - foreach ( $items as $index => $item ) {
224 + foreach ($items as $index => $item) {
214 225 ob_start();
215 226 $this->render_item($index);
216 227 $current_slide = ob_get_clean();
217 228
218 - if($should_duplicate){
219 - $duplicated_slides[$index] = $current_slide;
220 - }
221 -
222 229 $carousel_items .= $current_slide;
223 230 }
224 231
225 - // Most recent swiper versions requires, if loop, at least one extra slide compared to visible slides
226 - if($should_duplicate) {
227 - $diff = $this->TRAIT_get_duplication_diff($total_slides);
228 - for($i = 0; $i <= $diff; $i++){
229 - $carousel_items .= $duplicated_slides[$i];
230 - }
231 - }
232 +?>
233 + <div class="ui-e-carousel ui-e-nested swiper">
232 234
233 - ?>
234 - <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>
235 239
236 - <div class='swiper-wrapper'>
237 - <?php echo $carousel_items; //phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped ?>
238 - </div>
240 + </div>
239 241
240 - </div>
242 + <?php $this->TRAIT_render_carousel_navigations($total_slides); ?>
243 + <?php
244 + }
241 245
242 - <?php $this->TRAIT_render_carousel_navigations(); ?>
243 - <?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
244 253 }
245 254
246 - public function render_item( $index ) {
247 - ?>
248 - <div class="ui-e-wrp swiper-slide" data-hash="<?php echo esc_html($index);?>">
249 - <?php $this->print_child( $index ); ?>
250 - </div>
251 - <?php
252 - }
255 + public function print_child($index)
256 + {
257 + $children = $this->get_children();
258 + $child_ids = [];
253 259
254 - public function print_child( $index ) {
255 - $children = $this->get_children();
256 - $child_ids = [];
260 + if (empty($children) || ! isset($children[$index])) {
261 + return;
262 + }
257 263
258 - if( empty( $children )){
259 - return;
260 - }
264 + foreach ($children as $child) {
265 + $child_ids[] = $child->get_id();
266 + }
261 267
262 - foreach ( $children as $child ) {
263 - $child_ids[] = $child->get_id();
264 - }
268 + add_filter('elementor/frontend/container/should_render', function ($should_render, $container) use ($child_ids) {
269 + return $this->add_child_attributes($should_render, $container, $child_ids);
270 + }, 10, 3);
265 271
266 - // Add the `ui-e-item` class directly on the item container
267 - $add_attribute_to_container = function ( $should_render, $container ) use ( $child_ids ) {
268 - if ( in_array( $container->get_id(), $child_ids ) ) {
269 - $container->add_render_attribute( '_wrapper', [
270 - 'class' => 'ui-e-item',
271 - ] );
272 - }
272 + $children[$index]->print_element();
273 273
274 - return $should_render;
275 - };
274 + remove_filter('elementor/frontend/container/should_render', [$this, 'add_child_attributes']);
275 + }
276 276
277 - add_filter( 'elementor/frontend/container/should_render', $add_attribute_to_container, 10, 3 );
278 - $children[ $index ]->print_element();
279 - remove_filter( 'elementor/frontend/container/should_render', $add_attribute_to_container );
280 - }
277 + /**
278 + * Adds attributes to child elements containers.
279 + */
280 + protected function add_child_attributes($should_render, $container, $child_ids, $classnames = ['ui-e-item'])
281 + {
281 282
282 - protected function get_initial_config(): array {
283 - if ( Plugin::$instance->experiments->is_feature_active( 'e_nested_atomic_repeaters' ) ) {
284 - return array_merge( parent::get_initial_config(), [
285 - 'support_improved_repeaters' => true,
286 - 'node' => 'button',
287 - ] );
288 - }
283 + // custom cases may be added here
289 284
290 - return parent::get_initial_config();
291 - }
285 + if (in_array($container->get_id(), $child_ids)) {
286 + $container->add_render_attribute('_wrapper', [
287 + 'class' => $classnames,
288 + ]);
289 + }
292 290
293 - protected function content_template() {
291 + return $should_render;
292 + }
294 293
295 - if( Plugin::$instance->experiments->is_feature_active('nested-elements') == false ){
296 - return;
297 - }
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 + }
298 302
299 - ?>
300 - <#
301 - var carouselItems = settings.carousel_items,
302 - hideNavigation = settings.animation_style.includes('marquee'),
303 - navigationDots = settings.navigation.includes('dots') && !hideNavigation,
304 - navigationArrows = settings.navigation.includes('arrows') && !hideNavigation,
305 - navigationFraction = settings.navigation.includes('fraction') && !hideNavigation;
303 + return parent::get_initial_config();
304 + }
306 305
307 - var prev = elementor.helpers.renderIcon( view, settings.previous_arrow, { 'aria-hidden': true }, 'i' , 'object' ),
308 - next = elementor.helpers.renderIcon( view, settings.next_arrow, { 'aria-hidden': true }, 'i' , 'object' );
306 + protected function content_template()
307 + {
308 +
309 + if (Plugin::$instance->experiments->is_feature_active('nested-elements') == false) {
310 + return;
311 + }
312 +
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;
327 +
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' );
309 330 #>
310 331
311 - <div class="ui-e-carousel swiper {{ elementorFrontend.config.swiperClass }}">
312 - <div class='swiper-wrapper'> </div>
313 - </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>
314 337
315 - <# if ( navigationDots ) { #>
316 - <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>
317 346 <# } #>
318 - <# if ( navigationArrows ) { #>
319 - <div class="ui-e-button ui-e-carousel-button ui-e-previous" role="button" aria-label="Previous slide">
320 - {{{ prev.value }}}
347 +
348 + <div class="ui-e-carousel ui-e-nested swiper {{ elementorFrontend.config.swiperClass }}">
349 + <div class='swiper-wrapper'> </div>
321 350 </div>
322 - <div class="ui-e-button ui-e-carousel-button ui-e-next" role="button" aria-label="Next slide">
323 - {{{ next.value }}}
324 - </div>
325 - <# } #>
326 - <# if ( navigationFraction ) { #>
327 - <div class="ui-e-fraction ui-e-carousel-fraction">
328 - <span class="ui-e-current"></span>
329 - /
330 - <span class="ui-e-total"></span>
331 - </div>
332 - <# } #>
333 - <?php
334 - }
335 351
336 -}
337 -\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());