PluginProbe
ShopBuilder – WooCommerce Builder For Elementor / 3.2.5
ShopBuilder – WooCommerce Builder For Elementor v3.2.5
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 +898 -38 2.1.63.2.5 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' ),
@@ -196,8 +226,9 @@
196 226 'auto_play' => ! empty( $meta['slide_autoplay'] ),
197 227 'stop_on_hover' => ! empty( $meta['pause_hover'] ),
198 228 'slider_nav' => ! empty( $meta['slider_nav'] ),
199 229 'slider_dot' => ! empty( $meta['slider_pagi'] ),
230 + 'slider_dynamic_dot' => ! empty( $meta['slider_dynamic_pagi'] ),
200 231 'loop' => ! empty( $meta['slider_loop'] ),
201 232 'lazy_load' => ! empty( $meta['slider_lazy_load'] ),
202 233 'auto_height' => ! empty( $meta['slider_auto_height'] ),
203 234 'speed' => self::get_data( $meta, 'slide_speed', 2000 ),
@@ -340,9 +371,16 @@
340 371
341 372 if ( ! empty( $settings['single_category'] ) ) {
342 373 $visibility[] = 'single-cat';
343 374 }
375 + if ( ! empty( $settings['show_brands'] ) ) {
376 + $visibility[] = 'brands';
377 + }
344 378
379 + if ( ! empty( $settings['single_brand'] ) ) {
380 + $visibility[] = 'single-brand';
381 + }
382 +
345 383 if ( ! empty( $settings['show_swatches'] ) ) {
346 384 $visibility[] = 'swatches';
347 385 }
348 386
@@ -408,13 +446,23 @@
408 446 * @return int
409 447 */
410 448 public static function default_columns( $layout ) {
411 449 switch ( $layout ) {
450 + case 'rtsb-post-grid-layout1':
451 + case 'rtsb-post-grid-layout2':
452 + case 'rtsb-post-grid-layout3':
453 + case 'rtsb-team-layout1':
454 + case 'rtsb-team-layout2':
455 + case 'rtsb-testimonial-layout2':
412 456 case 'grid-layout2':
413 457 case 'slider-layout2':
458 + case 'rtsb-coupon-layout1':
459 + case 'rtsb-coupon-layout2':
460 + case 'rtsb-coupon-layout3':
414 461 $columns = 3;
415 462 break;
416 -
463 + case 'rtsb-post-list-layout1':
464 + case 'rtsb-post-list-layout2':
417 465 case 'list-layout1':
418 466 case 'list-layout2':
419 467 case 'list-layout3':
420 468 case 'list-layout7':
@@ -420,9 +468,13 @@
420 468 case 'list-layout7':
421 469 case 'list-layout5':
422 470 $columns = 1;
423 471 break;
424 -
472 + case 'rtsb-team-layout4':
473 + case 'rtsb-testimonial-layout1':
474 + case 'rtsb-testimonial-layout3':
475 + case 'rtsb-testimonial-layout4':
476 + case 'rtsb-testimonial-layout5':
425 477 case 'list-layout4':
426 478 case 'list-layout6':
427 479 case 'slider-layout5':
428 480 case 'slider-layout8':
@@ -427,10 +479,12 @@
427 479 case 'slider-layout5':
428 480 case 'slider-layout8':
429 481 $columns = 2;
430 482 break;
431 -
483 + case 'rtsb-logo-layout1':
484 + case 'rtsb-logo-layout2':
432 485 case 'grid-layout6':
486 + case 'grid-layout9':
433 487 $columns = 5;
434 488 break;
435 489
436 490 case 'category-layout1':
@@ -471,9 +525,10 @@
471 525 public static function prepare_container_classes( $metas = [], $settings = [], $custom_class = '' ) {
472 526 $classes = 'rtsb-elementor-container products rtsb-pos-r ';
473 527 $classes .= $custom_class;
474 528
475 - $layout = $metas['layout'];
529 + $raw_layout = esc_html( $metas['layout'] );
530 + $layout = self::filter_layout( $raw_layout );
476 531 $is_cat = preg_match( '/category/', $layout );
477 532 $cart_txt_class = '';
478 533
479 534 $animation = $metas['hover_animation'];
@@ -501,8 +556,11 @@
501 556
502 557 if ( in_array( 'single-cat', $metas['visibility'], true ) ) {
503 558 $classes .= ' show-single-cat';
504 559 }
560 + if ( in_array( 'single-brand', $metas['visibility'], true ) ) {
561 + $classes .= ' show-single-brand';
562 + }
505 563
506 564 if ( ! $is_cat ) {
507 565 $action_btn_classes = [
508 566 'show_compare_text' => 'has-compare-text',
@@ -533,8 +591,36 @@
533 591 return apply_filters( 'rtsb/product/container/class', $classes, $settings );
534 592 }
535 593
536 594 /**
595 + * Function to filter and validate the layout against allowed patterns.
596 + *
597 + * @param string $layout The layout string to be filtered.
598 + * @param string $template The template to be checked.
599 + *
600 + * @return string
601 + */
602 + public static function filter_layout( $layout, $template = '' ) {
603 + $allowed_patterns = apply_filters( 'rtsb/elementor/custom_layout', [ 'grid', 'list', 'slider', 'category', 'toyup', 'zilly', 'rtsb' ] );
604 + $layout_part = explode( '-', $layout );
605 + $default = 'grid-layout1';
606 +
607 + if ( empty( $layout_part[0] ) ) {
608 + return $default;
609 + }
610 +
611 + if ( in_array( $layout_part[0], $allowed_patterns, true ) ) {
612 + if ( ! rtsb()->has_pro() && ! in_array( $layout, array_keys( Fns::free_layouts( $layout ) ), true ) ) {
613 + $layout = self::set_default_layout( $layout );
614 + }
615 +
616 + return $layout;
617 + } else {
618 + return ! empty( $template ) ? self::set_default_layout( $layout ) : $default;
619 + }
620 + }
621 +
622 + /**
537 623 * Row classes
538 624 *
539 625 * @param array $settings Settings array.
540 626 *
@@ -542,11 +628,15 @@
542 628 */
543 629 public static function prepare_row_classes( $settings = [] ) {
544 630 $masonry_class = null;
545 631 $classes = 'rtsb-row rtsb-content-loader element-loading';
546 - $loader_class = ' rtsb-pre-loader';
547 632
548 - $layout = $settings['layout'];
633 + $loader_class = '';
634 + if ( Fns::enable_loader() ) {
635 + $loader_class = ' rtsb-pre-loader';
636 + }
637 + $raw_layout = esc_html( $settings['layout'] );
638 + $layout = self::filter_layout( $raw_layout );
549 639 $grid_type = $settings['grid_type'];
550 640 $is_carousel = preg_match( '/slider/', $layout );
551 641
552 642 if ( preg_match( '/category/', $layout ) && ! empty( $settings['active_cat_slider'] ) ) {
@@ -552,23 +642,30 @@
552 642 if ( preg_match( '/category/', $layout ) && ! empty( $settings['active_cat_slider'] ) ) {
553 643 $classes .= ' rtsb-slider-layout';
554 644 }
555 645
556 - if ( 'even' === $grid_type ) {
557 - $masonry_class = ' rtsb-even';
646 + if ( 'equal' === $grid_type ) {
647 + $masonry_class = ' rtsb-equal';
558 648 } elseif ( 'masonry' === $grid_type ) {
559 649 $masonry_class = ' rtsb-masonry';
650 + } else {
651 + $masonry_class = ' rtsb-even';
560 652 }
561 653
562 654 if ( ! rtsb()->has_pro() || $is_carousel ) {
563 655 $masonry_class = ' rtsb-even';
564 656 }
657 +
565 658 if ( $is_carousel && ! empty( $settings['raw_settings']['always_show_nav'] ) ) {
566 659 $classes .= ' always-show-nav';
567 660 }
661 +
568 662 if ( ! empty( $settings['raw_settings']['inner_slider_always_show_nav'] ) ) {
569 663 $classes .= ' inner-slider-always-show-nav';
570 664 }
665 + if ( empty( $settings['raw_settings']['cols_mobile'] ) ) {
666 + $classes .= ' rtsb-mobile-flex-row';
667 + }
571 668
572 669 $classes .= ' rtsb-' . $layout . $masonry_class . $loader_class;
573 670
574 671 return apply_filters( 'rtsb/elementor/row/classes', $classes, $settings );
@@ -576,13 +673,13 @@
576 673
577 674 /**
578 675 * Prepare pagination attributes.
579 676 *
580 - * @param string $layout The layout type.
677 + * @param string $layout The layout type.
581 678 * @param bool $has_filters Whether the widget has filters.
582 - * @param string $template The template name.
583 - * @param array $settings The widget settings.
584 - * @param bool $ajax Whether to enable AJAX pagination.
679 + * @param string $template The template name.
680 + * @param array $settings The widget settings.
681 + * @param bool $ajax Whether to enable AJAX pagination.
585 682 *
586 683 * @return string
587 684 */
588 685 public static function prepare_pagination_attr( $layout, $has_filters, $template, $settings, $ajax ) {
@@ -594,9 +691,9 @@
594 691 } elseif ( $is_cat ) {
595 692 return '';
596 693 } else {
597 694 $ajax_pagination = ! empty( $settings['show_pagination'] ) && 'pagination' !== $settings['pagination_type'];
598 - $page = Fns::product_filters_has_ajax( 'shop' ) || Fns::product_filters_has_ajax( 'archive' );
695 + $page = Fns::product_filters_has_ajax( apply_filters( 'rtsb/builder/set/current/page/type', '' ) );
599 696 $condition = rtsb()->has_pro() && $ajax && ( $ajax_pagination || $has_filters || $page );
600 697
601 698 return $condition ? self::pagination_data( $settings, $template ) : '';
602 699 }
@@ -624,15 +721,16 @@
624 721 *
625 722 * @return array
626 723 */
627 724 public static function slider_data( array $meta, $settings = [] ) {
628 - $has_dots = $meta['slider_dot'] ? ' has-dot' : ' no-dot';
629 - $has_dots .= $meta['slider_nav'] ? ' has-nav' : ' no-nav';
630 - $d_col = 0 === $meta['d_cols'] ? self::default_columns( $meta['layout'] ) : $meta['d_cols'];
631 - $t_col = 0 === $meta['t_cols'] ? 2 : $meta['t_cols'];
632 - $m_col = 0 === $meta['m_cols'] ? 1 : $meta['m_cols'];
725 + $has_dots = $meta['slider_dot'] ? ' has-dot' : ' no-dot';
726 + $has_dots .= $meta['slider_nav'] ? ' has-nav' : ' no-nav';
727 + $has_dynamic_dots = $meta['slider_dynamic_dot'] ? true : false;
728 + $d_col = 0 === $meta['d_cols'] ? self::default_columns( $meta['layout'] ) : $meta['d_cols'];
729 + $t_col = 0 === $meta['t_cols'] ? 2 : $meta['t_cols'];
730 + $m_col = 0 === $meta['m_cols'] ? 1 : $meta['m_cols'];
633 731
634 - if ( \Elementor\Plugin::$instance->breakpoints->has_custom_breakpoints() ) {
732 + if ( Plugin::$instance->breakpoints->has_custom_breakpoints() ) {
635 733 // Widescreen.
636 734 $w_col = self::get_data( $settings, 'cols_widescreen' );
637 735 $w_col = 0 === $w_col ? self::default_columns( $meta['layout'] ) : $w_col;
638 736 $w_group = self::get_data( $settings, 'cols_group_widescreen', 1 );
@@ -663,10 +761,13 @@
663 761 $breakpoints = [
664 762 0 => [
665 763 'slidesPerView' => absint( $m_col ),
666 764 'slidesPerGroup' => absint( $meta['m_group'] ),
765 + 'grid' => [
766 + 'rows' => 1,
767 + ],
667 768 'pagination' => [
668 - 'dynamicBullets' => true,
769 + 'dynamicBullets' => $has_dynamic_dots,
669 770 ],
670 771 ],
671 772 ];
672 773
@@ -691,16 +792,16 @@
691 792 }
692 793
693 794 foreach ( $el_breakpoints as $el_breakpoint => $value ) {
694 795 $breakpoint_value = ! empty( $value['value'] ) ? $value['value'] : $value['default_value'];
695 - $dynamic_bullets = false;
796 + $dynamic_bullets = $has_dynamic_dots;
696 797 $slides_per_view = $d_col;
697 798 $slides_per_group = $meta['d_group'];
698 799
699 800 switch ( $el_breakpoint ) {
700 801 case 'widescreen':
701 - $slides_per_view = $w_col;
702 - $slides_per_group = $w_group;
802 + $slides_per_view = $w_col;
803 + $slides_per_group = $w_group;
703 804
704 805 break;
705 806
706 807 case 'laptop':
@@ -709,10 +810,10 @@
709 810
710 811 break;
711 812
712 813 case 'tablet_extra':
713 - $slides_per_view = $l_col;
714 - $slides_per_group = $l_group;
814 + $slides_per_view = $l_col;
815 + $slides_per_group = $l_group;
715 816
716 817 if ( empty( $el_breakpoints['laptop'] ) ) {
717 818 $slides_per_view = $d_col;
718 819 $slides_per_group = $meta['d_group'];
@@ -737,11 +838,11 @@
737 838
738 839 break;
739 840
740 841 case 'mobile_extra':
741 - $slides_per_view = $t_col;
742 - $slides_per_group = $meta['t_group'];
743 - $dynamic_bullets = true;
842 + $slides_per_view = $t_col;
843 + $slides_per_group = $meta['t_group'];
844 + $dynamic_bullets = $has_dynamic_dots;
744 845
745 846 break;
746 847
747 848 case 'mobile':
@@ -746,9 +847,9 @@
746 847
747 848 case 'mobile':
748 849 $slides_per_view = $t_col;
749 850 $slides_per_group = $meta['t_group'];
750 - $dynamic_bullets = true;
851 + $dynamic_bullets = $has_dynamic_dots;
751 852
752 853 if ( ! empty( $el_breakpoints['mobile_extra'] ) ) {
753 854 $slides_per_view = $me_col;
754 855 $slides_per_group = $me_group;
@@ -774,9 +875,9 @@
774 875 0 => [
775 876 'slidesPerView' => absint( $m_col ),
776 877 'slidesPerGroup' => absint( $meta['m_group'] ),
777 878 'pagination' => [
778 - 'dynamicBullets' => true,
879 + 'dynamicBullets' => $has_dynamic_dots,
779 880 ],
780 881 ],
781 882 768 => [
782 883 'slidesPerView' => absint( $t_col ),
@@ -781,9 +882,9 @@
781 882 768 => [
782 883 'slidesPerView' => absint( $t_col ),
783 884 'slidesPerGroup' => absint( $meta['t_group'] ),
784 885 'pagination' => [
785 - 'dynamicBullets' => false,
886 + 'dynamicBullets' => $has_dynamic_dots,
786 887 ],
787 888 ],
788 889 1025 => [
789 890 'slidesPerView' => absint( $d_col ),
@@ -788,9 +889,9 @@
788 889 1025 => [
789 890 'slidesPerView' => absint( $d_col ),
790 891 'slidesPerGroup' => absint( $meta['d_group'] ),
791 892 'pagination' => [
792 - 'dynamicBullets' => false,
893 + 'dynamicBullets' => $has_dynamic_dots,
793 894 ],
794 895 ],
795 896 ];
796 897 }
@@ -840,9 +941,11 @@
840 941
841 942 if ( $is_carousel ) {
842 943 $loader_class = ' full-op';
843 944 }
844 -
945 + if ( ! Fns::enable_loader() ) {
946 + return '';
947 + }
845 948 return '<div class="rtsb-elements-loading rtsb-ball-clip-rotate"><div></div></div>';
846 949 }
847 950
848 951 /**
@@ -883,10 +986,11 @@
883 986 *
884 987 * @return void
885 988 */
886 989 public static function register_scripts( $scripts ) {
887 - $caro = false;
888 - $script = [];
990 + $caro = false;
991 + $masonry = false;
992 + $script = [];
889 993
890 994 $script[] = 'jquery';
891 995
892 996 foreach ( $scripts as $sc => $value ) {
@@ -893,8 +997,12 @@
893 997 if ( ! empty( $sc ) ) {
894 998 if ( 'isCarousel' === $sc ) {
895 999 $caro = $value;
896 1000 }
1001 +
1002 + if ( 'isMasonry' === $sc ) {
1003 + $masonry = $value;
1004 + }
897 1005 }
898 1006 }
899 1007
900 1008 if ( count( $scripts ) ) {
@@ -904,11 +1012,15 @@
904 1012 if ( $caro ) {
905 1013 $script[] = 'swiper';
906 1014 }
907 1015
908 - $script[] = 'rtsb-imagesloaded';
909 - $script[] = 'rtsb-public';
1016 + if ( $masonry ) {
1017 + $script[] = 'masonry';
1018 + }
910 1019
1020 + $script[] = 'imagesloaded';
1021 + $script[] = Fns::optimized_handle( 'rtsb-public' );
1022 +
911 1023 foreach ( $script as $sc ) {
912 1024 wp_enqueue_script( $sc );
913 1025 }
914 1026 }
@@ -950,6 +1062,754 @@
950 1062 $products_col = absint( get_option( 'woocommerce_catalog_columns', 4 ) );
951 1063 $products_per_page = apply_filters( 'rtsb/elementor/archive/products_per_page', $products_row * $products_col );
952 1064
953 1065 return ! empty( $products_per_page ) ? $products_per_page : 12;
1066 + }
1067 + /**
1068 + * Render Filters View.
1069 + *
1070 + * @param array $templates Template name.
1071 + * @param array $settings Control settings.
1072 + *
1073 + * @return string
1074 + */
1075 + public static function filters_view( $templates, $settings ) {
1076 + global $wp;
1077 + $filters = [];
1078 + $html = null;
1079 + $reset = ! empty( $settings['reset_btn'] );
1080 + $reset_mode = 'show' === $settings['reset_btn_behavior'] ? ' show-reset' : ' ondemand-reset';
1081 + $reset_text = ! empty( $settings['reset_btn_text'] ) ? $settings['reset_btn_text'] : esc_html__( 'Reset Filter', 'shopbuilder' );
1082 + $scroll_mode = ! empty( $settings['enable_scroll'] ) ? ' has-scroll' : ' no-scroll';
1083 + $scroll_height = ! empty( $settings['enable_scroll'] ) ? $settings['scroll_height']['size'] : 300;
1084 + $has_mobile_toggle = ! empty( $settings['filter_mobile_toggle'] );
1085 + $toggle_class = $has_mobile_toggle ? ' default-filter-has-toggle' : ' default-filter-no-toggle';
1086 + $mobile_toggle_text = ! empty( $settings['filter_mobile_toggle_text'] ) ? $settings['filter_mobile_toggle_text'] : esc_html__( 'Click to Filter', 'shopbuilder' );
1087 + $scroll_attr = '';
1088 +
1089 + if ( ! empty( $settings['enable_scroll'] ) ) {
1090 + $scroll_attr = ' style="--rtsb-filter-scroll-height: ' . absint( $scroll_height ) . 'px;"';
1091 + }
1092 +
1093 + foreach ( $settings['filter_types'] as $key => $item ) {
1094 + if ( ! defined( 'RTWPVS_PLUGIN_FILE' ) && in_array( $item['input_type_all'], [ 'color', 'button', 'image' ], true ) ) {
1095 + $item['input_type_all'] = 'checkbox';
1096 + }
1097 + $filters[] = [
1098 + 'filter_title' => $item['filter_title'],
1099 + 'filter_items' => $item['filter_items'],
1100 + 'filter_attr' => $item['filter_attr'],
1101 + 'input_type' => 'product_attr' === $item['filter_items'] ? $item['input_type_all'] : $item['input_type'],
1102 + ];
1103 +
1104 + if ( 'rating_filter' === $item['filter_items'] ) {
1105 + $filters[ $key ]['template'] = $templates['rating'];
1106 + } elseif ( 'price_filter' === $item['filter_items'] ) {
1107 +
1108 + $filters[ $key ]['input_type'] = 'slider';
1109 + $filters[ $key ]['template'] = $templates['price'];
1110 + } else {
1111 + $filters[ $key ]['template'] = 'product_attr' === $item['filter_items'] ? $templates[ $item['input_type_all'] ] : $templates[ $item['input_type'] ];
1112 + }
1113 + }
1114 +
1115 + if ( '' === get_option( 'permalink_structure' ) ) {
1116 + $form_action = remove_query_arg( [ 'page', 'paged', 'product-page' ], add_query_arg( $wp->query_string, '', home_url( $wp->request ) ) );
1117 + } else {
1118 + $form_action = preg_replace( '%\/page/[0-9]+%', '', home_url( trailingslashit( $wp->request ) ) );
1119 + }
1120 + $args = [
1121 + 'filters' => $filters,
1122 + 'scroll_mode' => $scroll_mode,
1123 + 'reset_mode' => $reset_mode,
1124 + 'reset' => $reset,
1125 + 'scroll_attr' => $scroll_attr,
1126 + 'toggle_class' => $toggle_class,
1127 + 'reset_text' => $reset_text,
1128 + 'settings' => $settings,
1129 + 'form_action' => $form_action,
1130 + ];
1131 +
1132 + $html .= '<div class="rtsb-default-archive-filters' . esc_attr( $toggle_class ) . '">';
1133 +
1134 + if ( $has_mobile_toggle ) {
1135 + $html .= '<div class="rtsb-filter-mobile-toggle">
1136 + <button class="product-filter-toggle">
1137 + <span class="icon"><i aria-hidden="true" class="toggle-icon rtsb-icon rtsb-icon-filter"></i></span>
1138 + <span class="text reset-text">' . esc_html( $mobile_toggle_text ) . '</span>
1139 + <span></span>
1140 + </button>
1141 + </div>';
1142 + }
1143 +
1144 + $html .= Fns::load_template( $templates['layout'], $args, true );
1145 + $html .= '</div>';
1146 + return $html;
1147 + }
1148 + /**
1149 + * Get taxonomy type.
1150 + *
1151 + * @param string $tax_type Taxonomy type.
1152 + * @param string $attr_type Attribute type.
1153 + *
1154 + * @return string
1155 + */
1156 + public static function get_product_filters_tax_type( $tax_type, $attr_type = '' ) {
1157 + if ( 'product_attr' !== $tax_type ) {
1158 + return $tax_type;
1159 + }
1160 +
1161 + if ( empty( $attr_type ) ) {
1162 + return $tax_type;
1163 + }
1164 +
1165 + return $attr_type;
1166 + }
1167 + /**
1168 + * Get attribute terms.
1169 + *
1170 + * @param string $tax Taxonomy type.
1171 + * @return int[]|string|string[]|\WP_Error|\WP_Term[]
1172 + */
1173 + public static function get_product_filters_attribute_terms( $tax ) {
1174 + $cache_key = 'get_default_filter_attribute_terms_' . $tax;
1175 + if ( isset( self::$cache[ $cache_key ] ) ) {
1176 + return self::$cache[ $cache_key ];
1177 + }
1178 +
1179 + $attributes = wc_get_attribute_taxonomies();
1180 + $att_name = str_replace( 'pa_', '', $tax );
1181 + $exist = array_search( $att_name, array_column( $attributes, 'attribute_name' ), true );
1182 + if ( false === $exist ) {
1183 + self::$cache[ $cache_key ] = [];
1184 + return self::$cache[ $cache_key ];
1185 + }
1186 + $attribute = $tax;
1187 +
1188 + if ( ! is_shop() && is_product_taxonomy() ) {
1189 + $term = get_queried_object();
1190 +
1191 + if ( ! $term instanceof WP_Term ) {
1192 + return [];
1193 + }
1194 +
1195 + $args = [
1196 + 'status' => 'publish',
1197 + 'limit' => -1,
1198 + 'return' => 'ids',
1199 + ];
1200 +
1201 + if ( 'product_cat' === $term->taxonomy ) {
1202 + $args['category'] = [ $term->slug ];
1203 + }
1204 +
1205 + if ( 'product_tag' === $term->taxonomy ) {
1206 + $args['tag'] = [ $term->slug ];
1207 + }
1208 +
1209 + if ( strpos( $term->taxonomy, 'pa_' ) !== false ) {
1210 + $args['tax_query'] = [ // phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_tax_query
1211 + [
1212 + 'taxonomy' => $term->taxonomy,
1213 + 'field' => 'term_id',
1214 + 'terms' => $term->term_id,
1215 + 'operator' => 'IN',
1216 + ],
1217 + ];
1218 + }
1219 +
1220 + $query = new WC_Product_Query( $args );
1221 + $products = $query->get_products();
1222 + $attr_terms = [];
1223 +
1224 + foreach ( $products as $product_id ) {
1225 + $product_attr = wp_get_post_terms( $product_id, $attribute );
1226 +
1227 + foreach ( $product_attr as $attr ) {
1228 + $attr_terms[] = $attr;
1229 + }
1230 + }
1231 + self::$cache[ $cache_key ] = self::filter_products_array_unique( $attr_terms );
1232 + return self::$cache[ $cache_key ];
1233 + } else {
1234 + self::$cache[ $cache_key ] = get_terms(
1235 + [
1236 + 'taxonomy' => $attribute,
1237 + 'hide_empty' => false,
1238 + ]
1239 + );
1240 + return self::$cache[ $cache_key ];
1241 + }
1242 + }
1243 + /**
1244 + * Remove duplicate values from an array.
1245 + *
1246 + * @param array $array The input array.
1247 + * @param bool $keep_key_assoc Whether to keep the key associations after removing duplicates.
1248 + * @return array The array with duplicates removed.
1249 + */
1250 + public static function filter_products_array_unique( $array, $keep_key_assoc = false ) {
1251 + $duplicate_keys = [];
1252 + $tmp = [];
1253 +
1254 + foreach ( $array as $key => $val ) {
1255 + // convert objects to arrays, in_array() does not support objects.
1256 + if ( is_object( $val ) ) {
1257 + $val = (array) $val;
1258 + }
1259 +
1260 + if ( ! in_array( $val, $tmp, true ) ) {
1261 + $tmp[] = $val;
1262 + } else {
1263 + $duplicate_keys[] = $key;
1264 + }
1265 + }
1266 +
1267 + foreach ( $duplicate_keys as $key ) {
1268 + unset( $array[ $key ] );
1269 + }
1270 +
1271 + return $keep_key_assoc ? $array : array_values( $array );
1272 + }
1273 + /**
1274 + * Retrieve product categories (including hierarchical support)
1275 + *
1276 + * @param string $taxonomy Taxonomy name.
1277 + * @return int[]|string|string[]|\WP_Error|\WP_Term[]
1278 + */
1279 + public static function get_all_terms( $taxonomy ) {
1280 + $args = [
1281 + 'taxonomy' => $taxonomy,
1282 + 'suppress_filter' => true,
1283 + 'hide_empty' => false,
1284 + 'pad_counts' => true,
1285 + 'hierarchical' => true,
1286 + ];
1287 +
1288 + $cache_key = 'rtsb_get_terms_filter_products' . $taxonomy;
1289 + $taxonomy_terms = wp_cache_get( $cache_key, 'shopbuilder' );
1290 +
1291 + if ( false === $taxonomy_terms ) {
1292 + $queried_object = get_queried_object();
1293 +
1294 + if ( 'archive' === apply_filters( 'rtsb/builder/set/current/page/type', '' ) && $queried_object instanceof WP_Term && $queried_object->taxonomy === $taxonomy ) {
1295 + $term_id = $queried_object->term_id;
1296 + $taxonomy = $queried_object->taxonomy;
1297 + $archive_cache_key = 'rtsb_get_terms_filter_products_' . $taxonomy . $term_id;
1298 + $taxonomy_terms = wp_cache_get( $archive_cache_key, 'shopbuilder' );
1299 + if ( false === $taxonomy_terms ) {
1300 + $taxonomy_terms = [ $queried_object ];
1301 + $child_args = [
1302 + 'taxonomy' => $taxonomy,
1303 + 'child_of' => $term_id,
1304 + 'hide_empty' => false,
1305 + ];
1306 +
1307 + $child_terms = get_terms( $child_args );
1308 +
1309 + if ( ! empty( $child_terms ) ) {
1310 + $taxonomy_terms = array_merge( $taxonomy_terms, $child_terms );
1311 + }
1312 +
1313 + wp_cache_set( $archive_cache_key, $taxonomy_terms, 'shopbuilder' );
1314 + Cache::set_data_cache_key( $archive_cache_key );
1315 + }
1316 + } else {
1317 + $taxonomy_terms = get_terms( $args );
1318 + }
1319 +
1320 + wp_cache_set( $cache_key, $taxonomy_terms, 'shopbuilder' );
1321 + Cache::set_data_cache_key( $cache_key );
1322 + }
1323 +
1324 + return $taxonomy_terms;
1325 + }
1326 + /**
1327 + * Generates an error message block.
1328 + *
1329 + * @param array $title The title array of the error message block.
1330 + * @param string $wrapper Additional CSS class for the wrapper div.
1331 + *
1332 + * @return string The HTML representation of the error message block.
1333 + */
1334 + public static function filter_error_message( $title, $wrapper ) {
1335 + $html = '<div class="rtsb-product-default-filters ' . esc_attr( $wrapper ) . '">';
1336 + $html .= self::get_default_filter_title( $title );
1337 + $html .= '<div class="default-filter-content">';
1338 + $html .= '<p class="no-filter">' . esc_html__( 'Nothing found.', 'shopbuilder' ) . '</p>';
1339 + $html .= '</div>';
1340 + $html .= '</div>';
1341 +
1342 + return $html;
1343 + }
1344 + /**
1345 + * Get filter title.
1346 + *
1347 + * @param array $title Filter title.
1348 + * @return string
1349 + */
1350 + public static function get_default_filter_title( $title ) {
1351 + $html = '';
1352 +
1353 + if ( empty( $title['title'] ) ) {
1354 + return $html;
1355 + }
1356 +
1357 + $html .= '<div class="default-filter-title-wrapper">';
1358 +
1359 + $html .= '<h3 class="widget-title rtsb-d-flex rtsb-align-items-center"><span class="title">' . $title['title'] . '</span></h3>';
1360 +
1361 + $html .= '</div>';
1362 +
1363 + return apply_filters( 'rtsb/elementor/default/filter/title', $html, $title );
1364 + }
1365 + /**
1366 + * Recursive function to generate the filter list with hierarchy.
1367 + *
1368 + * @param array $data Array of required data.
1369 + * @param string $input Type of input field for the filter (e.g., checkbox).
1370 + * @param array $additional_data Data for additional filtering.
1371 + * @param int $parent ID of the parent term (default: 0).
1372 + *
1373 + * @return string The generated HTML for the product filter list.
1374 + */
1375 + public static function get_product_default_filter_list_html( $data, $input = 'checkbox', $additional_data = [], $parent = 0 ) {
1376 +
1377 + $html = '';
1378 + $default_tax = [];
1379 + $is_attribute = ! empty( $data['is_attribute'] );
1380 + $active_option = isset( $_GET[ $additional_data['taxonomy'] ] ) ? explode( ',', wc_clean( wp_unslash( $_GET[ $additional_data['taxonomy'] ] ) ) ) : []; // phpcs:ignore WordPress.Security.NonceVerification.Recommended, WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
1381 + $counter = 0;
1382 +
1383 + if ( $is_attribute ) {
1384 + list(
1385 + 'filter_name' => $filter_name,
1386 + 'base_link' => $base_link
1387 + ) = self::get_product_filters_attribute_term_info( $additional_data['taxonomy'] );
1388 + }
1389 +
1390 + $html .= '<ul class="product-default-filters input-type-' . esc_attr( $input ) . '">';
1391 +
1392 + foreach ( $data['taxonomy'] as $tax ) {
1393 + if ( $tax->parent !== $parent ) {
1394 + continue;
1395 + }
1396 +
1397 + if ( $is_attribute ) {
1398 + $tax_link = remove_query_arg( $filter_name, $base_link );
1399 + $tax_link = add_query_arg( $filter_name, $tax->slug, $tax_link );
1400 + $active_option = isset( $_GET[ $filter_name ] ) ? explode( ',', sanitize_text_field( wp_unslash( $_GET[ $filter_name ] ) ) ) : []; // phpcs:ignore WordPress.Security.NonceVerification.Recommended
1401 + } else {
1402 + $tax_link = get_term_link( $tax );
1403 + }
1404 +
1405 + $unique_id = substr( uniqid(), -4 );
1406 +
1407 + $active_tax = in_array( $tax->slug, $active_option, true ) ? ' checked' : '';
1408 + $active_tax_parent = in_array( $tax->slug, $active_option, true ) ? ' active' : '';
1409 + $term_children = in_array( $tax->taxonomy, [ 'product_cat', 'product_brand' ], true ) ? get_term_children( $tax->term_id, $tax->taxonomy ) : [];
1410 + $taxonomy = $tax->taxonomy;
1411 + $product_count = $tax->count;
1412 +
1413 + // Show count.
1414 + if ( 'archive' === apply_filters( 'rtsb/builder/set/current/page/type', '' ) && ! empty( $data['count_display'] ) && 'block' === $data['count_display'] ) {
1415 + $product_count = self::count_tax_data( $tax, $tax->count );
1416 + }
1417 +
1418 + // Show Empty Categories.
1419 + if ( empty( $data['show_empty_terms'] ) && 0 === $product_count ) {
1420 + continue;
1421 + }
1422 +
1423 + $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' : '' ) . '">
1424 + <div class="rtsb-default-filter-group' . esc_attr( $active_tax_parent ) . '">
1425 + <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 ) . '>
1426 + <label class="rtsb-default-' . esc_attr( $input ) . '-filter-label" for="rtsb-default-term-filter-' . $unique_id . absint( $tax->term_id ) . '">
1427 + <span class="name">' . esc_html( $tax->name ) . '</span>
1428 + </label>
1429 + <div class="rtsb-product-count">(' . esc_html( $product_count ) . ')</div>
1430 + ' . ( ! empty( $term_children ) && $data['show_child'] ? '<i class="rtsb-plus-icon"></i>' : '' ) . '
1431 + </div>';
1432 +
1433 + // Show Sub-categories.
1434 + if ( $data['show_child'] ) {
1435 + $children = self::get_product_default_filter_list_html( $data, $input, $additional_data, $tax->term_id );
1436 +
1437 + if ( ! empty( $children ) ) {
1438 + $html .= '<div class="filter-child">' . $children . '</div>';
1439 + }
1440 + }
1441 +
1442 + $counter++;
1443 +
1444 + $html .= '</li>';
1445 + }
1446 +
1447 + $html .= '</ul>';
1448 +
1449 + // Check if the output contains any child elements.
1450 + $has_children = strpos( $html, '<li class="rtsb-default-filter-term-item' ) !== false;
1451 +
1452 + if ( ! $has_children ) {
1453 + // Remove the outer <ul> if there are no child elements.
1454 + $html = '';
1455 + }
1456 + return $html;
1457 + }
1458 + /**
1459 + * Get attribute term info.
1460 + *
1461 + * @param string $tax Taxonomy type.
1462 + * @return array
1463 + */
1464 + public static function get_product_filters_attribute_term_info( $tax ) {
1465 + $result = [];
1466 + $attributes = wc_get_attribute_taxonomies();
1467 +
1468 + foreach ( $attributes as $attr ) {
1469 + if ( str_replace( 'pa_', '', $tax ) === $attr->attribute_name ) {
1470 + $term_type = $attr->attribute_type;
1471 + $attribute_slug = $attr->attribute_name;
1472 + $attribute = wc_attribute_taxonomy_name( $attr->attribute_name );
1473 + break;
1474 + }
1475 + }
1476 +
1477 + $filter_name = 'filter_' . wc_attribute_taxonomy_slug( $attribute_slug );
1478 +
1479 + $result['attribute'] = $attribute ?? '';
1480 + $result['term_type'] = $term_type ?? '';
1481 + $result['attribute_slug'] = $attribute_slug ?? '';
1482 + $result['filter_name'] = $filter_name;
1483 + $result['base_link'] = self::get_base_url();
1484 +
1485 + return $result;
1486 + }
1487 + /**
1488 + * Get base URL.
1489 + *
1490 + * @return string|null
1491 + */
1492 + public static function get_base_url() {
1493 + global $wp;
1494 + return home_url( add_query_arg( [], $wp->request ) );
1495 + }
1496 + /**
1497 + * Count the number of occurrences for a specific term in a taxonomy for the current queried object.
1498 + *
1499 + * @param object|array $tax The term object for the taxonomy.
1500 + * @param int $count The initial count value.
1501 + *
1502 + * @return int The updated count value.
1503 + */
1504 + public static function count_tax_data( $tax, $count ) {
1505 + $page = get_queried_object();
1506 +
1507 + if ( is_array( $tax ) && strpos( $tax['taxonomy'], 'attribute_' ) !== false ) {
1508 + $taxonomy = str_replace( 'attribute_', '', $tax['taxonomy'] );
1509 + $term_id = $tax['term_id'];
1510 + } else {
1511 + $taxonomy = $tax->taxonomy;
1512 + $term_id = $tax->term_id;
1513 + }
1514 +
1515 + if ( strpos( $page->taxonomy, 'pa_' ) !== false ) {
1516 + $args['status'] = 'publish';
1517 + $args['limit'] = -1;
1518 + $args['return'] = 'ids';
1519 + $args['tax_query'] = [ // phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_tax_query
1520 + 'relation' => 'AND',
1521 + [
1522 + 'taxonomy' => $page->taxonomy,
1523 + 'field' => 'term_id',
1524 + 'terms' => $page->term_id,
1525 + 'operator' => 'IN',
1526 + ],
1527 + [
1528 + 'taxonomy' => $tax->taxonomy,
1529 + 'field' => 'term_id',
1530 + 'terms' => $tax->term_id,
1531 + 'operator' => 'IN',
1532 + ],
1533 + ];
1534 +
1535 + $query = new WC_Product_Query( $args );
1536 + $products = $query->get_products();
1537 +
1538 + return count( $products );
1539 + }
1540 +
1541 + if ( $taxonomy !== $page->taxonomy ) {
1542 + $args = [
1543 + 'limit' => -1,
1544 + 'return' => 'ids',
1545 + 'status' => 'publish',
1546 + 'tax_query' => [ // phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_tax_query
1547 + [
1548 + 'taxonomy' => $taxonomy,
1549 + 'field' => 'term_id',
1550 + 'terms' => $term_id,
1551 + ],
1552 + ],
1553 + ];
1554 +
1555 + if ( 'product_cat' === $page->taxonomy ) {
1556 + $args['category'] = [ $page->slug ];
1557 + }
1558 +
1559 + if ( 'product_tag' === $page->taxonomy ) {
1560 + $args['tag'] = [ $page->slug ];
1561 + }
1562 +
1563 + $query = new WC_Product_Query( $args );
1564 + $products = $query->get_products();
1565 +
1566 + $count = count( $products );
1567 + }
1568 +
1569 + return $count;
1570 + }
1571 + /**
1572 + * Get filter HTML.
1573 + *
1574 + * @param string $filter_type Filter type.
1575 + * @param array $options Options.
1576 + * @param array $additional_data Data for additional filtering.
1577 + * @param string $input Input type.
1578 + *
1579 + * @return string The generated HTML for the attribute filter list.
1580 + */
1581 + public static function get_default_filter_html( $filter_type, $options, $additional_data = [], $input = 'checkbox' ) {
1582 + $html = '<ul class="product-filters input-type-' . esc_attr( $input ) . '" ';
1583 + $active_option = isset( $_GET[ $filter_type ] ) ? explode( ',', wc_clean( wp_unslash( $_GET[ $filter_type ] ) ) ) : []; // phpcs:ignore WordPress.Security.NonceVerification.Recommended, WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
1584 + $option_link = self::get_base_url() . '/' . $filter_type . '/';
1585 +
1586 + foreach ( $options as $option => $option_name ) {
1587 + $unique_id = substr( uniqid(), -6 );
1588 + $active_tax = in_array( $option, $active_option, true ) ? ' checked' : '';
1589 + $active_group = in_array( $option, $active_option, true ) ? ' active' : '';
1590 +
1591 + $html .= '
1592 + <li class="rtsb-term-item">
1593 + <div class="rtsb-default-filter-group' . esc_attr( $active_group ) . '">
1594 + <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 . '>
1595 + <label class="rtsb-default-' . esc_attr( $input ) . '-filter-label" for="rtsb-term-default-filter-' . $unique_id . '">
1596 + <span class="name">' . esc_html( $option_name ) . '</span>
1597 + </label>
1598 + </div>
1599 + </li>';
1600 + }
1601 +
1602 + $html .= '</ul>';
1603 +
1604 + return $html;
1605 + }
1606 + /**
1607 + * Get the count of products with a specific star rating.
1608 + *
1609 + * @param int $star_rating The star rating value.
1610 + *
1611 + * @return int
1612 + */
1613 + public static function get_product_rating_count( $star_rating ) {
1614 + $args = [
1615 + 'status' => 'publish',
1616 + 'limit' => -1,
1617 + 'product_rating' => sprintf( '%.1f', $star_rating ),
1618 + ];
1619 +
1620 + if ( is_product_taxonomy() ) {
1621 + $term = get_queried_object();
1622 + $term_type = 'product_cat' === $term->taxonomy ? 'product_category_id' : 'product_tag_id';
1623 +
1624 + if ( $term instanceof WP_Term ) {
1625 + $args[ $term_type ] = [ $term->term_id ];
1626 + }
1627 + }
1628 +
1629 + $query = new WC_Product_Query( $args );
1630 + $products = $query->get_products();
1631 +
1632 + return count( $products );
1633 + }
1634 + /**
1635 + * Get attribute filter HTML.
1636 + *
1637 + * @param array $data Array of required data.
1638 + * @param string $input Type of input field for the filter (e.g., color).
1639 + *
1640 + * @return string The generated HTML for the attribute filter list.
1641 + */
1642 + public static function get_attribute_filter_list_html( $data, $input = 'color' ) {
1643 + if ( ! function_exists( 'rtwpvs' ) ) {
1644 + return '';
1645 + }
1646 +
1647 + $terms = $data['terms'];
1648 + $term_info = $data['term_info'];
1649 + $show_tooltips = $data['show_tooltips'];
1650 + $show_empty_terms = $data['show_empty_terms'];
1651 + $counter = 0;
1652 +
1653 + $html = '<ul class="product-default-filters rtsb-terms-wrapper ' . esc_attr( $term_info['type'] ) . '-variable-wrapper' . esc_attr( $data['show_label'] ) . '">';
1654 +
1655 + foreach ( $terms as $attr_term ) {
1656 + $count = $attr_term->count;
1657 + $term_link = remove_query_arg( $term_info['filter_name'], $term_info['base_link'] );
1658 + $term_link = add_query_arg( $term_info['filter_name'], $attr_term->slug, $term_link );
1659 + $unique_id = substr( uniqid(), -6 );
1660 + $name = 'term-' . wc_variation_attribute_name( $term_info['attribute'] ) . '-' . $unique_id;
1661 + $selected_class = in_array( $attr_term->slug, $term_info['current_filter'], true ) ? ' selected' : '';
1662 + $selected_item = in_array( $attr_term->slug, $term_info['current_filter'], true ) ? ' checked' : '';
1663 + $active_class = in_array( $attr_term->slug, $term_info['current_filter'], true ) ? ' active' : '';
1664 +
1665 + $args = [
1666 + 'id' => $name,
1667 + 'name' => $attr_term->name,
1668 + 'link' => $term_link,
1669 + 'type' => $term_info['type'],
1670 + 'term_id' => $attr_term->term_id,
1671 + 'term_slug' => $attr_term->slug,
1672 + 'taxonomy' => wc_variation_attribute_name( $term_info['attribute'] ),
1673 + 'tooltips' => $show_tooltips,
1674 + 'attribute_name' => $term_info['attribute'],
1675 + 'selected_item' => $selected_item,
1676 + ];
1677 +
1678 + if ( 'archive' === apply_filters( 'rtsb/builder/set/current/page/type', '' ) && ! empty( $data['count_display'] ) && 'block' === $data['count_display'] ) {
1679 + $count = self::count_tax_data( $args, $attr_term->count );
1680 + }
1681 +
1682 + $args['count'] = $count;
1683 +
1684 + if ( ! $show_empty_terms && 0 === $count ) {
1685 + continue;
1686 + }
1687 +
1688 + $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 ) . '">';
1689 + $html .= '<div class="rtsb-default-filter-group' . esc_attr( $active_class ) . '">';
1690 + $html .= self::get_input_type_html( $input, $args );
1691 +
1692 + $counter++;
1693 +
1694 + $html .= '</div>';
1695 + $html .= '</li>';
1696 + }
1697 +
1698 + $html .= '</ul>';
1699 +
1700 + return $html;
1701 + }
1702 + /**
1703 + * Get input type HTML.
1704 + *
1705 + * @param string $input Input type.
1706 + * @param array $args Args.
1707 + * @return mixed|string|null
1708 + */
1709 + public static function get_input_type_html( $input, $args ) {
1710 + $html = '';
1711 + $count = $args['count'];
1712 +
1713 + switch ( $input ) {
1714 + case 'color':
1715 + $color = sanitize_hex_color( get_term_meta( $args['term_id'], 'product_attribute_color', true ) );
1716 +
1717 + $html .= sprintf(
1718 + // phpcs:ignore Generic.Strings.UnnecessaryStringConcat.Found
1719 + '<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>',
1720 + esc_attr( $args['id'] ),
1721 + esc_attr( $args['type'] ),
1722 + $args['tooltips'] ? esc_attr( ' tipsy' ) : '',
1723 + esc_attr( $color ),
1724 + esc_html( $args['name'] ),
1725 + absint( $count )
1726 + );
1727 + break;
1728 +
1729 + case 'image':
1730 + if ( ! function_exists( 'rtwpvs' ) ) {
1731 + return $html;
1732 + }
1733 +
1734 + $attachment_id = absint( get_term_meta( $args['term_id'], 'product_attribute_image', true ) );
1735 + $image_size = rtwpvs()->get_option( 'attribute_image_size' );
1736 + $image_url = wp_get_attachment_image_url( $attachment_id, apply_filters( 'rtwpvs_product_attribute_image_size', $image_size ) );
1737 +
1738 + $html .= sprintf(
1739 + // phpcs:ignore Generic.Strings.UnnecessaryStringConcat.Found
1740 + '<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>',
1741 + esc_attr( $args['id'] ),
1742 + esc_attr( $args['type'] ),
1743 + $args['tooltips'] ? esc_attr( ' tipsy' ) : '',
1744 + esc_attr( $args['name'] ),
1745 + esc_url( $image_url )
1746 + );
1747 + break;
1748 +
1749 + case 'button':
1750 + $html .= sprintf(
1751 + // phpcs:ignore Generic.Strings.UnnecessaryStringConcat.Found
1752 + '<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>',
1753 + esc_attr( $args['id'] ),
1754 + esc_attr( $args['type'] ),
1755 + $args['tooltips'] ? esc_attr( ' tipsy' ) : '',
1756 + esc_html( $args['name'] ),
1757 + absint( $count )
1758 + );
1759 + break;
1760 +
1761 + default:
1762 + }
1763 +
1764 + return apply_filters( 'rtsb/elementor/default/filter/get_input_type_html', $html );
1765 + }
1766 + /**
1767 + * Get reset button.
1768 + *
1769 + * @param string $btn_text Button text.
1770 + * @param array $settings Settings array.
1771 + *
1772 + * @return string
1773 + */
1774 + public static function get_default_filter_reset_button( $btn_text, $settings ) {
1775 + $html = '';
1776 +
1777 + ob_start();
1778 +
1779 + $active = ! empty( $_SERVER['QUERY_STRING'] ) ? ' active' : '';
1780 + $reset = ! empty( $settings['reset_btn'] );
1781 + $apply_text = ! empty( $settings['apply_filters_btn_text'] ) ? $settings['apply_filters_btn_text'] : esc_html__( 'Apply Filters', 'shopbuilder' );
1782 + $apply_icon = ! empty( $settings['apply_filters_btn_icon'] ) ? $settings['apply_filters_btn_icon'] : [];
1783 + echo '<div class="default-filter-btn-wrapper">';
1784 + ?>
1785 + <?php if ( $settings['show_filter_btn'] ) { ?>
1786 + <div class="rtsb-product-default-filters rtsb-apply-filters-btn">
1787 + <div class="reset-btn-item">
1788 + <button class="rtsb-apply-filters init">
1789 + <span class="icon"><?php Fns::print_html( Fns::icons_manager( $apply_icon, 'icon-default' ) ); ?></span>
1790 + <span class="text reset-text"><?php echo esc_html( $apply_text ); ?></span>
1791 + <span></span>
1792 + </button>
1793 + </div>
1794 + </div>
1795 + <?php } ?>
1796 + <?php
1797 + if ( $reset ) {
1798 + ?>
1799 + <div class="rtsb-product-default-filters rtsb-reset<?php echo esc_attr( $active ); ?>">
1800 + <div class="reset-btn-item">
1801 + <button class="product-default-filter-reset">
1802 + <span class="text reset-text"><?php echo esc_html( $btn_text ); ?></span>
1803 + <span></span>
1804 + </button>
1805 + </div>
1806 + </div>
1807 + <?php
1808 + }
1809 + echo '</div>';
1810 +
1811 + $html .= ob_get_clean();
1812 +
1813 + return $html;
954 1814 }
955 1815 }