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 +376 -311 1.0.12 → 1.3.18 View file →
@@ -1,311 +1,376 @@
1 -<?php
2 -namespace UiCoreElements;
3 -use Elementor\Plugin;
4 -use Elementor\Controls_Manager;
5 -use Elementor\Repeater;
6 -use Elementor\Modules\NestedElements\Controls\Control_Nested_Repeater;
7 -use UiCoreElements\Utils\Carousel_Trait;
8 -use UiCoreElements\Utils\Animation_Trait;
9 -use UiCoreElements\Utils\Item_Style_Component;
10 -
11 -defined('ABSPATH') || exit();
12 -
13 -/**
14 - * Custom Carousel
15 - *
16 - * @author Lucas Marini Falbo <[email protected]>
17 - * @since 1.0.7
18 - */
19 -
20 -class CustomCarousel extends UiCoreNestedWidget {
21 -
22 - use Carousel_Trait;
23 - use Animation_Trait;
24 - use Item_Style_Component;
25 -
26 - public function get_name()
27 - {
28 - return 'uicore-custom-carousel';
29 - }
30 - public function get_title()
31 - {
32 - return esc_html__('Custom Carousel', 'uicore-elements');
33 - }
34 - public function get_icon()
35 - {
36 - return 'eicon-carousel-loop ui-e-widget';
37 - }
38 - public function get_categories()
39 - {
40 - return ['uicore'];
41 - }
42 - public function get_keywords()
43 - {
44 - return ['slide', 'carousel', 'nested'];
45 - }
46 - public function get_styles()
47 - {
48 - $styles = ['custom-carousel'];
49 - return $styles;
50 - }
51 - public function get_scripts()
52 - {
53 - return $this->TRAIT_get_scripts(false);
54 - }
55 -
56 - // 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',
63 - 'flex_justify_content' => 'center',
64 - '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 - }
84 -
85 - /**
86 - * We've set a bool variable to this function because Custom Slider extends this widget and requires one extra control.
87 - *
88 - * @param bool $is_slider - If the widget is a slider, it will enable the slider height control.
89 - */
90 - protected function register_controls(bool $is_slider = false)
91 - {
92 -
93 - if( !Plugin::$instance->experiments->is_feature_active('nested-elements') ){
94 - $this->nesting_fallback('controls');
95 - return;
96 - }
97 -
98 - $this->start_controls_section(
99 - 'section_content',
100 - [
101 - 'label' => __('Items', 'uicore-elements'),
102 - 'tab' => Controls_Manager::TAB_CONTENT,
103 - ]
104 - );
105 -
106 - $repeater = new Repeater();
107 -
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 - );
119 -
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 - ]
130 - ]
131 - );
132 -
133 - $this->end_controls_section();
134 -
135 - // Additional Carousel Controls
136 - $this->start_controls_section(
137 - 'section_additional_settings',
138 - [
139 - 'label' => __('Additional Settings', 'uicore-elements'),
140 - 'tab' => Controls_Manager::TAB_CONTENT,
141 - ]
142 - );
143 -
144 - $this->TRAIT_register_carousel_additional_controls($is_slider); // Carousel Additionals
145 -
146 - $this->end_controls_section();
147 -
148 - $this->start_controls_section(
149 - 'section_carousel_settings',
150 - [
151 - 'label' => __('Carousel Settings', 'uicore-elements'),
152 - ]
153 - );
154 -
155 - $this->TRAIT_register_carousel_settings_controls(); // Carousel settings
156 -
157 - $this->end_controls_section();
158 -
159 - $this->TRAIT_register_navigation_controls(); // Navigation settings
160 -
161 - $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 - );
168 -
169 - $this->TRAIT_register_all_item_style_controls();
170 -
171 - $this->end_controls_section();
172 -
173 - $this->TRAIT_register_navigation_style_controls(); // Carousel Navigation Styles
174 -
175 - // Decrease default item padding
176 - $this->update_control('item_padding', [
177 - 'default' => [
178 - 'top' => 25,
179 - 'right' => 25,
180 - 'bottom' => 25,
181 - 'left' => 25,
182 - 'unit' => 'px',
183 - 'isLinked' => true,
184 - ],
185 - ]);
186 -
187 - // Adds description to loop
188 - $this->update_control('loop', [
189 - '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 - ]);
191 -
192 - }
193 -
194 - public function render()
195 - {
196 - if( Plugin::$instance->experiments->is_feature_active('nested-elements') == false ){
197 - $this->nesting_fallback();
198 - return;
199 - }
200 -
201 - $items = $this->get_settings_for_display('carousel_items');
202 - $carousel_items = '';
203 -
204 - foreach ( $items as $index => $item ) {
205 - ob_start();
206 - $this->render_item($index);
207 - $carousel_items .= ob_get_clean();
208 - }
209 - ?>
210 - <div class="ui-e-carousel swiper">
211 -
212 - <div class='swiper-wrapper'>
213 - <?php echo $carousel_items; //phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped ?>
214 - </div>
215 -
216 - <?php $this->TRAIT_render_carousel_navigations(); ?>
217 - </div>
218 - <?php
219 - }
220 -
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
227 - }
228 -
229 - public function print_child( $index ) {
230 - $children = $this->get_children();
231 - $child_ids = [];
232 -
233 - if( empty( $children )){
234 - return;
235 - }
236 -
237 - foreach ( $children as $child ) {
238 - $child_ids[] = $child->get_id();
239 - }
240 -
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 - }
248 -
249 - return $should_render;
250 - };
251 -
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 - }
256 -
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 - }
264 -
265 - return parent::get_initial_config();
266 - }
267 -
268 - protected function content_template() {
269 -
270 - if( Plugin::$instance->experiments->is_feature_active('nested-elements') == false ){
271 - return;
272 - }
273 -
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');
280 -
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' );
283 - #>
284 - <div class="ui-e-carousel swiper {{ elementorFrontend.config.swiperClass }}">
285 -
286 - <div class='swiper-wrapper'> </div>
287 -
288 - <# if ( navigationDots ) { #>
289 - <div class="swiper-pagination ui-e-dots"></div>
290 - <# } #>
291 - <# if ( navigationArrows ) { #>
292 - <div class="ui-e-button ui-e-previous" role="button" aria-label="Previous slide">
293 - {{{ prev.value }}}
294 - </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 -
310 -}
311 -\Elementor\Plugin::instance()->widgets_manager->register(new CustomCarousel());
1 +<?php
2 +
3 +namespace UiCoreElements;
4 +
5 +use Elementor\Plugin;
6 +use Elementor\Controls_Manager;
7 +use Elementor\Repeater;
8 +use Elementor\Modules\NestedElements\Controls\Control_Nested_Repeater;
9 +use UiCoreElements\Utils\Carousel_Trait;
10 +use UiCoreElements\Utils\Animation_Trait;
11 +use UiCoreElements\Utils\Item_Style_Component;
12 +
13 +defined('ABSPATH') || exit();
14 +
15 +/**
16 + * Custom Carousel
17 + *
18 + * @author Lucas Marini Falbo <[email protected]>
19 + * @since 1.0.7
20 + */
21 +
22 +class CustomCarousel extends UiCoreNestedWidget
23 +{
24 +
25 + use Carousel_Trait;
26 + use Animation_Trait;
27 + use Item_Style_Component;
28 +
29 + public function get_name()
30 + {
31 + return 'uicore-custom-carousel';
32 + }
33 + public function get_title()
34 + {
35 + return esc_html__('Custom Carousel', 'uicore-elements');
36 + }
37 + public function get_icon()
38 + {
39 + return 'eicon-carousel-loop ui-e-widget';
40 + }
41 + public function get_categories()
42 + {
43 + return ['uicore'];
44 + }
45 + public function get_keywords()
46 + {
47 + return ['slide', 'carousel', 'nested'];
48 + }
49 + public function get_styles()
50 + {
51 + $styles = [
52 + 'custom-carousel',
53 + 'carousel'
54 + ];
55 + return $styles;
56 + }
57 + public function get_scripts()
58 + {
59 + return $this->TRAIT_get_carousel_scripts(false);
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 + }
66 +
67 + // Nested required functions
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',
76 + 'flex_justify_content' => 'center',
77 + 'flex_align_items' => 'center',
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 + }
102 +
103 + /**
104 + * We've set a bool variable to this function because Custom Slider extends this widget and requires one extra control.
105 + *
106 + * @param bool $is_slider - If the widget is a slider, it will enable the slider height control.
107 + */
108 + protected function register_controls(bool $is_slider = false)
109 + {
110 +
111 + if (!Plugin::$instance->experiments->is_feature_active('nested-elements')) {
112 + $this->nesting_fallback('controls');
113 + return;
114 + }
115 +
116 + $this->start_controls_section(
117 + 'section_content',
118 + [
119 + 'label' => __('Items', 'uicore-elements'),
120 + 'tab' => Controls_Manager::TAB_CONTENT,
121 + ]
122 + );
123 +
124 + $repeater = new Repeater();
125 +
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 + );
137 +
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')],
147 + ]
148 + ]
149 + );
150 +
151 + $this->end_controls_section();
152 +
153 + // Additional Carousel Controls
154 + $this->start_controls_section(
155 + 'section_additional_settings',
156 + [
157 + 'label' => __('Additional Settings', 'uicore-elements'),
158 + 'tab' => Controls_Manager::TAB_CONTENT,
159 + ]
160 + );
161 +
162 + $this->TRAIT_register_carousel_additional_controls($is_slider); // Carousel Additionals
163 +
164 + $this->end_controls_section();
165 +
166 + $this->start_controls_section(
167 + 'section_carousel_settings',
168 + [
169 + 'label' => __('Carousel Settings', 'uicore-elements'),
170 + ]
171 + );
172 +
173 + $this->TRAIT_register_carousel_settings_controls(); // Carousel settings
174 +
175 + $this->end_controls_section();
176 +
177 + $this->TRAIT_register_navigation_controls(); // Navigation settings
178 +
179 + $this->start_controls_section(
180 + 'section_style_review_items',
181 + [
182 + 'label' => esc_html__('Items', 'uicore-elements'),
183 + 'tab' => Controls_Manager::TAB_STYLE,
184 + ]
185 + );
186 +
187 + $this->TRAIT_register_all_item_style_controls();
188 +
189 + $this->end_controls_section();
190 +
191 + $this->TRAIT_register_navigation_style_controls(); // Carousel Navigation Styles
192 +
193 + // Decrease default item padding
194 + $this->update_control('item_padding', [
195 + 'default' => [
196 + 'top' => 25,
197 + 'right' => 25,
198 + 'bottom' => 25,
199 + 'left' => 25,
200 + 'unit' => 'px',
201 + 'isLinked' => true,
202 + ],
203 + ]);
204 +
205 + // Adds description to loop
206 + $this->update_control('loop', [
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'),
208 + ]);
209 + }
210 +
211 + public function render()
212 + {
213 + if (Plugin::$instance->experiments->is_feature_active('nested-elements') == false) {
214 + $this->nesting_fallback();
215 + return;
216 + }
217 +
218 + $items = $this->get_settings_for_display('carousel_items');
219 + $carousel_items = '';
220 +
221 + $total_slides = count($items);
222 + $this->TRAIT_render_center_loop_warning($total_slides);
223 +
224 + foreach ($items as $index => $item) {
225 + ob_start();
226 + $this->render_item($index);
227 + $current_slide = ob_get_clean();
228 +
229 + $carousel_items .= $current_slide;
230 + }
231 +
232 +?>
233 + <div class="ui-e-carousel ui-e-nested swiper">
234 +
235 + <div class='swiper-wrapper'>
236 + <?php echo $carousel_items; //phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
237 + ?>
238 + </div>
239 +
240 + </div>
241 +
242 + <?php $this->TRAIT_render_carousel_navigations($total_slides); ?>
243 + <?php
244 + }
245 +
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
253 + }
254 +
255 + public function print_child($index)
256 + {
257 + $children = $this->get_children();
258 + $child_ids = [];
259 +
260 + if (empty($children) || ! isset($children[$index])) {
261 + return;
262 + }
263 +
264 + foreach ($children as $child) {
265 + $child_ids[] = $child->get_id();
266 + }
267 +
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);
271 +
272 + $children[$index]->print_element();
273 +
274 + remove_filter('elementor/frontend/container/should_render', [$this, 'add_child_attributes']);
275 + }
276 +
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 + {
282 +
283 + // custom cases may be added here
284 +
285 + if (in_array($container->get_id(), $child_ids)) {
286 + $container->add_render_attribute('_wrapper', [
287 + 'class' => $classnames,
288 + ]);
289 + }
290 +
291 + return $should_render;
292 + }
293 +
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 + }
302 +
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' );
330 + #>
331 +
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>
337 +
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>
346 + <# } #>
347 +
348 + <div class="ui-e-carousel ui-e-nested swiper {{ elementorFrontend.config.swiperClass }}">
349 + <div class='swiper-wrapper'> </div>
350 + </div>
351 +
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());