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