PluginProbe
ShopBuilder – WooCommerce Builder For Elementor / 3.2.6
ShopBuilder – WooCommerce Builder For Elementor v3.2.6
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.2.6, at app/Elementor/Helper/RenderHelpers.php

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