PluginProbe
ShopBuilder – WooCommerce Builder For Elementor / 3.0.0
ShopBuilder – WooCommerce Builder For Elementor v3.0.0
3.4.2 3.4.1 3.4.0 2.0.1 2.0.2 2.0.3 2.1.0 2.1.1 2.1.10 2.1.11 2.1.12 2.1.13 2.1.14 2.1.15 2.1.2 2.1.3 2.1.4 2.1.5 2.1.6 2.1.7 2.1.8 2.1.9 2.2.0 2.2.1 2.2.2 All 63 releases
shopbuilder / app / Elementor / Helper / RenderHelpers.php

RenderHelpers.php in ShopBuilder – WooCommerce Builder For Elementor 3.0.0, at app/Elementor/Helper/RenderHelpers.php

1,786 lines 61.5 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * Elementor Render Helper Class.
4 *
5 * This class contains render helper logics.
6 *
7 * @package RadiusTheme\SB
8 */
9
10 namespace RadiusTheme\SB\Elementor\Helper;
11
12 use Elementor\Plugin;
13 use RadiusTheme\SB\Helpers\Cache;
14 use RadiusTheme\SB\Helpers\Fns;
15 use RadiusTheme\SB\Helpers\BuilderFns;
16 use WC_Product_Query;
17 use WP_Term;
18
19 // Do not allow directly accessing this file.
20 if ( ! defined( 'ABSPATH' ) ) {
21 exit( 'This script cannot be accessed directly.' );
22 }
23
24 /**
25 * BuilderFns class
26 */
27 class RenderHelpers {
28 /**
29 * @var array
30 */
31 private static $cache = [];
32 /**
33 * Get data.
34 *
35 * @param array|string $haystack The array or string to search for the value.
36 * @param string $needle The key to look for in the array or the string itself.
37 * @param mixed $default The default value to return if the key is not.
38 *
39 * @return mixed
40 */
41 public static function get_data( $haystack, $needle, $default = null ) {
42 if ( is_array( $haystack ) && ! empty( $haystack[ $needle ] ) ) {
43 return $haystack[ $needle ];
44 } elseif ( is_string( $haystack ) && ! empty( $haystack ) ) {
45 return $haystack;
46 } else {
47 return $default;
48 }
49 }
50
51 /**
52 * Builds an array with field values.
53 *
54 * @param array $meta Field values.
55 * @param string $template Template name.
56 * @param array $raw_settings Raw settings.
57 *
58 * @return array
59 */
60 public static function meta_dataset( array $meta, $template = '', $raw_settings = [] ) {
61 $c_image_size = self::get_data( $meta, 'image_custom_dimension', [] );
62 $c_image_size['crop'] = self::get_data( $meta, 'image_crop', [] );
63
64 if ( ( ! empty( $_GET['displayview'] ) && 'list' === $_GET['displayview'] ) || ( empty( $_GET['displayview'] ) && ( ! empty( $meta['view_mode'] ) && 'list' === $meta['view_mode'] ) ) ) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended
65 $meta['cols'] = self::get_data( $meta, 'list_cols', 1 );
66 $meta['cols_tablet'] = self::get_data( $meta, 'list_cols_tablet', $meta['cols'] );
67 $meta['cols_mobile'] = self::get_data( $meta, 'list_cols_mobile', $meta['cols'] );
68 }
69
70 $data = apply_filters(
71 'rtsb/elementor/render/meta_dataset',
72 [
73 // Layout.
74 'widget' => 'custom',
75 'template' => self::get_data( $template, '', '' ),
76 'raw_settings' => $raw_settings,
77 'layout' => self::get_data( $meta, 'layout', 'layout1' ),
78 'grid_layout' => self::get_data( $raw_settings, 'layout', 'grid-layout1' ),
79 'list_layout' => self::get_data( $raw_settings, 'list_layout', 'list-layout1' ),
80 'd_cols' => self::get_data( $meta, 'cols', 0 ),
81 't_cols' => self::get_data( $meta, 'cols_tablet', 2 ),
82 'm_cols' => self::get_data( $meta, 'cols_mobile', 1 ),
83 'grid_type' => self::get_data( $meta, 'grid_style', 'even' ),
84
85 // Query.
86 'post_in' => self::get_data( $meta, 'include_posts', [] ),
87 'post_not_in' => self::get_data( $meta, 'exclude_posts', [] ),
88 'limit' => ( empty( $meta['posts_limit'] ) || '-1' === $meta['posts_limit'] ) ? 10000000 : $meta['posts_limit'],
89 'offset' => self::get_data( $meta, 'posts_offset', 0 ),
90 'order_by' => self::get_data( $meta, 'posts_order_by', 'date' ),
91 'order' => self::get_data( $meta, 'posts_order', 'DESC' ),
92 'author_in' => self::get_data( $meta, 'filter_author', [] ),
93 'display_by' => self::get_data( $meta, 'products_filter', 'date' ),
94 'categories' => self::get_data( $meta, 'filter_categories', [] ),
95 'brands' => self::get_data( $meta, 'filter_brands', [] ),
96 'tags' => self::get_data( $meta, 'filter_tags', [] ),
97 'attributes' => self::get_data( $meta, 'filter_attributes', [] ),
98 'relation' => self::get_data( $meta, 'tax_relation', 'OR' ),
99 'category_source' => self::get_data( $meta, 'select_source', 'product_cat' ),
100 'category_term' => self::get_data( $meta, 'select_cat' ),
101 'display_cat_by' => self::get_data( $meta, 'display_cat_by' ),
102 'include_cats' => self::get_data( $meta, 'include_cats', [] ),
103 'exclude_cats' => self::get_data( $meta, 'exclude_cats', [] ),
104 'select_parent_cat' => self::get_data( $meta, 'select_parent_cat' ),
105 'select_cats' => self::get_data( $meta, 'select_cats', [] ),
106 'select_cat_ids' => self::get_data( $meta, 'include_cat_ids', '' ),
107 'cats_limit' => ( empty( $meta['cats_limit'] ) || '-1' === $meta['cats_limit'] ) ? 10000000 : $meta['cats_limit'],
108 'show_empty' => ! empty( $meta['show_empty'] ),
109 'show_uncategorized' => ! empty( $meta['show_uncategorized'] ),
110 'show_subcats' => ! empty( $meta['show_subcats'] ),
111 'show_top_level_cats' => ! empty( $meta['show_top_level_cats'] ),
112 'cats_order_by' => self::get_data( $meta, 'cats_order_by', 'name' ),
113 'cats_order' => self::get_data( $meta, 'cats_order', 'DESC' ),
114 'rtsb_order' => self::get_data( $meta, 'rtsb_order', 'ASC' ),
115 'rtsb_orderby' => self::get_data( $meta, 'rtsb_orderby', 'menu_order' ),
116
117 // Pagination.
118 'pagination' => ! empty( $meta['show_pagination'] ),
119 'posts_loading_type' => self::get_data( $meta, 'pagination_type', 'pagination' ),
120 'posts_per_page' => self::get_data( $meta, 'pagination_per_page', '' ),
121
122 // Image.
123 'f_img' => ! empty( $meta['show_featured_image'] ),
124 'gallery_img' => ! empty( $meta['show_product_gallery'] ),
125 'c_img' => ! empty( $meta['show_cat_image'] ),
126 'hover_img' => ! empty( $meta['show_hover_image'] ),
127 'f_img_size' => self::get_data( $meta, 'image', 'medium' ),
128 'custom_img_size' => ! empty( $c_image_size ) && is_array( $c_image_size ) ? $c_image_size : [],
129 'default_img_id' => ! empty( $meta['default_preview_image']['id'] ) ? $meta['default_preview_image']['id'] : null,
130 'show_overlay' => ! empty( $meta['show_overlay'] ),
131 'hover_animation' => self::get_data( $meta, 'image_hover_animation', 'none' ),
132 'show_custom_image' => ! empty( $meta['show_custom_image'] ),
133 'custom_image' => ! empty( $meta['custom_image']['id'] ) ? $meta['custom_image']['id'] : null,
134
135 // Visibility.
136 'visibility' => ! empty( self::content_visibility( $meta ) ) ? self::content_visibility( $meta ) : [],
137
138 // Action Buttons.
139 'btn_preset' => self::get_data( $meta, 'action_btn_preset', 'preset1' ),
140 'btn_position' => self::get_data( $meta, 'action_btn_position', 'above' ),
141 'tooltip_position' => self::get_data( $meta, 'action_btn_tooltip_position', 'top' ),
142
143 // Product Title.
144 'title_tag' => self::get_data( $meta, 'title_tag', 'h3' ),
145 'title_hover' => ! empty( $meta['title_hover'] ),
146 'title_limit' => self::get_data( $meta, 'title_limit', 'default' ),
147 'title_limit_custom' => self::get_data( $meta, 'title_limit_custom' ),
148 'show_custom_title' => ! empty( $meta['show_custom_title'] ),
149 'cat_custom_title' => self::get_data( $meta, 'custom_title', '' ),
150
151 // Variation Swatches.
152 'swatch_position' => self::get_data( $meta, 'swatch_position', 'top' ),
153 'swatch_type' => self::get_data( $meta, 'swatch_type', 'circle' ),
154
155 // Short Description.
156 'show_custom_excerpt' => ! empty( $meta['show_custom_description'] ),
157 'cat_custom_excerpt' => self::get_data( $meta, 'custom_description', '' ),
158 'cat_excerpt_position' => self::get_data( $meta, 'excerpt_position', 'below' ),
159 'excerpt_limit' => self::get_data( $meta, 'excerpt_limit', 'default' ),
160 'excerpt_limit_custom' => self::get_data( $meta, 'excerpt_limit_custom', 200 ),
161
162 // Count.
163 'count_position' => self::get_data( $meta, 'count_display_type', 'flex' ),
164 'before_count' => self::get_data( $meta, 'before_count', '' ),
165 'after_count' => self::get_data( $meta, 'after_count', '' ),
166
167 // Add to cart.
168 'show_cart_icon' => ! empty( $meta['show_cart_icon'] ),
169 'show_cart_text' => ! empty( $meta['show_cart_text'] ),
170 'add_to_cart_icon' => self::get_data( $meta, 'add_to_cart_icon', [] ),
171 'add_to_cart_success_icon' => self::get_data( $meta, 'add_to_cart_success_icon', [] ),
172 'add_to_cart_text' => self::get_data( $meta, 'add_to_cart_text', esc_html__( 'Add to Cart', 'shopbuilder' ) ),
173 'add_to_cart_success_text' => self::get_data( $meta, 'add_to_cart_success_text', '' ),
174 'add_to_cart_alignment' => self::get_data( $meta, 'cart_icon_alignment', 'left' ),
175
176 // Action Button Icons.
177 'quick_view_icon' => self::get_data( $meta, 'quick_view_icon', [] ),
178 'comparison_icon' => self::get_data( $meta, 'comparison_icon', [] ),
179 'comparison_icon_added' => self::get_data( $meta, 'comparison_icon_added', [] ),
180 'wishlist_icon' => self::get_data( $meta, 'wishlist_icon', [] ),
181 'wishlist_icon_added' => self::get_data( $meta, 'wishlist_icon_added', [] ),
182
183 // Badges.
184 'sale_badge_type' => self::get_data( $meta, 'sale_badges_type', 'percentage' ),
185 'sale_badge_text' => self::get_data( $meta, 'sale_badges_text', esc_html__( 'Sale', 'shopbuilder' ) ),
186 'custom_badge_text' => self::get_data( $meta, 'custom_badge_text', esc_html__( 'Sale', 'shopbuilder' ) ),
187 'out_of_stock_badge_text' => self::get_data( $meta, 'stock_badges_text', esc_html__( 'Out of Stock', 'shopbuilder' ) ),
188 'badge_position' => self::get_data( $meta, 'badges_position', 'top' ),
189 'badge_alignment' => self::get_data( $meta, 'badges_alignment', 'left' ),
190 'badge_preset' => self::get_data( $meta, 'custom_badge_preset', 'preset-1' ),
191 'enable_badges_module' => self::get_data( $meta, 'enable_badges_module', '' ),
192
193 // Link.
194 'image_link' => ! empty( $meta['image_link'] ),
195 'title_link' => ! empty( $meta['title_link'] ),
196 'hover_btn_text' => self::get_data( $meta, 'hover_btn_text', esc_html__( 'See Details', 'shopbuilder' ) ),
197 'show_hover_btn_icon' => ! empty( $meta['show_hover_btn_icon'] ),
198 'hover_btn_icon' => self::get_data( $meta, 'hover_btn_icon', [] ),
199 'custom_link' => self::get_data( $meta, 'custom_link' ),
200
201 // Slider.
202 'd_group' => self::get_data( $meta, 'cols_group', 1 ),
203 't_group' => self::get_data( $meta, 'cols_group_tablet', 1 ),
204 'm_group' => self::get_data( $meta, 'cols_group_mobile', 1 ),
205 'auto_play' => ! empty( $meta['slide_autoplay'] ),
206 'stop_on_hover' => ! empty( $meta['pause_hover'] ),
207 'slider_nav' => ! empty( $meta['slider_nav'] ),
208 'slider_dot' => ! empty( $meta['slider_pagi'] ),
209 'slider_dynamic_dot' => ! empty( $meta['slider_dynamic_pagi'] ),
210 'loop' => ! empty( $meta['slider_loop'] ),
211 'lazy_load' => ! empty( $meta['slider_lazy_load'] ),
212 'auto_height' => ! empty( $meta['slider_auto_height'] ),
213 'speed' => self::get_data( $meta, 'slide_speed', 2000 ),
214 'space_between' => isset( $meta['grid_gap']['size'] ) && strlen( $meta['grid_gap']['size'] ) ? $meta['grid_gap']['size'] : 30,
215 'auto_play_timeout' => self::get_data( $meta, 'autoplay_timeout', 5000 ),
216 'nav_position' => self::get_data( $meta, 'slider_nav_position', 'top' ),
217 'left_arrow_icon' => self::get_data( $meta, 'slider_left_arrow_icon', [] ),
218 'right_arrow_icon' => self::get_data( $meta, 'slider_right_arrow_icon', [] ),
219 ],
220 $meta
221 );
222
223 if ( ! empty( $meta['active_cat_slider'] ) ) {
224 $data['active_cat_slider'] = true;
225 }
226
227 if ( ! empty( $meta['cols_widescreen'] ) ) {
228 $data['w_cols'] = $meta['cols_widescreen'];
229 }
230
231 if ( ! empty( $meta['cols_laptop'] ) ) {
232 $data['l_cols'] = $meta['cols_laptop'];
233 }
234
235 if ( ! empty( $meta['cols_tablet_extra'] ) ) {
236 $data['te_cols'] = $meta['cols_tablet_extra'];
237 }
238
239 if ( ! empty( $meta['cols_mobile_extra'] ) ) {
240 $data['me_cols'] = $meta['cols_mobile_extra'];
241 }
242
243 $queried_obj = get_queried_object();
244
245 if ( is_shop() || is_product_taxonomy() ) {
246 $data['posts_per_page'] = self::get_products_per_page();
247 $data['order_by'] = self::get_data( $data, 'rtsb_orderby', $data['order_by'] );
248 $data['order'] = self::get_data( $data, 'rtsb_order', $data['order'] );
249 }
250
251 if ( ! is_shop() && is_product_taxonomy() ) {
252 if ( ! empty( $queried_obj->taxonomy ) ) {
253 $data['queried_tax'] = esc_html( $queried_obj->taxonomy );
254 }
255
256 if ( ! empty( $queried_obj->term_id ) ) {
257 $data['queried_term'] = esc_html( $queried_obj->term_id );
258 }
259 }
260
261 return apply_filters( 'rtsb/elementor/render/meta_dataset_final', $data, $meta, $raw_settings );
262 }
263
264 /**
265 * Builds an array with field values.
266 *
267 * @param array $meta Field values.
268 * @param string $template Template name.
269 *
270 * @return array
271 */
272 public static function archive_meta_dataset( array $meta, $template = '' ) {
273 $data = apply_filters(
274 'rtsb/elementor/render/archive_meta_dataset',
275 [
276 // Layout.
277 'widget' => 'default',
278 'template' => self::get_data( $template, '', '' ),
279 'view_mode' => self::get_data( $meta, 'view_mode', 'grid' ),
280 'show_flash_sale' => ! empty( $meta['show_flash_sale'] ),
281 'wishlist_button' => ! empty( $meta['wishlist_button'] ),
282 'comparison_button' => ! empty( $meta['comparison_button'] ),
283 'quick_view_button' => ! empty( $meta['quick_view_button'] ),
284 'show_rating' => ! empty( $meta['show_rating'] ),
285 'show_pagination' => ! empty( $meta['show_pagination'] ),
286 'cart_icon' => self::get_data( $meta, 'cart_icon', [] ),
287 'wishlist_icon' => self::get_data( $meta, 'wishlist_icon', [] ),
288 'wishlist_icon_added' => self::get_data( $meta, 'wishlist_icon_added', [] ),
289 'comparison_icon' => self::get_data( $meta, 'comparison_icon', [] ),
290 'comparison_icon_added' => self::get_data( $meta, 'comparison_icon_added', [] ),
291 'quick_view_icon' => self::get_data( $meta, 'quick_view_icon', [] ),
292 'prev_icon' => self::get_data( $meta, 'prev_icon', [] ),
293 'next_icon' => self::get_data( $meta, 'next_icon', [] ),
294 'posts_per_page' => self::get_products_per_page(),
295 'rtsb_order' => self::get_data( $meta, 'rtsb_order', 'ASC' ),
296 'rtsb_orderby' => self::get_data( $meta, 'rtsb_orderby', 'menu_order' ),
297 'tooltip_position' => self::get_data( $meta, 'action_btn_tooltip_position', 'top' ),
298 ],
299 $meta
300 );
301
302 $queried_obj = get_queried_object();
303
304 if ( ! is_shop() && BuilderFns::is_archive() ) {
305 if ( ! empty( $queried_obj->taxonomy ) ) {
306 $data['queried_tax'] = esc_html( $queried_obj->taxonomy );
307 }
308
309 if ( ! empty( $queried_obj->term_id ) ) {
310 $data['queried_term'] = esc_html( $queried_obj->term_id );
311 }
312 }
313
314 return apply_filters( 'rtsb/elementor/render/archive_meta_dataset_final', $data, $meta );
315 }
316
317 /**
318 * Setting up content visibility
319 *
320 * @param array $settings Elementor settings.
321 *
322 * @return array
323 */
324 public static function content_visibility( $settings ) {
325 $visibility = [];
326
327 if ( ! empty( $settings['show_title'] ) ) {
328 $visibility[] = 'title';
329 }
330
331 if ( ! empty( $settings['show_short_desc'] ) ) {
332 $visibility[] = 'excerpt';
333 }
334
335 if ( ! empty( $settings['show_price'] ) ) {
336 $visibility[] = 'price';
337 }
338
339 if ( ! empty( $settings['show_rating'] ) ) {
340 $visibility[] = 'rating';
341 }
342
343 if ( ! empty( $settings['show_badges'] ) ) {
344 $visibility[] = 'badges';
345 }
346
347 if ( ! empty( $settings['show_categories'] ) ) {
348 $visibility[] = 'categories';
349 }
350
351 if ( ! empty( $settings['single_category'] ) ) {
352 $visibility[] = 'single-cat';
353 }
354 if ( ! empty( $settings['show_brands'] ) ) {
355 $visibility[] = 'brands';
356 }
357
358 if ( ! empty( $settings['single_brand'] ) ) {
359 $visibility[] = 'single-brand';
360 }
361
362 if ( ! empty( $settings['show_swatches'] ) ) {
363 $visibility[] = 'swatches';
364 }
365
366 if ( ! empty( $settings['show_vs_clear_btn'] ) ) {
367 $visibility[] = 'clear-btn';
368 }
369
370 if ( ! empty( $settings['show_count'] ) ) {
371 $visibility[] = 'count';
372 }
373
374 if ( ! empty( $settings['show_wishlist'] ) ) {
375 $visibility[] = 'wishlist';
376 }
377
378 if ( ! empty( $settings['show_compare'] ) ) {
379 $visibility[] = 'compare';
380 }
381
382 if ( ! empty( $settings['show_quick_view'] ) ) {
383 $visibility[] = 'quick_view';
384 }
385
386 if ( ! empty( $settings['show_add_to_cart'] ) ) {
387 $visibility[] = 'add_to_cart';
388 }
389
390 return $visibility;
391 }
392
393 /**
394 * Set Default Layout.
395 *
396 * @param string $layout Layout.
397 *
398 * @return string
399 */
400 public static function set_default_layout( $layout ) {
401 $is_list = preg_match( '/list/', $layout );
402 $is_cat_single = preg_match( '/category-single/', $layout );
403 $is_cat = preg_match( '/category/', $layout );
404 $is_carousel = preg_match( '/slider/', $layout );
405 $default = 'grid-layout1';
406
407 if ( $is_list ) {
408 $default = 'list-layout1';
409 } elseif ( $is_cat_single ) {
410 $default = 'category-single-layout1';
411 } elseif ( $is_cat ) {
412 $default = 'category-layout1';
413 } elseif ( $is_carousel ) {
414 $default = 'slider-layout1';
415 }
416
417 return $default;
418 }
419
420 /**
421 * Default layout columns.
422 *
423 * @param int $layout Layout.
424 *
425 * @return int
426 */
427 public static function default_columns( $layout ) {
428 switch ( $layout ) {
429 case 'rtsb-post-grid-layout1':
430 case 'rtsb-post-grid-layout2':
431 case 'rtsb-post-grid-layout3':
432 case 'rtsb-team-layout1':
433 case 'rtsb-team-layout2':
434 case 'rtsb-testimonial-layout2':
435 case 'grid-layout2':
436 case 'slider-layout2':
437 case 'rtsb-coupon-layout1':
438 case 'rtsb-coupon-layout2':
439 case 'rtsb-coupon-layout3':
440 $columns = 3;
441 break;
442 case 'rtsb-post-list-layout1':
443 case 'rtsb-post-list-layout2':
444 case 'list-layout1':
445 case 'list-layout2':
446 case 'list-layout3':
447 case 'list-layout7':
448 case 'list-layout5':
449 $columns = 1;
450 break;
451 case 'rtsb-team-layout4':
452 case 'rtsb-testimonial-layout1':
453 case 'rtsb-testimonial-layout3':
454 case 'rtsb-testimonial-layout4':
455 case 'rtsb-testimonial-layout5':
456 case 'list-layout4':
457 case 'list-layout6':
458 case 'slider-layout5':
459 case 'slider-layout8':
460 $columns = 2;
461 break;
462 case 'rtsb-logo-layout1':
463 case 'rtsb-logo-layout2':
464 case 'grid-layout6':
465 case 'grid-layout9':
466 $columns = 5;
467 break;
468
469 case 'category-layout1':
470 $columns = 6;
471 break;
472
473 default:
474 $columns = 4;
475 break;
476 }
477
478 return apply_filters( 'rtsb/element/general/default_columns', $columns, $layout );
479 }
480
481 /**
482 * Pagination JSON data.
483 *
484 * @param array $metas Data set.
485 * @param string $template Template name.
486 *
487 * @return string
488 */
489 public static function pagination_data( $metas, $template ) {
490 $el_data = self::meta_dataset( $metas, $template );
491
492 return esc_js( wp_json_encode( $el_data, JSON_UNESCAPED_UNICODE ) );
493 }
494
495 /**
496 * Container classes
497 *
498 * @param array $metas Meta data.
499 * @param array $settings Settings array.
500 * @param string $custom_class Custom class.
501 *
502 * @return mixed|null
503 */
504 public static function prepare_container_classes( $metas = [], $settings = [], $custom_class = '' ) {
505 $classes = 'rtsb-elementor-container products rtsb-pos-r ';
506 $classes .= $custom_class;
507
508 $raw_layout = esc_html( $metas['layout'] );
509 $layout = self::filter_layout( $raw_layout );
510 $is_cat = preg_match( '/category/', $layout );
511 $cart_txt_class = '';
512
513 $animation = $metas['hover_animation'];
514
515 if ( ! $is_cat ) {
516 $cart_txt_class = $metas['show_cart_text'] ? ' has-cart-text' : ' no-cart-text';
517 $animation .= ' gallery-hover-' . ( ! empty( $settings['gallery_hover_animation'] ) ? $settings['gallery_hover_animation'] : 'fade' );
518 }
519
520 $badge_class = [
521 'position' => $metas['badge_position'],
522 'alignment' => $metas['badge_alignment'],
523 ];
524
525 if ( ! in_array( 'clear-btn', $metas['visibility'], true ) ) {
526 $classes .= ' no-clear-btn';
527 }
528
529 $classes .= ! empty( $metas['pagination'] ) ? ' rtsb-has-pagination' : ' rtsb-no-pagination';
530 $classes .= ' badge-' . esc_attr( $badge_class['position'] ) . ' badge-' . esc_attr( $badge_class['alignment'] ) . esc_attr( $cart_txt_class ) . ' img-hover-' . esc_attr( $animation ) . ' excerpt-' . esc_attr( $metas['cat_excerpt_position'] );
531
532 if ( $metas['show_overlay'] ) {
533 $classes .= ' has-overlay';
534 }
535
536 if ( in_array( 'single-cat', $metas['visibility'], true ) ) {
537 $classes .= ' show-single-cat';
538 }
539 if ( in_array( 'single-brand', $metas['visibility'], true ) ) {
540 $classes .= ' show-single-brand';
541 }
542
543 if ( ! $is_cat ) {
544 $action_btn_classes = [
545 'show_compare_text' => 'has-compare-text',
546 'show_quick_view_text' => 'has-quick-view-text',
547 'show_wishlist_text' => 'has-wishlist-text',
548 'show_compare_icon' => 'no-compare-icon',
549 'show_quick_view_icon' => 'no-quick-view-icon',
550 'show_wishlist_icon' => 'no-wishlist-icon',
551 'show_quick_checkout_icon' => 'no-quick_checkout-icon',
552 ];
553
554 foreach ( $action_btn_classes as $setting_key => $class ) {
555 if ( strpos( $setting_key, 'icon' ) !== false ) {
556 $classes .= empty( $settings[ $setting_key ] ) ? ' ' . $class : '';
557 } else {
558 $classes .= ! empty( $settings[ $setting_key ] ) ? ' ' . $class : '';
559 }
560 }
561
562 if ( rtsb()->has_pro() && ! empty( $settings['custom_ordering'] ) ) {
563 $classes .= ' has-custom-ordering';
564 }
565 }
566 if ( rtsb()->has_pro() && ! empty( $settings['slider_slide_animation'] ) ) {
567 $classes .= ' has-slide-animation';
568 }
569
570 return apply_filters( 'rtsb/product/container/class', $classes, $settings );
571 }
572
573 /**
574 * Function to filter and validate the layout against allowed patterns.
575 *
576 * @param string $layout The layout string to be filtered.
577 * @param string $template The template to be checked.
578 *
579 * @return string
580 */
581 public static function filter_layout( $layout, $template = '' ) {
582 $allowed_patterns = apply_filters( 'rtsb/elementor/custom_layout', [ 'grid', 'list', 'slider', 'category', 'toyup', 'zilly', 'rtsb' ] );
583 $layout_part = explode( '-', $layout );
584 $default = 'grid-layout1';
585
586 if ( empty( $layout_part[0] ) ) {
587 return $default;
588 }
589
590 if ( in_array( $layout_part[0], $allowed_patterns, true ) ) {
591 if ( ! rtsb()->has_pro() && ! in_array( $layout, array_keys( Fns::free_layouts( $layout ) ), true ) ) {
592 $layout = self::set_default_layout( $layout );
593 }
594
595 return $layout;
596 } else {
597 return ! empty( $template ) ? self::set_default_layout( $layout ) : $default;
598 }
599 }
600
601 /**
602 * Row classes
603 *
604 * @param array $settings Settings array.
605 *
606 * @return mixed|null
607 */
608 public static function prepare_row_classes( $settings = [] ) {
609 $masonry_class = null;
610 $classes = 'rtsb-row rtsb-content-loader element-loading';
611 $loader_class = ' rtsb-pre-loader';
612
613 $raw_layout = esc_html( $settings['layout'] );
614 $layout = self::filter_layout( $raw_layout );
615 $grid_type = $settings['grid_type'];
616 $is_carousel = preg_match( '/slider/', $layout );
617
618 if ( preg_match( '/category/', $layout ) && ! empty( $settings['active_cat_slider'] ) ) {
619 $classes .= ' rtsb-slider-layout';
620 }
621
622 if ( 'equal' === $grid_type ) {
623 $masonry_class = ' rtsb-equal';
624 } elseif ( 'masonry' === $grid_type ) {
625 $masonry_class = ' rtsb-masonry';
626 } else {
627 $masonry_class = ' rtsb-even';
628 }
629
630 if ( ! rtsb()->has_pro() || $is_carousel ) {
631 $masonry_class = ' rtsb-even';
632 }
633
634 if ( $is_carousel && ! empty( $settings['raw_settings']['always_show_nav'] ) ) {
635 $classes .= ' always-show-nav';
636 }
637
638 if ( ! empty( $settings['raw_settings']['inner_slider_always_show_nav'] ) ) {
639 $classes .= ' inner-slider-always-show-nav';
640 }
641 if ( empty( $settings['raw_settings']['cols_mobile'] ) ) {
642 $classes .= ' rtsb-mobile-flex-row';
643 }
644
645 $classes .= ' rtsb-' . $layout . $masonry_class . $loader_class;
646
647 return apply_filters( 'rtsb/elementor/row/classes', $classes, $settings );
648 }
649
650 /**
651 * Prepare pagination attributes.
652 *
653 * @param string $layout The layout type.
654 * @param bool $has_filters Whether the widget has filters.
655 * @param string $template The template name.
656 * @param array $settings The widget settings.
657 * @param bool $ajax Whether to enable AJAX pagination.
658 *
659 * @return string
660 */
661 public static function prepare_pagination_attr( $layout, $has_filters, $template, $settings, $ajax ) {
662 $is_cat = preg_match( '/category/', $layout );
663 $is_carousel = preg_match( '/slider/', $layout );
664
665 if ( $is_carousel ) {
666 return $has_filters ? self::pagination_data( $settings, $template ) : '';
667 } elseif ( $is_cat ) {
668 return '';
669 } else {
670 $ajax_pagination = ! empty( $settings['show_pagination'] ) && 'pagination' !== $settings['pagination_type'];
671 $page = Fns::product_filters_has_ajax( apply_filters( 'rtsb/builder/set/current/page/type', '' ) );
672 $condition = rtsb()->has_pro() && $ajax && ( $ajax_pagination || $has_filters || $page );
673
674 return $condition ? self::pagination_data( $settings, $template ) : '';
675 }
676 }
677
678 /**
679 * Archive JSON data.
680 *
681 * @param array $metas Data set.
682 * @param string $template Template name.
683 *
684 * @return string
685 */
686 public static function archive_data( $metas, $template ) {
687 $el_data = self::archive_meta_dataset( $metas, $template );
688
689 return ' data-rtsb-ajax=\'' . esc_js( wp_json_encode( $el_data ) ) . '\'';
690 }
691
692 /**
693 * Slider options.
694 *
695 * @param array $meta Meta values.
696 * @param array $settings Raw Settings.
697 *
698 * @return array
699 */
700 public static function slider_data( array $meta, $settings = [] ) {
701 $has_dots = $meta['slider_dot'] ? ' has-dot' : ' no-dot';
702 $has_dots .= $meta['slider_nav'] ? ' has-nav' : ' no-nav';
703 $has_dynamic_dots = $meta['slider_dynamic_dot'] ? true : false;
704 $d_col = 0 === $meta['d_cols'] ? self::default_columns( $meta['layout'] ) : $meta['d_cols'];
705 $t_col = 0 === $meta['t_cols'] ? 2 : $meta['t_cols'];
706 $m_col = 0 === $meta['m_cols'] ? 1 : $meta['m_cols'];
707
708 if ( Plugin::$instance->breakpoints->has_custom_breakpoints() ) {
709 // Widescreen.
710 $w_col = self::get_data( $settings, 'cols_widescreen' );
711 $w_col = 0 === $w_col ? self::default_columns( $meta['layout'] ) : $w_col;
712 $w_group = self::get_data( $settings, 'cols_group_widescreen', 1 );
713
714 // Laptop.
715 $l_col = self::get_data( $settings, 'cols_laptop' );
716 $l_col = 0 === $l_col ? self::default_columns( $meta['layout'] ) : $l_col;
717 $l_group = self::get_data( $settings, 'cols_group_laptop', 1 );
718
719 // Tablet Landscape.
720 $te_col = self::get_data( $settings, 'cols_tablet_extra' );
721 $te_col = 0 === $te_col ? 3 : $te_col;
722 $te_group = self::get_data( $settings, 'cols_group_tablet_extra', 1 );
723
724 // Mobile Landscape.
725 $me_col = self::get_data( $settings, 'cols_mobile_extra' );
726 $me_col = 0 === $me_col ? 2 : $me_col;
727 $me_group = self::get_data( $settings, 'cols_group_mobile_extra', 1 );
728
729 $el_breakpoints = Fns::get_elementor_breakpoints();
730
731 foreach ( $el_breakpoints as $key => $value ) {
732 if ( isset( $value['is_enabled'] ) && ! $value['is_enabled'] ) {
733 unset( $el_breakpoints[ $key ] );
734 }
735 }
736
737 $breakpoints = [
738 0 => [
739 'slidesPerView' => absint( $m_col ),
740 'slidesPerGroup' => absint( $meta['m_group'] ),
741 'pagination' => [
742 'dynamicBullets' => $has_dynamic_dots,
743 ],
744 ],
745 ];
746
747 $desktop = [
748 'desktop' => [
749 'label' => 'Desktop',
750 'value' => 1920,
751 'is_enabled' => 1,
752 ],
753 ];
754
755 if ( ! empty( $el_breakpoints['laptop'] ) && $el_breakpoints['laptop']['is_enabled'] ) {
756 $widescreen_position = array_search( 'widescreen', array_keys( $el_breakpoints ), true );
757 $el_breakpoints = array_merge(
758 array_slice( $el_breakpoints, 0, $widescreen_position ),
759 $desktop,
760 array_slice( $el_breakpoints, $widescreen_position )
761 );
762 } else {
763 $desktop['desktop']['value'] = 1366;
764 $el_breakpoints['desktop'] = $desktop['desktop'];
765 }
766
767 foreach ( $el_breakpoints as $el_breakpoint => $value ) {
768 $breakpoint_value = ! empty( $value['value'] ) ? $value['value'] : $value['default_value'];
769 $dynamic_bullets = $has_dynamic_dots;
770 $slides_per_view = $d_col;
771 $slides_per_group = $meta['d_group'];
772
773 switch ( $el_breakpoint ) {
774 case 'widescreen':
775 $slides_per_view = $w_col;
776 $slides_per_group = $w_group;
777
778 break;
779
780 case 'laptop':
781 $slides_per_view = $l_col;
782 $slides_per_group = $l_group;
783
784 break;
785
786 case 'tablet_extra':
787 $slides_per_view = $l_col;
788 $slides_per_group = $l_group;
789
790 if ( empty( $el_breakpoints['laptop'] ) ) {
791 $slides_per_view = $d_col;
792 $slides_per_group = $meta['d_group'];
793 }
794
795 break;
796
797 case 'tablet':
798 $slides_per_view = $te_col;
799 $slides_per_group = $te_group;
800
801 if ( empty( $el_breakpoints['laptop'] ) && empty( $el_breakpoints['tablet_extra'] ) ) {
802 $slides_per_view = $d_col;
803 $slides_per_group = $meta['d_group'];
804 } elseif ( empty( $el_breakpoints['laptop'] ) && ! empty( $el_breakpoints['tablet_extra'] ) ) {
805 $slides_per_view = $te_col;
806 $slides_per_group = $te_group;
807 } elseif ( ! empty( $el_breakpoints['laptop'] ) && empty( $el_breakpoints['tablet_extra'] ) ) {
808 $slides_per_view = $l_col;
809 $slides_per_group = $l_group;
810 }
811
812 break;
813
814 case 'mobile_extra':
815 $slides_per_view = $t_col;
816 $slides_per_group = $meta['t_group'];
817 $dynamic_bullets = $has_dynamic_dots;
818
819 break;
820
821 case 'mobile':
822 $slides_per_view = $t_col;
823 $slides_per_group = $meta['t_group'];
824 $dynamic_bullets = $has_dynamic_dots;
825
826 if ( ! empty( $el_breakpoints['mobile_extra'] ) ) {
827 $slides_per_view = $me_col;
828 $slides_per_group = $me_group;
829 }
830
831 break;
832 }
833
834 if ( $value['is_enabled'] ) {
835 $br = 'widescreen' !== $el_breakpoint ? $breakpoint_value + 1 : $breakpoint_value;
836
837 $breakpoints[ absint( $br ) ] = [
838 'slidesPerView' => absint( $slides_per_view ),
839 'slidesPerGroup' => absint( $slides_per_group ),
840 'pagination' => [
841 'dynamicBullets' => $dynamic_bullets,
842 ],
843 ];
844 }
845 }
846 } else {
847 $breakpoints = [
848 0 => [
849 'slidesPerView' => absint( $m_col ),
850 'slidesPerGroup' => absint( $meta['m_group'] ),
851 'pagination' => [
852 'dynamicBullets' => $has_dynamic_dots,
853 ],
854 ],
855 768 => [
856 'slidesPerView' => absint( $t_col ),
857 'slidesPerGroup' => absint( $meta['t_group'] ),
858 'pagination' => [
859 'dynamicBullets' => $has_dynamic_dots,
860 ],
861 ],
862 1025 => [
863 'slidesPerView' => absint( $d_col ),
864 'slidesPerGroup' => absint( $meta['d_group'] ),
865 'pagination' => [
866 'dynamicBullets' => $has_dynamic_dots,
867 ],
868 ],
869 ];
870 }
871
872 $slider_options = [
873 'slidesPerView' => absint( $d_col ),
874 'slidesPerGroup' => absint( $meta['d_group'] ),
875 'speed' => absint( $meta['speed'] ),
876 'loop' => $meta['loop'],
877 'autoHeight' => $meta['auto_height'],
878 'preloadImages' => ! $meta['lazy_load'],
879 'lazy' => $meta['lazy_load'],
880 'breakpoints' => $breakpoints,
881 ];
882
883 if ( ! empty( $meta['raw_settings']['slider_slide_animation'] ) ) {
884 $slider_options['watchSlidesProgress'] = true;
885 }
886 if ( $meta['auto_play'] ) {
887 $slider_options['autoplay'] = [
888 'delay' => absint( $meta['auto_play_timeout'] ),
889 'pauseOnMouseEnter' => $meta['stop_on_hover'],
890 'disableOnInteraction' => false,
891 ];
892 }
893
894 $slider_options = apply_filters( 'rtsb/elementor/render/slider_dataset', $slider_options, $meta );
895 $carouselClass = 'rtsb-carousel-slider slider-loading rtsb-pos-s ' . $meta['nav_position'] . '-nav' . $has_dots;
896
897 return [
898 'data' => esc_js( wp_json_encode( $slider_options ) ),
899 'class' => $carouselClass,
900 ];
901 }
902
903 /**
904 * Preloader.
905 *
906 * @param string $layout Layout.
907 *
908 * @return string
909 */
910 public static function pre_loader( $layout ) {
911 $loader_class = '';
912
913 $is_carousel = preg_match( '/slider/', $layout );
914
915 if ( $is_carousel ) {
916 $loader_class = ' full-op';
917 }
918
919 return '<div class="rtsb-elements-loading rtsb-ball-clip-rotate"><div></div></div>';
920 }
921
922 /**
923 * Badge class.
924 *
925 * @param string $preset Badge preset.
926 *
927 * @return string|null
928 */
929 public static function badge_class( $preset ) {
930 switch ( $preset ) {
931 case 'preset-default':
932 $class = 'default-badge';
933 break;
934 case 'preset2':
935 $class = 'fill angle-right';
936 break;
937 case 'preset3':
938 $class = 'outline';
939 break;
940
941 case 'preset4':
942 $class = 'outline angle-right';
943 break;
944
945 default:
946 $class = 'fill';
947 break;
948 }
949
950 return $class;
951 }
952
953 /**
954 * Registers required scripts.
955 *
956 * @param array $scripts Scripts to register.
957 *
958 * @return void
959 */
960 public static function register_scripts( $scripts ) {
961 $caro = false;
962 $masonry = false;
963 $script = [];
964
965 $script[] = 'jquery';
966
967 foreach ( $scripts as $sc => $value ) {
968 if ( ! empty( $sc ) ) {
969 if ( 'isCarousel' === $sc ) {
970 $caro = $value;
971 }
972
973 if ( 'isMasonry' === $sc ) {
974 $masonry = $value;
975 }
976 }
977 }
978
979 if ( count( $scripts ) ) {
980 /**
981 * Scripts.
982 */
983 if ( $caro ) {
984 $script[] = 'swiper';
985 }
986
987 if ( $masonry ) {
988 $script[] = 'masonry';
989 }
990
991 $script[] = 'imagesloaded';
992 $script[] = Fns::optimized_handle( 'rtsb-public' );
993
994 foreach ( $script as $sc ) {
995 wp_enqueue_script( $sc );
996 }
997 }
998 }
999
1000 /**
1001 * Check if a wrapper is needed based on the current theme.
1002 *
1003 * @return bool
1004 */
1005 public static function is_wrapper_needed() {
1006 $theme_list = apply_filters(
1007 'rtsb/products/inner/wrapper/basedon/themes',
1008 [
1009 'twentytwentyone',
1010 'twentytwentytwo',
1011 'twentytwentythree',
1012 'storefront',
1013 'hello-elementor',
1014 'astra',
1015 ],
1016 rtsb()->current_theme
1017 );
1018
1019 if ( in_array( rtsb()->current_theme, $theme_list, true ) ) {
1020 return true;
1021 }
1022
1023 return false;
1024 }
1025
1026 /**
1027 * Get the number of products per page based on WooCommerce settings.
1028 *
1029 * @return int
1030 */
1031 public static function get_products_per_page() {
1032 $products_row = absint( get_option( 'woocommerce_catalog_rows', 4 ) );
1033 $products_col = absint( get_option( 'woocommerce_catalog_columns', 4 ) );
1034 $products_per_page = apply_filters( 'rtsb/elementor/archive/products_per_page', $products_row * $products_col );
1035
1036 return ! empty( $products_per_page ) ? $products_per_page : 12;
1037 }
1038 /**
1039 * Render Filters View.
1040 *
1041 * @param array $templates Template name.
1042 * @param array $settings Control settings.
1043 *
1044 * @return string
1045 */
1046 public static function filters_view( $templates, $settings ) {
1047 global $wp;
1048 $filters = [];
1049 $html = null;
1050 $reset = ! empty( $settings['reset_btn'] );
1051 $reset_mode = 'show' === $settings['reset_btn_behavior'] ? ' show-reset' : ' ondemand-reset';
1052 $reset_text = ! empty( $settings['reset_btn_text'] ) ? $settings['reset_btn_text'] : esc_html__( 'Reset Filter', 'shopbuilder' );
1053 $scroll_mode = ! empty( $settings['enable_scroll'] ) ? ' has-scroll' : ' no-scroll';
1054 $scroll_height = ! empty( $settings['enable_scroll'] ) ? $settings['scroll_height']['size'] : 300;
1055 $has_mobile_toggle = ! empty( $settings['filter_mobile_toggle'] );
1056 $toggle_class = $has_mobile_toggle ? ' default-filter-has-toggle' : ' default-filter-no-toggle';
1057 $mobile_toggle_text = ! empty( $settings['filter_mobile_toggle_text'] ) ? $settings['filter_mobile_toggle_text'] : esc_html__( 'Click to Filter', 'shopbuilder' );
1058 $scroll_attr = '';
1059
1060 if ( ! empty( $settings['enable_scroll'] ) ) {
1061 $scroll_attr = ' style="--rtsb-filter-scroll-height: ' . absint( $scroll_height ) . 'px;"';
1062 }
1063
1064 foreach ( $settings['filter_types'] as $key => $item ) {
1065 if ( ! defined( 'RTWPVS_PLUGIN_FILE' ) && in_array( $item['input_type_all'], [ 'color', 'button', 'image' ], true ) ) {
1066 $item['input_type_all'] = 'checkbox';
1067 }
1068 $filters[] = [
1069 'filter_title' => $item['filter_title'],
1070 'filter_items' => $item['filter_items'],
1071 'filter_attr' => $item['filter_attr'],
1072 'input_type' => 'product_attr' === $item['filter_items'] ? $item['input_type_all'] : $item['input_type'],
1073 ];
1074
1075 if ( 'rating_filter' === $item['filter_items'] ) {
1076 $filters[ $key ]['template'] = $templates['rating'];
1077 } elseif ( 'price_filter' === $item['filter_items'] ) {
1078
1079 $filters[ $key ]['input_type'] = 'slider';
1080 $filters[ $key ]['template'] = $templates['price'];
1081 } else {
1082 $filters[ $key ]['template'] = 'product_attr' === $item['filter_items'] ? $templates[ $item['input_type_all'] ] : $templates[ $item['input_type'] ];
1083 }
1084 }
1085
1086 if ( '' === get_option( 'permalink_structure' ) ) {
1087 $form_action = remove_query_arg( [ 'page', 'paged', 'product-page' ], add_query_arg( $wp->query_string, '', home_url( $wp->request ) ) );
1088 } else {
1089 $form_action = preg_replace( '%\/page/[0-9]+%', '', home_url( trailingslashit( $wp->request ) ) );
1090 }
1091 $args = [
1092 'filters' => $filters,
1093 'scroll_mode' => $scroll_mode,
1094 'reset_mode' => $reset_mode,
1095 'reset' => $reset,
1096 'scroll_attr' => $scroll_attr,
1097 'toggle_class' => $toggle_class,
1098 'reset_text' => $reset_text,
1099 'settings' => $settings,
1100 'form_action' => $form_action,
1101 ];
1102
1103 $html .= '<div class="rtsb-default-archive-filters' . esc_attr( $toggle_class ) . '">';
1104
1105 if ( $has_mobile_toggle ) {
1106 $html .= '<div class="rtsb-filter-mobile-toggle">
1107 <button class="product-filter-toggle">
1108 <span class="icon"><i aria-hidden="true" class="toggle-icon rtsb-icon rtsb-icon-filter"></i></span>
1109 <span class="text reset-text">' . esc_html( $mobile_toggle_text ) . '</span>
1110 <span></span>
1111 </button>
1112 </div>';
1113 }
1114
1115 $html .= Fns::load_template( $templates['layout'], $args, true );
1116 $html .= '</div>';
1117 return $html;
1118 }
1119 /**
1120 * Get taxonomy type.
1121 *
1122 * @param string $tax_type Taxonomy type.
1123 * @param string $attr_type Attribute type.
1124 *
1125 * @return string
1126 */
1127 public static function get_product_filters_tax_type( $tax_type, $attr_type = '' ) {
1128 if ( 'product_attr' !== $tax_type ) {
1129 return $tax_type;
1130 }
1131
1132 if ( empty( $attr_type ) ) {
1133 return $tax_type;
1134 }
1135
1136 return $attr_type;
1137 }
1138 /**
1139 * Get attribute terms.
1140 *
1141 * @param string $tax Taxonomy type.
1142 * @return int[]|string|string[]|\WP_Error|\WP_Term[]
1143 */
1144 public static function get_product_filters_attribute_terms( $tax ) {
1145 $cache_key = 'get_default_filter_attribute_terms_' . $tax;
1146 if ( isset( self::$cache[ $cache_key ] ) ) {
1147 return self::$cache[ $cache_key ];
1148 }
1149
1150 $attributes = wc_get_attribute_taxonomies();
1151 $att_name = str_replace( 'pa_', '', $tax );
1152 $exist = array_search( $att_name, array_column( $attributes, 'attribute_name' ), true );
1153 if ( false === $exist ) {
1154 self::$cache[ $cache_key ] = [];
1155 return self::$cache[ $cache_key ];
1156 }
1157 $attribute = $tax;
1158
1159 if ( ! is_shop() && is_product_taxonomy() ) {
1160 $term = get_queried_object();
1161
1162 if ( ! $term instanceof WP_Term ) {
1163 return [];
1164 }
1165
1166 $args = [
1167 'status' => 'publish',
1168 'limit' => -1,
1169 'return' => 'ids',
1170 ];
1171
1172 if ( 'product_cat' === $term->taxonomy ) {
1173 $args['category'] = [ $term->slug ];
1174 }
1175
1176 if ( 'product_tag' === $term->taxonomy ) {
1177 $args['tag'] = [ $term->slug ];
1178 }
1179
1180 if ( strpos( $term->taxonomy, 'pa_' ) !== false ) {
1181 $args['tax_query'] = [ // phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_tax_query
1182 [
1183 'taxonomy' => $term->taxonomy,
1184 'field' => 'term_id',
1185 'terms' => $term->term_id,
1186 'operator' => 'IN',
1187 ],
1188 ];
1189 }
1190
1191 $query = new WC_Product_Query( $args );
1192 $products = $query->get_products();
1193 $attr_terms = [];
1194
1195 foreach ( $products as $product_id ) {
1196 $product_attr = wp_get_post_terms( $product_id, $attribute );
1197
1198 foreach ( $product_attr as $attr ) {
1199 $attr_terms[] = $attr;
1200 }
1201 }
1202 self::$cache[ $cache_key ] = self::filter_products_array_unique( $attr_terms );
1203 return self::$cache[ $cache_key ];
1204 } else {
1205 self::$cache[ $cache_key ] = get_terms(
1206 [
1207 'taxonomy' => $attribute,
1208 'hide_empty' => false,
1209 ]
1210 );
1211 return self::$cache[ $cache_key ];
1212 }
1213 }
1214 /**
1215 * Remove duplicate values from an array.
1216 *
1217 * @param array $array The input array.
1218 * @param bool $keep_key_assoc Whether to keep the key associations after removing duplicates.
1219 * @return array The array with duplicates removed.
1220 */
1221 public static function filter_products_array_unique( $array, $keep_key_assoc = false ) {
1222 $duplicate_keys = [];
1223 $tmp = [];
1224
1225 foreach ( $array as $key => $val ) {
1226 // convert objects to arrays, in_array() does not support objects.
1227 if ( is_object( $val ) ) {
1228 $val = (array) $val;
1229 }
1230
1231 if ( ! in_array( $val, $tmp, true ) ) {
1232 $tmp[] = $val;
1233 } else {
1234 $duplicate_keys[] = $key;
1235 }
1236 }
1237
1238 foreach ( $duplicate_keys as $key ) {
1239 unset( $array[ $key ] );
1240 }
1241
1242 return $keep_key_assoc ? $array : array_values( $array );
1243 }
1244 /**
1245 * Retrieve product categories (including hierarchical support)
1246 *
1247 * @param string $taxonomy Taxonomy name.
1248 * @return int[]|string|string[]|\WP_Error|\WP_Term[]
1249 */
1250 public static function get_products( $taxonomy ) {
1251 $args = [
1252 'taxonomy' => esc_html( $taxonomy ),
1253 'hide_empty' => false,
1254 'pad_counts' => true,
1255 'hierarchical' => true,
1256 ];
1257
1258 $cache_key = 'rtsb_get_terms_filter_products' . $taxonomy;
1259 $taxonomy_terms = wp_cache_get( $cache_key, 'shopbuilder' );
1260
1261 if ( false === $taxonomy_terms ) {
1262 $queried_object = get_queried_object();
1263
1264 if ( 'archive' === apply_filters( 'rtsb/builder/set/current/page/type', '' ) && $queried_object instanceof WP_Term && $queried_object->taxonomy === $taxonomy ) {
1265 $term_id = $queried_object->term_id;
1266 $taxonomy = $queried_object->taxonomy;
1267 $archive_cache_key = 'rtsb_get_terms_filter_products_' . $taxonomy . $term_id;
1268 $taxonomy_terms = wp_cache_get( $archive_cache_key, 'shopbuilder' );
1269 if ( false === $taxonomy_terms ) {
1270 $taxonomy_terms = [ $queried_object ];
1271 $child_args = [
1272 'taxonomy' => $taxonomy,
1273 'child_of' => $term_id,
1274 'hide_empty' => false,
1275 ];
1276
1277 $child_terms = get_terms( $child_args );
1278
1279 if ( ! empty( $child_terms ) ) {
1280 $taxonomy_terms = array_merge( $taxonomy_terms, $child_terms );
1281 }
1282
1283 wp_cache_set( $archive_cache_key, $taxonomy_terms, 'shopbuilder' );
1284 Cache::set_data_cache_key( $archive_cache_key );
1285 }
1286 } else {
1287 $taxonomy_terms = get_terms( $args );
1288 }
1289
1290 wp_cache_set( $cache_key, $taxonomy_terms, 'shopbuilder' );
1291 Cache::set_data_cache_key( $cache_key );
1292 }
1293
1294 return $taxonomy_terms;
1295 }
1296 /**
1297 * Generates an error message block.
1298 *
1299 * @param array $title The title array of the error message block.
1300 * @param string $wrapper Additional CSS class for the wrapper div.
1301 *
1302 * @return string The HTML representation of the error message block.
1303 */
1304 public static function filter_error_message( $title, $wrapper ) {
1305 $html = '<div class="rtsb-product-default-filters ' . esc_attr( $wrapper ) . '">';
1306 $html .= self::get_default_filter_title( $title );
1307 $html .= '<div class="default-filter-content">';
1308 $html .= '<p class="no-filter">' . esc_html__( 'Nothing found.', 'shopbuilder' ) . '</p>';
1309 $html .= '</div>';
1310 $html .= '</div>';
1311
1312 return $html;
1313 }
1314 /**
1315 * Get filter title.
1316 *
1317 * @param array $title Filter title.
1318 * @return string
1319 */
1320 public static function get_default_filter_title( $title ) {
1321 $html = '';
1322
1323 if ( empty( $title['title'] ) ) {
1324 return $html;
1325 }
1326
1327 $html .= '<div class="default-filter-title-wrapper">';
1328
1329 $html .= '<h3 class="widget-title rtsb-d-flex rtsb-align-items-center"><span class="title">' . $title['title'] . '</span></h3>';
1330
1331 $html .= '</div>';
1332
1333 return apply_filters( 'rtsb/elementor/default/filter/title', $html, $title );
1334 }
1335 /**
1336 * Recursive function to generate the filter list with hierarchy.
1337 *
1338 * @param array $data Array of required data.
1339 * @param string $input Type of input field for the filter (e.g., checkbox).
1340 * @param array $additional_data Data for additional filtering.
1341 * @param int $parent ID of the parent term (default: 0).
1342 *
1343 * @return string The generated HTML for the product filter list.
1344 */
1345 public static function get_product_default_filter_list_html( $data, $input = 'checkbox', $additional_data = [], $parent = 0 ) {
1346
1347 $html = '';
1348 $default_tax = [];
1349 $is_attribute = ! empty( $data['is_attribute'] );
1350 $active_option = isset( $_GET[ $additional_data['taxonomy'] ] ) ? explode( ',', wc_clean( wp_unslash( $_GET[ $additional_data['taxonomy'] ] ) ) ) : []; // phpcs:ignore WordPress.Security.NonceVerification.Recommended, WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
1351 $counter = 0;
1352
1353 if ( $is_attribute ) {
1354 list(
1355 'filter_name' => $filter_name,
1356 'base_link' => $base_link
1357 ) = self::get_product_filters_attribute_term_info( $additional_data['taxonomy'] );
1358 }
1359
1360 $html .= '<ul class="product-default-filters input-type-' . esc_attr( $input ) . '">';
1361
1362 foreach ( $data['taxonomy'] as $tax ) {
1363 if ( $tax->parent !== $parent ) {
1364 continue;
1365 }
1366
1367 if ( $is_attribute ) {
1368 $tax_link = remove_query_arg( $filter_name, $base_link );
1369 $tax_link = add_query_arg( $filter_name, $tax->slug, $tax_link );
1370 $active_option = isset( $_GET[ $filter_name ] ) ? explode( ',', sanitize_text_field( wp_unslash( $_GET[ $filter_name ] ) ) ) : []; // phpcs:ignore WordPress.Security.NonceVerification.Recommended
1371 } else {
1372 $tax_link = get_term_link( $tax );
1373 }
1374
1375 $unique_id = substr( uniqid(), -4 );
1376
1377 $active_tax = in_array( $tax->slug, $active_option, true ) ? ' checked' : '';
1378 $active_tax_parent = in_array( $tax->slug, $active_option, true ) ? ' active' : '';
1379 $term_children = in_array( $tax->taxonomy, [ 'product_cat', 'product_brand' ], true ) ? get_term_children( $tax->term_id, $tax->taxonomy ) : [];
1380 $taxonomy = $tax->taxonomy;
1381 $product_count = $tax->count;
1382
1383 // Show count.
1384 if ( 'archive' === apply_filters( 'rtsb/builder/set/current/page/type', '' ) && ! empty( $data['count_display'] ) && 'block' === $data['count_display'] ) {
1385 $product_count = self::count_tax_data( $tax, $tax->count );
1386 }
1387
1388 // Show Empty Categories.
1389 if ( empty( $data['show_empty_terms'] ) && 0 === $product_count ) {
1390 continue;
1391 }
1392
1393 $html .= '<li class="rtsb-default-filter-term-item term-item-' . absint( $tax->term_id ) . esc_attr( $term_children ? ' term-has-children' : '' ) . ( ! $data['show_child'] ? ' child-terms-hidden' : '' ) . '">
1394 <div class="rtsb-default-filter-group' . esc_attr( $active_tax_parent ) . '">
1395 <input type="' . esc_attr( $input ) . '" class="rtsb-default-filter-trigger rtsb-' . esc_attr( $input . '-filter rtsb-term-' . $tax->slug . $active_tax ) . '" name="rtsb-filter-' . esc_attr( $taxonomy ) . '[]" id="rtsb-default-term-filter-' . $unique_id . absint( $tax->term_id ) . '" value="' . esc_attr( $tax->slug ) . '" ' . esc_attr( $active_tax ) . '>
1396 <label class="rtsb-default-' . esc_attr( $input ) . '-filter-label" for="rtsb-default-term-filter-' . $unique_id . absint( $tax->term_id ) . '">
1397 <span class="name">' . esc_html( $tax->name ) . '</span>
1398 </label>
1399 <div class="rtsb-product-count">(' . esc_html( $product_count ) . ')</div>
1400 ' . ( ! empty( $term_children ) && $data['show_child'] ? '<i class="rtsb-plus-icon"></i>' : '' ) . '
1401 </div>';
1402
1403 // Show Sub-categories.
1404 if ( $data['show_child'] ) {
1405 $children = self::get_product_default_filter_list_html( $data, $input, $additional_data, $tax->term_id );
1406
1407 if ( ! empty( $children ) ) {
1408 $html .= '<div class="filter-child">' . $children . '</div>';
1409 }
1410 }
1411
1412 $counter++;
1413
1414 $html .= '</li>';
1415 }
1416
1417 $html .= '</ul>';
1418
1419 // Check if the output contains any child elements.
1420 $has_children = strpos( $html, '<li class="rtsb-default-filter-term-item' ) !== false;
1421
1422 if ( ! $has_children ) {
1423 // Remove the outer <ul> if there are no child elements.
1424 $html = '';
1425 }
1426 return $html;
1427 }
1428 /**
1429 * Get attribute term info.
1430 *
1431 * @param string $tax Taxonomy type.
1432 * @return array
1433 */
1434 public static function get_product_filters_attribute_term_info( $tax ) {
1435 $result = [];
1436 $attributes = wc_get_attribute_taxonomies();
1437
1438 foreach ( $attributes as $attr ) {
1439 if ( str_replace( 'pa_', '', $tax ) === $attr->attribute_name ) {
1440 $term_type = $attr->attribute_type;
1441 $attribute_slug = $attr->attribute_name;
1442 $attribute = wc_attribute_taxonomy_name( $attr->attribute_name );
1443 break;
1444 }
1445 }
1446
1447 $filter_name = 'filter_' . wc_attribute_taxonomy_slug( $attribute_slug );
1448
1449 $result['attribute'] = $attribute ?? '';
1450 $result['term_type'] = $term_type ?? '';
1451 $result['attribute_slug'] = $attribute_slug ?? '';
1452 $result['filter_name'] = $filter_name;
1453 $result['base_link'] = self::get_base_url();
1454
1455 return $result;
1456 }
1457 /**
1458 * Get base URL.
1459 *
1460 * @return string|null
1461 */
1462 public static function get_base_url() {
1463 global $wp;
1464 return home_url( add_query_arg( [], $wp->request ) );
1465 }
1466 /**
1467 * Count the number of occurrences for a specific term in a taxonomy for the current queried object.
1468 *
1469 * @param object|array $tax The term object for the taxonomy.
1470 * @param int $count The initial count value.
1471 *
1472 * @return int The updated count value.
1473 */
1474 public static function count_tax_data( $tax, $count ) {
1475 $page = get_queried_object();
1476
1477 if ( is_array( $tax ) && strpos( $tax['taxonomy'], 'attribute_' ) !== false ) {
1478 $taxonomy = str_replace( 'attribute_', '', $tax['taxonomy'] );
1479 $term_id = $tax['term_id'];
1480 } else {
1481 $taxonomy = $tax->taxonomy;
1482 $term_id = $tax->term_id;
1483 }
1484
1485 if ( strpos( $page->taxonomy, 'pa_' ) !== false ) {
1486 $args['status'] = 'publish';
1487 $args['limit'] = -1;
1488 $args['return'] = 'ids';
1489 $args['tax_query'] = [ // phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_tax_query
1490 'relation' => 'AND',
1491 [
1492 'taxonomy' => $page->taxonomy,
1493 'field' => 'term_id',
1494 'terms' => $page->term_id,
1495 'operator' => 'IN',
1496 ],
1497 [
1498 'taxonomy' => $tax->taxonomy,
1499 'field' => 'term_id',
1500 'terms' => $tax->term_id,
1501 'operator' => 'IN',
1502 ],
1503 ];
1504
1505 $query = new WC_Product_Query( $args );
1506 $products = $query->get_products();
1507
1508 return count( $products );
1509 }
1510
1511 if ( $taxonomy !== $page->taxonomy ) {
1512 $args = [
1513 'limit' => -1,
1514 'return' => 'ids',
1515 'status' => 'publish',
1516 'tax_query' => [ // phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_tax_query
1517 [
1518 'taxonomy' => $taxonomy,
1519 'field' => 'term_id',
1520 'terms' => $term_id,
1521 ],
1522 ],
1523 ];
1524
1525 if ( 'product_cat' === $page->taxonomy ) {
1526 $args['category'] = [ $page->slug ];
1527 }
1528
1529 if ( 'product_tag' === $page->taxonomy ) {
1530 $args['tag'] = [ $page->slug ];
1531 }
1532
1533 $query = new WC_Product_Query( $args );
1534 $products = $query->get_products();
1535
1536 $count = count( $products );
1537 }
1538
1539 return $count;
1540 }
1541 /**
1542 * Get filter HTML.
1543 *
1544 * @param string $filter_type Filter type.
1545 * @param array $options Options.
1546 * @param array $additional_data Data for additional filtering.
1547 * @param string $input Input type.
1548 *
1549 * @return string The generated HTML for the attribute filter list.
1550 */
1551 public static function get_default_filter_html( $filter_type, $options, $additional_data = [], $input = 'checkbox' ) {
1552 $html = '<ul class="product-filters input-type-' . esc_attr( $input ) . '" ';
1553 $active_option = isset( $_GET[ $filter_type ] ) ? explode( ',', wc_clean( wp_unslash( $_GET[ $filter_type ] ) ) ) : []; // phpcs:ignore WordPress.Security.NonceVerification.Recommended, WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
1554 $option_link = self::get_base_url() . '/' . $filter_type . '/';
1555
1556 foreach ( $options as $option => $option_name ) {
1557 $unique_id = substr( uniqid(), -6 );
1558 $active_tax = in_array( $option, $active_option, true ) ? ' checked' : '';
1559 $active_group = in_array( $option, $active_option, true ) ? ' active' : '';
1560
1561 $html .= '
1562 <li class="rtsb-term-item">
1563 <div class="rtsb-default-filter-group' . esc_attr( $active_group ) . '">
1564 <input type="' . esc_attr( $input ) . '" class="rtsb-default-filter-trigger rtsb-' . esc_attr( $input ) . '-filter rtsb-term-' . esc_attr( $option ) . esc_attr( $active_tax ) . '" name="rtsb-filter-' . esc_attr( $filter_type ) . '[]" id="rtsb-term-default-filter-' . $unique_id . '" value="' . esc_attr( $option ) . '" ' . $active_tax . '>
1565 <label class="rtsb-default-' . esc_attr( $input ) . '-filter-label" for="rtsb-term-default-filter-' . $unique_id . '">
1566 <span class="name">' . esc_html( $option_name ) . '</span>
1567 </label>
1568 </div>
1569 </li>';
1570 }
1571
1572 $html .= '</ul>';
1573
1574 return $html;
1575 }
1576 /**
1577 * Get the count of products with a specific star rating.
1578 *
1579 * @param int $star_rating The star rating value.
1580 *
1581 * @return int
1582 */
1583 public static function get_product_rating_count( $star_rating ) {
1584 $args = [
1585 'status' => 'publish',
1586 'limit' => -1,
1587 'product_rating' => sprintf( '%.1f', $star_rating ),
1588 ];
1589
1590 if ( is_product_taxonomy() ) {
1591 $term = get_queried_object();
1592 $term_type = 'product_cat' === $term->taxonomy ? 'product_category_id' : 'product_tag_id';
1593
1594 if ( $term instanceof WP_Term ) {
1595 $args[ $term_type ] = [ $term->term_id ];
1596 }
1597 }
1598
1599 $query = new WC_Product_Query( $args );
1600 $products = $query->get_products();
1601
1602 return count( $products );
1603 }
1604 /**
1605 * Get attribute filter HTML.
1606 *
1607 * @param array $data Array of required data.
1608 * @param string $input Type of input field for the filter (e.g., color).
1609 *
1610 * @return string The generated HTML for the attribute filter list.
1611 */
1612 public static function get_attribute_filter_list_html( $data, $input = 'color' ) {
1613 if ( ! function_exists( 'rtwpvs' ) ) {
1614 return '';
1615 }
1616
1617 $terms = $data['terms'];
1618 $term_info = $data['term_info'];
1619 $show_tooltips = $data['show_tooltips'];
1620 $show_empty_terms = $data['show_empty_terms'];
1621 $counter = 0;
1622
1623 $html = '<ul class="product-default-filters rtsb-terms-wrapper ' . esc_attr( $term_info['type'] ) . '-variable-wrapper' . esc_attr( $data['show_label'] ) . '">';
1624
1625 foreach ( $terms as $attr_term ) {
1626 $count = $attr_term->count;
1627 $term_link = remove_query_arg( $term_info['filter_name'], $term_info['base_link'] );
1628 $term_link = add_query_arg( $term_info['filter_name'], $attr_term->slug, $term_link );
1629 $unique_id = substr( uniqid(), -6 );
1630 $name = 'term-' . wc_variation_attribute_name( $term_info['attribute'] ) . '-' . $unique_id;
1631 $selected_class = in_array( $attr_term->slug, $term_info['current_filter'], true ) ? ' selected' : '';
1632 $selected_item = in_array( $attr_term->slug, $term_info['current_filter'], true ) ? ' checked' : '';
1633 $active_class = in_array( $attr_term->slug, $term_info['current_filter'], true ) ? ' active' : '';
1634
1635 $args = [
1636 'id' => $name,
1637 'name' => $attr_term->name,
1638 'link' => $term_link,
1639 'type' => $term_info['type'],
1640 'term_id' => $attr_term->term_id,
1641 'term_slug' => $attr_term->slug,
1642 'taxonomy' => wc_variation_attribute_name( $term_info['attribute'] ),
1643 'tooltips' => $show_tooltips,
1644 'attribute_name' => $term_info['attribute'],
1645 'selected_item' => $selected_item,
1646 ];
1647
1648 if ( 'archive' === apply_filters( 'rtsb/builder/set/current/page/type', '' ) && ! empty( $data['count_display'] ) && 'block' === $data['count_display'] ) {
1649 $count = self::count_tax_data( $args, $attr_term->count );
1650 }
1651
1652 $args['count'] = $count;
1653
1654 if ( ! $show_empty_terms && 0 === $count ) {
1655 continue;
1656 }
1657
1658 $html .= '<li class="rtsb-default-filter-term-item term-item-' . esc_attr( $attr_term->term_id ) . ' rtsb-term rtsb-default-' . esc_attr( $input ) . '-term ' . esc_attr( $term_info['type'] ) . '-variable-term-' . esc_attr( $attr_term->slug ) . esc_attr( $selected_class ) . '">';
1659 $html .= '<div class="rtsb-default-filter-group' . esc_attr( $active_class ) . '">';
1660 $html .= self::get_input_type_html( $input, $args );
1661
1662 $counter++;
1663
1664 $html .= '</div>';
1665 $html .= '</li>';
1666 }
1667
1668 $html .= '</ul>';
1669
1670 return $html;
1671 }
1672 /**
1673 * Get input type HTML.
1674 *
1675 * @param string $input Input type.
1676 * @param array $args Args.
1677 * @return mixed|string|null
1678 */
1679 public static function get_input_type_html( $input, $args ) {
1680 $html = '';
1681 $count = $args['count'];
1682
1683 switch ( $input ) {
1684 case 'color':
1685 $color = sanitize_hex_color( get_term_meta( $args['term_id'], 'product_attribute_color', true ) );
1686
1687 $html .= sprintf(
1688 // phpcs:ignore Generic.Strings.UnnecessaryStringConcat.Found
1689 '<input type="checkbox" id="' . esc_attr( $args['id'] ) . '" value="' . esc_attr( $args['term_slug'] ) . '" class="rtsb-attr-hidden-field" name="rtsb-filter-' . esc_attr( $args['attribute_name'] ) . '[]' . '" ' . esc_attr( $args['selected_item'] ) . '/><label for="%s" title="' . esc_attr( $args['name'] ) . '" class="rtsb-default-filter-trigger rtsb-attr-filter rtsb-color-filter rtsb-term-span rtsb-term-span-%s%s"><span class="default-filter-attr-color" style="background-color:%s;"></span><span class="default-filter-attr-name">%s</span></label><div class="rtsb-count">(%s)</div>',
1690 esc_attr( $args['id'] ),
1691 esc_attr( $args['type'] ),
1692 $args['tooltips'] ? esc_attr( ' tipsy' ) : '',
1693 esc_attr( $color ),
1694 esc_html( $args['name'] ),
1695 absint( $count )
1696 );
1697 break;
1698
1699 case 'image':
1700 if ( ! function_exists( 'rtwpvs' ) ) {
1701 return $html;
1702 }
1703
1704 $attachment_id = absint( get_term_meta( $args['term_id'], 'product_attribute_image', true ) );
1705 $image_size = rtwpvs()->get_option( 'attribute_image_size' );
1706 $image_url = wp_get_attachment_image_url( $attachment_id, apply_filters( 'rtwpvs_product_attribute_image_size', $image_size ) );
1707
1708 $html .= sprintf(
1709 // phpcs:ignore Generic.Strings.UnnecessaryStringConcat.Found
1710 '<input type="checkbox" id="' . esc_attr( $args['id'] ) . '" value="' . esc_attr( $args['term_slug'] ) . '" class="rtsb-attr-hidden-field" name="rtsb-filter-' . esc_attr( $args['attribute_name'] ) . '[]' . '" ' . esc_attr( $args['selected_item'] ) . '/><label for="%s" title="' . esc_attr( $args['name'] ) . '" class="rtsb-default-filter-trigger rtsb-image-filter rtsb-term-span rtsb-term-span-%s%s"><img class="rtsb-default-attr-filter" alt="%s" src="%s" /></label>',
1711 esc_attr( $args['id'] ),
1712 esc_attr( $args['type'] ),
1713 $args['tooltips'] ? esc_attr( ' tipsy' ) : '',
1714 esc_attr( $args['name'] ),
1715 esc_url( $image_url )
1716 );
1717 break;
1718
1719 case 'button':
1720 $html .= sprintf(
1721 // phpcs:ignore Generic.Strings.UnnecessaryStringConcat.Found
1722 '<input id="' . esc_attr( $args['id'] ) . '" type="checkbox" value="' . esc_attr( $args['term_slug'] ) . '" class="rtsb-attr-hidden-field" name="rtsb-filter-' . esc_attr( $args['attribute_name'] ) . '[]' . '" ' . esc_attr( $args['selected_item'] ) . '/><label for="%s" title="' . esc_attr( $args['name'] ) . '" class="rtsb-default-filter-trigger rtsb-attr-filter rtsb-button-filter rtsb-term-span rtsb-term-span-%s%s"><span class="default-filter-attr-name">%s</span><div class="rtsb-count">(%s)</div></label>',
1723 esc_attr( $args['id'] ),
1724 esc_attr( $args['type'] ),
1725 $args['tooltips'] ? esc_attr( ' tipsy' ) : '',
1726 esc_html( $args['name'] ),
1727 absint( $count )
1728 );
1729 break;
1730
1731 default:
1732 }
1733
1734 return apply_filters( 'rtsb/elementor/default/filter/get_input_type_html', $html );
1735 }
1736 /**
1737 * Get reset button.
1738 *
1739 * @param string $btn_text Button text.
1740 * @param array $settings Settings array.
1741 *
1742 * @return string
1743 */
1744 public static function get_default_filter_reset_button( $btn_text, $settings ) {
1745 $html = '';
1746
1747 ob_start();
1748
1749 $active = ! empty( $_SERVER['QUERY_STRING'] ) ? ' active' : '';
1750 $reset = ! empty( $settings['reset_btn'] );
1751 $apply_text = ! empty( $settings['apply_filters_btn_text'] ) ? $settings['apply_filters_btn_text'] : esc_html__( 'Apply Filters', 'shopbuilder' );
1752 $apply_icon = ! empty( $settings['apply_filters_btn_icon'] ) ? $settings['apply_filters_btn_icon'] : [];
1753 echo '<div class="default-filter-btn-wrapper">';
1754 ?>
1755 <?php if ( $settings['show_filter_btn'] ) { ?>
1756 <div class="rtsb-product-default-filters rtsb-apply-filters-btn">
1757 <div class="reset-btn-item">
1758 <button class="rtsb-apply-filters init">
1759 <span class="icon"><?php Fns::print_html( Fns::icons_manager( $apply_icon, 'icon-default' ) ); ?></span>
1760 <span class="text reset-text"><?php echo esc_html( $apply_text ); ?></span>
1761 <span></span>
1762 </button>
1763 </div>
1764 </div>
1765 <?php } ?>
1766 <?php
1767 if ( $reset ) {
1768 ?>
1769 <div class="rtsb-product-default-filters rtsb-reset<?php echo esc_attr( $active ); ?>">
1770 <div class="reset-btn-item">
1771 <button class="product-default-filter-reset">
1772 <span class="text reset-text"><?php echo esc_html( $btn_text ); ?></span>
1773 <span></span>
1774 </button>
1775 </div>
1776 </div>
1777 <?php
1778 }
1779 echo '</div>';
1780
1781 $html .= ob_get_clean();
1782
1783 return $html;
1784 }
1785 }
1786