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
← All changes | app/Elementor/Helper/RenderHelpers.php +963 -16 2.1.83.2.6 View file →
@@ -8,10 +8,14 @@
8 8 */
9 9
10 10 namespace RadiusTheme\SB\Elementor\Helper;
11 11
12 +use Elementor\Plugin;
13 +use RadiusTheme\SB\Helpers\Cache;
14 +use RadiusTheme\SB\Helpers\Fns;
12 15 use RadiusTheme\SB\Helpers\BuilderFns;
13 -use RadiusTheme\SB\Helpers\Fns;
16 +use WC_Product_Query;
17 +use WP_Term;
14 18
15 19 // Do not allow directly accessing this file.
16 20 if ( ! defined( 'ABSPATH' ) ) {
17 21 exit( 'This script cannot be accessed directly.' );
@@ -21,8 +25,33 @@
21 25 * BuilderFns class
22 26 */
23 27 class RenderHelpers {
24 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 + /**
25 54 * Get data.
26 55 *
27 56 * @param array|string $haystack The array or string to search for the value.
28 57 * @param string $needle The key to look for in the array or the string itself.
@@ -83,8 +112,9 @@
83 112 'order' => self::get_data( $meta, 'posts_order', 'DESC' ),
84 113 'author_in' => self::get_data( $meta, 'filter_author', [] ),
85 114 'display_by' => self::get_data( $meta, 'products_filter', 'date' ),
86 115 'categories' => self::get_data( $meta, 'filter_categories', [] ),
116 + 'brands' => self::get_data( $meta, 'filter_brands', [] ),
87 117 'tags' => self::get_data( $meta, 'filter_tags', [] ),
88 118 'attributes' => self::get_data( $meta, 'filter_attributes', [] ),
89 119 'relation' => self::get_data( $meta, 'tax_relation', 'OR' ),
90 120 'category_source' => self::get_data( $meta, 'select_source', 'product_cat' ),
@@ -248,8 +278,16 @@
248 278 $data['queried_term'] = esc_html( $queried_obj->term_id );
249 279 }
250 280 }
251 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 +
252 290 return apply_filters( 'rtsb/elementor/render/meta_dataset_final', $data, $meta, $raw_settings );
253 291 }
254 292
255 293 /**
@@ -301,8 +339,16 @@
301 339 $data['queried_term'] = esc_html( $queried_obj->term_id );
302 340 }
303 341 }
304 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 +
305 351 return apply_filters( 'rtsb/elementor/render/archive_meta_dataset_final', $data, $meta );
306 352 }
307 353
308 354 /**
@@ -341,9 +387,16 @@
341 387
342 388 if ( ! empty( $settings['single_category'] ) ) {
343 389 $visibility[] = 'single-cat';
344 390 }
391 + if ( ! empty( $settings['show_brands'] ) ) {
392 + $visibility[] = 'brands';
393 + }
345 394
395 + if ( ! empty( $settings['single_brand'] ) ) {
396 + $visibility[] = 'single-brand';
397 + }
398 +
346 399 if ( ! empty( $settings['show_swatches'] ) ) {
347 400 $visibility[] = 'swatches';
348 401 }
349 402
@@ -409,13 +462,23 @@
409 462 * @return int
410 463 */
411 464 public static function default_columns( $layout ) {
412 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':
413 472 case 'grid-layout2':
414 473 case 'slider-layout2':
474 + case 'rtsb-coupon-layout1':
475 + case 'rtsb-coupon-layout2':
476 + case 'rtsb-coupon-layout3':
415 477 $columns = 3;
416 478 break;
417 -
479 + case 'rtsb-post-list-layout1':
480 + case 'rtsb-post-list-layout2':
418 481 case 'list-layout1':
419 482 case 'list-layout2':
420 483 case 'list-layout3':
421 484 case 'list-layout7':
@@ -421,9 +484,13 @@
421 484 case 'list-layout7':
422 485 case 'list-layout5':
423 486 $columns = 1;
424 487 break;
425 -
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':
426 493 case 'list-layout4':
427 494 case 'list-layout6':
428 495 case 'slider-layout5':
429 496 case 'slider-layout8':
@@ -428,10 +495,12 @@
428 495 case 'slider-layout5':
429 496 case 'slider-layout8':
430 497 $columns = 2;
431 498 break;
432 -
499 + case 'rtsb-logo-layout1':
500 + case 'rtsb-logo-layout2':
433 501 case 'grid-layout6':
502 + case 'grid-layout9':
434 503 $columns = 5;
435 504 break;
436 505
437 506 case 'category-layout1':
@@ -472,9 +541,10 @@
472 541 public static function prepare_container_classes( $metas = [], $settings = [], $custom_class = '' ) {
473 542 $classes = 'rtsb-elementor-container products rtsb-pos-r ';
474 543 $classes .= $custom_class;
475 544
476 - $layout = $metas['layout'];
545 + $raw_layout = esc_html( $metas['layout'] );
546 + $layout = self::filter_layout( $raw_layout );
477 547 $is_cat = preg_match( '/category/', $layout );
478 548 $cart_txt_class = '';
479 549
480 550 $animation = $metas['hover_animation'];
@@ -502,8 +572,11 @@
502 572
503 573 if ( in_array( 'single-cat', $metas['visibility'], true ) ) {
504 574 $classes .= ' show-single-cat';
505 575 }
576 + if ( in_array( 'single-brand', $metas['visibility'], true ) ) {
577 + $classes .= ' show-single-brand';
578 + }
506 579
507 580 if ( ! $is_cat ) {
508 581 $action_btn_classes = [
509 582 'show_compare_text' => 'has-compare-text',
@@ -534,8 +607,36 @@
534 607 return apply_filters( 'rtsb/product/container/class', $classes, $settings );
535 608 }
536 609
537 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 + /**
538 639 * Row classes
539 640 *
540 641 * @param array $settings Settings array.
541 642 *
@@ -543,11 +644,15 @@
543 644 */
544 645 public static function prepare_row_classes( $settings = [] ) {
545 646 $masonry_class = null;
546 647 $classes = 'rtsb-row rtsb-content-loader element-loading';
547 - $loader_class = ' rtsb-pre-loader';
548 648
549 - $layout = $settings['layout'];
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 );
550 655 $grid_type = $settings['grid_type'];
551 656 $is_carousel = preg_match( '/slider/', $layout );
552 657
553 658 if ( preg_match( '/category/', $layout ) && ! empty( $settings['active_cat_slider'] ) ) {
@@ -553,23 +658,30 @@
553 658 if ( preg_match( '/category/', $layout ) && ! empty( $settings['active_cat_slider'] ) ) {
554 659 $classes .= ' rtsb-slider-layout';
555 660 }
556 661
557 - if ( 'even' === $grid_type ) {
558 - $masonry_class = ' rtsb-even';
662 + if ( 'equal' === $grid_type ) {
663 + $masonry_class = ' rtsb-equal';
559 664 } elseif ( 'masonry' === $grid_type ) {
560 665 $masonry_class = ' rtsb-masonry';
666 + } else {
667 + $masonry_class = ' rtsb-even';
561 668 }
562 669
563 670 if ( ! rtsb()->has_pro() || $is_carousel ) {
564 671 $masonry_class = ' rtsb-even';
565 672 }
673 +
566 674 if ( $is_carousel && ! empty( $settings['raw_settings']['always_show_nav'] ) ) {
567 675 $classes .= ' always-show-nav';
568 676 }
677 +
569 678 if ( ! empty( $settings['raw_settings']['inner_slider_always_show_nav'] ) ) {
570 679 $classes .= ' inner-slider-always-show-nav';
571 680 }
681 + if ( empty( $settings['raw_settings']['cols_mobile'] ) ) {
682 + $classes .= ' rtsb-mobile-flex-row';
683 + }
572 684
573 685 $classes .= ' rtsb-' . $layout . $masonry_class . $loader_class;
574 686
575 687 return apply_filters( 'rtsb/elementor/row/classes', $classes, $settings );
@@ -595,9 +707,9 @@
595 707 } elseif ( $is_cat ) {
596 708 return '';
597 709 } else {
598 710 $ajax_pagination = ! empty( $settings['show_pagination'] ) && 'pagination' !== $settings['pagination_type'];
599 - $page = Fns::product_filters_has_ajax( 'shop' ) || Fns::product_filters_has_ajax( 'archive' );
711 + $page = Fns::product_filters_has_ajax( apply_filters( 'rtsb/builder/set/current/page/type', '' ) );
600 712 $condition = rtsb()->has_pro() && $ajax && ( $ajax_pagination || $has_filters || $page );
601 713
602 714 return $condition ? self::pagination_data( $settings, $template ) : '';
603 715 }
@@ -632,9 +744,9 @@
632 744 $d_col = 0 === $meta['d_cols'] ? self::default_columns( $meta['layout'] ) : $meta['d_cols'];
633 745 $t_col = 0 === $meta['t_cols'] ? 2 : $meta['t_cols'];
634 746 $m_col = 0 === $meta['m_cols'] ? 1 : $meta['m_cols'];
635 747
636 - if ( \Elementor\Plugin::$instance->breakpoints->has_custom_breakpoints() ) {
748 + if ( Plugin::$instance->breakpoints->has_custom_breakpoints() ) {
637 749 // Widescreen.
638 750 $w_col = self::get_data( $settings, 'cols_widescreen' );
639 751 $w_col = 0 === $w_col ? self::default_columns( $meta['layout'] ) : $w_col;
640 752 $w_group = self::get_data( $settings, 'cols_group_widescreen', 1 );
@@ -665,8 +777,11 @@
665 777 $breakpoints = [
666 778 0 => [
667 779 'slidesPerView' => absint( $m_col ),
668 780 'slidesPerGroup' => absint( $meta['m_group'] ),
781 + 'grid' => [
782 + 'rows' => 1,
783 + ],
669 784 'pagination' => [
670 785 'dynamicBullets' => $has_dynamic_dots,
671 786 ],
672 787 ],
@@ -842,9 +957,11 @@
842 957
843 958 if ( $is_carousel ) {
844 959 $loader_class = ' full-op';
845 960 }
846 -
961 + if ( ! Fns::enable_loader() ) {
962 + return '';
963 + }
847 964 return '<div class="rtsb-elements-loading rtsb-ball-clip-rotate"><div></div></div>';
848 965 }
849 966
850 967 /**
@@ -885,10 +1002,11 @@
885 1002 *
886 1003 * @return void
887 1004 */
888 1005 public static function register_scripts( $scripts ) {
889 - $caro = false;
890 - $script = [];
1006 + $caro = false;
1007 + $masonry = false;
1008 + $script = [];
891 1009
892 1010 $script[] = 'jquery';
893 1011
894 1012 foreach ( $scripts as $sc => $value ) {
@@ -895,8 +1013,12 @@
895 1013 if ( ! empty( $sc ) ) {
896 1014 if ( 'isCarousel' === $sc ) {
897 1015 $caro = $value;
898 1016 }
1017 +
1018 + if ( 'isMasonry' === $sc ) {
1019 + $masonry = $value;
1020 + }
899 1021 }
900 1022 }
901 1023
902 1024 if ( count( $scripts ) ) {
@@ -906,11 +1028,15 @@
906 1028 if ( $caro ) {
907 1029 $script[] = 'swiper';
908 1030 }
909 1031
910 - $script[] = 'rtsb-imagesloaded';
911 - $script[] = 'rtsb-public';
1032 + if ( $masonry ) {
1033 + $script[] = 'masonry';
1034 + }
912 1035
1036 + $script[] = 'imagesloaded';
1037 + $script[] = Fns::optimized_handle( 'rtsb-public' );
1038 +
913 1039 foreach ( $script as $sc ) {
914 1040 wp_enqueue_script( $sc );
915 1041 }
916 1042 }
@@ -952,6 +1078,827 @@
952 1078 $products_col = absint( get_option( 'woocommerce_catalog_columns', 4 ) );
953 1079 $products_per_page = apply_filters( 'rtsb/elementor/archive/products_per_page', $products_row * $products_col );
954 1080
955 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;
956 1903 }
957 1904 }