PluginProbe
ShopBuilder – WooCommerce Builder For Elementor / 3.2.0
ShopBuilder – WooCommerce Builder For Elementor v3.2.0
3.4.2 3.4.1 3.4.0 2.0.1 2.0.2 2.0.3 2.1.0 2.1.1 2.1.10 2.1.11 2.1.12 2.1.13 2.1.14 2.1.15 2.1.2 2.1.3 2.1.4 2.1.5 2.1.6 2.1.7 2.1.8 2.1.9 2.2.0 2.2.1 2.2.2 All 63 releases
← All changes | app/Elementor/Helper/RenderHelpers.php +884 -38 2.1.4 → 3.2.0 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,12 @@
21 25 * BuilderFns class
22 26 */
23 27 class RenderHelpers {
24 28 /**
29 + * @var array
30 + */
31 + private static $cache = [];
32 + /**
25 33 * Get data.
26 34 *
27 35 * @param array|string $haystack The array or string to search for the value.
28 36 * @param string $needle The key to look for in the array or the string itself.
@@ -83,8 +91,9 @@
83 91 'order' => self::get_data( $meta, 'posts_order', 'DESC' ),
84 92 'author_in' => self::get_data( $meta, 'filter_author', [] ),
85 93 'display_by' => self::get_data( $meta, 'products_filter', 'date' ),
86 94 'categories' => self::get_data( $meta, 'filter_categories', [] ),
95 + 'brands' => self::get_data( $meta, 'filter_brands', [] ),
87 96 'tags' => self::get_data( $meta, 'filter_tags', [] ),
88 97 'attributes' => self::get_data( $meta, 'filter_attributes', [] ),
89 98 'relation' => self::get_data( $meta, 'tax_relation', 'OR' ),
90 99 'category_source' => self::get_data( $meta, 'select_source', 'product_cat' ),
@@ -178,8 +187,9 @@
178 187 'out_of_stock_badge_text' => self::get_data( $meta, 'stock_badges_text', esc_html__( 'Out of Stock', 'shopbuilder' ) ),
179 188 'badge_position' => self::get_data( $meta, 'badges_position', 'top' ),
180 189 'badge_alignment' => self::get_data( $meta, 'badges_alignment', 'left' ),
181 190 'badge_preset' => self::get_data( $meta, 'custom_badge_preset', 'preset-1' ),
191 + 'enable_badges_module' => self::get_data( $meta, 'enable_badges_module', '' ),
182 192
183 193 // Link.
184 194 'image_link' => ! empty( $meta['image_link'] ),
185 195 'title_link' => ! empty( $meta['title_link'] ),
@@ -195,8 +205,9 @@
195 205 'auto_play' => ! empty( $meta['slide_autoplay'] ),
196 206 'stop_on_hover' => ! empty( $meta['pause_hover'] ),
197 207 'slider_nav' => ! empty( $meta['slider_nav'] ),
198 208 'slider_dot' => ! empty( $meta['slider_pagi'] ),
209 + 'slider_dynamic_dot' => ! empty( $meta['slider_dynamic_pagi'] ),
199 210 'loop' => ! empty( $meta['slider_loop'] ),
200 211 'lazy_load' => ! empty( $meta['slider_lazy_load'] ),
201 212 'auto_height' => ! empty( $meta['slider_auto_height'] ),
202 213 'speed' => self::get_data( $meta, 'slide_speed', 2000 ),
@@ -339,9 +350,16 @@
339 350
340 351 if ( ! empty( $settings['single_category'] ) ) {
341 352 $visibility[] = 'single-cat';
342 353 }
354 + if ( ! empty( $settings['show_brands'] ) ) {
355 + $visibility[] = 'brands';
356 + }
343 357
358 + if ( ! empty( $settings['single_brand'] ) ) {
359 + $visibility[] = 'single-brand';
360 + }
361 +
344 362 if ( ! empty( $settings['show_swatches'] ) ) {
345 363 $visibility[] = 'swatches';
346 364 }
347 365
@@ -407,13 +425,23 @@
407 425 * @return int
408 426 */
409 427 public static function default_columns( $layout ) {
410 428 switch ( $layout ) {
429 + case 'rtsb-post-grid-layout1':
430 + case 'rtsb-post-grid-layout2':
431 + case 'rtsb-post-grid-layout3':
432 + case 'rtsb-team-layout1':
433 + case 'rtsb-team-layout2':
434 + case 'rtsb-testimonial-layout2':
411 435 case 'grid-layout2':
412 436 case 'slider-layout2':
437 + case 'rtsb-coupon-layout1':
438 + case 'rtsb-coupon-layout2':
439 + case 'rtsb-coupon-layout3':
413 440 $columns = 3;
414 441 break;
415 -
442 + case 'rtsb-post-list-layout1':
443 + case 'rtsb-post-list-layout2':
416 444 case 'list-layout1':
417 445 case 'list-layout2':
418 446 case 'list-layout3':
419 447 case 'list-layout7':
@@ -419,9 +447,13 @@
419 447 case 'list-layout7':
420 448 case 'list-layout5':
421 449 $columns = 1;
422 450 break;
423 -
451 + case 'rtsb-team-layout4':
452 + case 'rtsb-testimonial-layout1':
453 + case 'rtsb-testimonial-layout3':
454 + case 'rtsb-testimonial-layout4':
455 + case 'rtsb-testimonial-layout5':
424 456 case 'list-layout4':
425 457 case 'list-layout6':
426 458 case 'slider-layout5':
427 459 case 'slider-layout8':
@@ -426,10 +458,12 @@
426 458 case 'slider-layout5':
427 459 case 'slider-layout8':
428 460 $columns = 2;
429 461 break;
430 -
462 + case 'rtsb-logo-layout1':
463 + case 'rtsb-logo-layout2':
431 464 case 'grid-layout6':
465 + case 'grid-layout9':
432 466 $columns = 5;
433 467 break;
434 468
435 469 case 'category-layout1':
@@ -470,9 +504,10 @@
470 504 public static function prepare_container_classes( $metas = [], $settings = [], $custom_class = '' ) {
471 505 $classes = 'rtsb-elementor-container products rtsb-pos-r ';
472 506 $classes .= $custom_class;
473 507
474 - $layout = $metas['layout'];
508 + $raw_layout = esc_html( $metas['layout'] );
509 + $layout = self::filter_layout( $raw_layout );
475 510 $is_cat = preg_match( '/category/', $layout );
476 511 $cart_txt_class = '';
477 512
478 513 $animation = $metas['hover_animation'];
@@ -500,8 +535,11 @@
500 535
501 536 if ( in_array( 'single-cat', $metas['visibility'], true ) ) {
502 537 $classes .= ' show-single-cat';
503 538 }
539 + if ( in_array( 'single-brand', $metas['visibility'], true ) ) {
540 + $classes .= ' show-single-brand';
541 + }
504 542
505 543 if ( ! $is_cat ) {
506 544 $action_btn_classes = [
507 545 'show_compare_text' => 'has-compare-text',
@@ -532,8 +570,36 @@
532 570 return apply_filters( 'rtsb/product/container/class', $classes, $settings );
533 571 }
534 572
535 573 /**
574 + * Function to filter and validate the layout against allowed patterns.
575 + *
576 + * @param string $layout The layout string to be filtered.
577 + * @param string $template The template to be checked.
578 + *
579 + * @return string
580 + */
581 + public static function filter_layout( $layout, $template = '' ) {
582 + $allowed_patterns = apply_filters( 'rtsb/elementor/custom_layout', [ 'grid', 'list', 'slider', 'category', 'toyup', 'zilly', 'rtsb' ] );
583 + $layout_part = explode( '-', $layout );
584 + $default = 'grid-layout1';
585 +
586 + if ( empty( $layout_part[0] ) ) {
587 + return $default;
588 + }
589 +
590 + if ( in_array( $layout_part[0], $allowed_patterns, true ) ) {
591 + if ( ! rtsb()->has_pro() && ! in_array( $layout, array_keys( Fns::free_layouts( $layout ) ), true ) ) {
592 + $layout = self::set_default_layout( $layout );
593 + }
594 +
595 + return $layout;
596 + } else {
597 + return ! empty( $template ) ? self::set_default_layout( $layout ) : $default;
598 + }
599 + }
600 +
601 + /**
536 602 * Row classes
537 603 *
538 604 * @param array $settings Settings array.
539 605 *
@@ -541,11 +607,15 @@
541 607 */
542 608 public static function prepare_row_classes( $settings = [] ) {
543 609 $masonry_class = null;
544 610 $classes = 'rtsb-row rtsb-content-loader element-loading';
545 - $loader_class = ' rtsb-pre-loader';
546 611
547 - $layout = $settings['layout'];
612 + $loader_class = '';
613 + if ( Fns::enable_loader() ) {
614 + $loader_class = ' rtsb-pre-loader';
615 + }
616 + $raw_layout = esc_html( $settings['layout'] );
617 + $layout = self::filter_layout( $raw_layout );
548 618 $grid_type = $settings['grid_type'];
549 619 $is_carousel = preg_match( '/slider/', $layout );
550 620
551 621 if ( preg_match( '/category/', $layout ) && ! empty( $settings['active_cat_slider'] ) ) {
@@ -551,12 +621,14 @@
551 621 if ( preg_match( '/category/', $layout ) && ! empty( $settings['active_cat_slider'] ) ) {
552 622 $classes .= ' rtsb-slider-layout';
553 623 }
554 624
555 - if ( 'even' === $grid_type ) {
556 - $masonry_class = ' rtsb-even';
625 + if ( 'equal' === $grid_type ) {
626 + $masonry_class = ' rtsb-equal';
557 627 } elseif ( 'masonry' === $grid_type ) {
558 628 $masonry_class = ' rtsb-masonry';
629 + } else {
630 + $masonry_class = ' rtsb-even';
559 631 }
560 632
561 633 if ( ! rtsb()->has_pro() || $is_carousel ) {
562 634 $masonry_class = ' rtsb-even';
@@ -561,8 +633,19 @@
561 633 if ( ! rtsb()->has_pro() || $is_carousel ) {
562 634 $masonry_class = ' rtsb-even';
563 635 }
564 636
637 + if ( $is_carousel && ! empty( $settings['raw_settings']['always_show_nav'] ) ) {
638 + $classes .= ' always-show-nav';
639 + }
640 +
641 + if ( ! empty( $settings['raw_settings']['inner_slider_always_show_nav'] ) ) {
642 + $classes .= ' inner-slider-always-show-nav';
643 + }
644 + if ( empty( $settings['raw_settings']['cols_mobile'] ) ) {
645 + $classes .= ' rtsb-mobile-flex-row';
646 + }
647 +
565 648 $classes .= ' rtsb-' . $layout . $masonry_class . $loader_class;
566 649
567 650 return apply_filters( 'rtsb/elementor/row/classes', $classes, $settings );
568 651 }
@@ -569,13 +652,13 @@
569 652
570 653 /**
571 654 * Prepare pagination attributes.
572 655 *
573 - * @param string $layout The layout type.
656 + * @param string $layout The layout type.
574 657 * @param bool $has_filters Whether the widget has filters.
575 - * @param string $template The template name.
576 - * @param array $settings The widget settings.
577 - * @param bool $ajax Whether to enable AJAX pagination.
658 + * @param string $template The template name.
659 + * @param array $settings The widget settings.
660 + * @param bool $ajax Whether to enable AJAX pagination.
578 661 *
579 662 * @return string
580 663 */
581 664 public static function prepare_pagination_attr( $layout, $has_filters, $template, $settings, $ajax ) {
@@ -587,9 +670,9 @@
587 670 } elseif ( $is_cat ) {
588 671 return '';
589 672 } else {
590 673 $ajax_pagination = ! empty( $settings['show_pagination'] ) && 'pagination' !== $settings['pagination_type'];
591 - $page = Fns::product_filters_has_ajax( 'shop' ) || Fns::product_filters_has_ajax( 'archive' );
674 + $page = Fns::product_filters_has_ajax( apply_filters( 'rtsb/builder/set/current/page/type', '' ) );
592 675 $condition = rtsb()->has_pro() && $ajax && ( $ajax_pagination || $has_filters || $page );
593 676
594 677 return $condition ? self::pagination_data( $settings, $template ) : '';
595 678 }
@@ -617,15 +700,16 @@
617 700 *
618 701 * @return array
619 702 */
620 703 public static function slider_data( array $meta, $settings = [] ) {
621 - $has_dots = $meta['slider_dot'] ? ' has-dot' : ' no-dot';
622 - $has_dots .= $meta['slider_nav'] ? ' has-nav' : ' no-nav';
623 - $d_col = 0 === $meta['d_cols'] ? self::default_columns( $meta['layout'] ) : $meta['d_cols'];
624 - $t_col = 0 === $meta['t_cols'] ? 2 : $meta['t_cols'];
625 - $m_col = 0 === $meta['m_cols'] ? 1 : $meta['m_cols'];
704 + $has_dots = $meta['slider_dot'] ? ' has-dot' : ' no-dot';
705 + $has_dots .= $meta['slider_nav'] ? ' has-nav' : ' no-nav';
706 + $has_dynamic_dots = $meta['slider_dynamic_dot'] ? true : false;
707 + $d_col = 0 === $meta['d_cols'] ? self::default_columns( $meta['layout'] ) : $meta['d_cols'];
708 + $t_col = 0 === $meta['t_cols'] ? 2 : $meta['t_cols'];
709 + $m_col = 0 === $meta['m_cols'] ? 1 : $meta['m_cols'];
626 710
627 - if ( \Elementor\Plugin::$instance->breakpoints->has_custom_breakpoints() ) {
711 + if ( Plugin::$instance->breakpoints->has_custom_breakpoints() ) {
628 712 // Widescreen.
629 713 $w_col = self::get_data( $settings, 'cols_widescreen' );
630 714 $w_col = 0 === $w_col ? self::default_columns( $meta['layout'] ) : $w_col;
631 715 $w_group = self::get_data( $settings, 'cols_group_widescreen', 1 );
@@ -656,10 +740,13 @@
656 740 $breakpoints = [
657 741 0 => [
658 742 'slidesPerView' => absint( $m_col ),
659 743 'slidesPerGroup' => absint( $meta['m_group'] ),
744 + 'grid' => [
745 + 'rows' => 1,
746 + ],
660 747 'pagination' => [
661 - 'dynamicBullets' => true,
748 + 'dynamicBullets' => $has_dynamic_dots,
662 749 ],
663 750 ],
664 751 ];
665 752
@@ -684,16 +771,16 @@
684 771 }
685 772
686 773 foreach ( $el_breakpoints as $el_breakpoint => $value ) {
687 774 $breakpoint_value = ! empty( $value['value'] ) ? $value['value'] : $value['default_value'];
688 - $dynamic_bullets = false;
775 + $dynamic_bullets = $has_dynamic_dots;
689 776 $slides_per_view = $d_col;
690 777 $slides_per_group = $meta['d_group'];
691 778
692 779 switch ( $el_breakpoint ) {
693 780 case 'widescreen':
694 - $slides_per_view = $w_col;
695 - $slides_per_group = $w_group;
781 + $slides_per_view = $w_col;
782 + $slides_per_group = $w_group;
696 783
697 784 break;
698 785
699 786 case 'laptop':
@@ -702,10 +789,10 @@
702 789
703 790 break;
704 791
705 792 case 'tablet_extra':
706 - $slides_per_view = $l_col;
707 - $slides_per_group = $l_group;
793 + $slides_per_view = $l_col;
794 + $slides_per_group = $l_group;
708 795
709 796 if ( empty( $el_breakpoints['laptop'] ) ) {
710 797 $slides_per_view = $d_col;
711 798 $slides_per_group = $meta['d_group'];
@@ -730,11 +817,11 @@
730 817
731 818 break;
732 819
733 820 case 'mobile_extra':
734 - $slides_per_view = $t_col;
735 - $slides_per_group = $meta['t_group'];
736 - $dynamic_bullets = true;
821 + $slides_per_view = $t_col;
822 + $slides_per_group = $meta['t_group'];
823 + $dynamic_bullets = $has_dynamic_dots;
737 824
738 825 break;
739 826
740 827 case 'mobile':
@@ -739,9 +826,9 @@
739 826
740 827 case 'mobile':
741 828 $slides_per_view = $t_col;
742 829 $slides_per_group = $meta['t_group'];
743 - $dynamic_bullets = true;
830 + $dynamic_bullets = $has_dynamic_dots;
744 831
745 832 if ( ! empty( $el_breakpoints['mobile_extra'] ) ) {
746 833 $slides_per_view = $me_col;
747 834 $slides_per_group = $me_group;
@@ -767,9 +854,9 @@
767 854 0 => [
768 855 'slidesPerView' => absint( $m_col ),
769 856 'slidesPerGroup' => absint( $meta['m_group'] ),
770 857 'pagination' => [
771 - 'dynamicBullets' => true,
858 + 'dynamicBullets' => $has_dynamic_dots,
772 859 ],
773 860 ],
774 861 768 => [
775 862 'slidesPerView' => absint( $t_col ),
@@ -774,9 +861,9 @@
774 861 768 => [
775 862 'slidesPerView' => absint( $t_col ),
776 863 'slidesPerGroup' => absint( $meta['t_group'] ),
777 864 'pagination' => [
778 - 'dynamicBullets' => false,
865 + 'dynamicBullets' => $has_dynamic_dots,
779 866 ],
780 867 ],
781 868 1025 => [
782 869 'slidesPerView' => absint( $d_col ),
@@ -781,9 +868,9 @@
781 868 1025 => [
782 869 'slidesPerView' => absint( $d_col ),
783 870 'slidesPerGroup' => absint( $meta['d_group'] ),
784 871 'pagination' => [
785 - 'dynamicBullets' => false,
872 + 'dynamicBullets' => $has_dynamic_dots,
786 873 ],
787 874 ],
788 875 ];
789 876 }
@@ -833,9 +920,11 @@
833 920
834 921 if ( $is_carousel ) {
835 922 $loader_class = ' full-op';
836 923 }
837 -
924 + if ( ! Fns::enable_loader() ) {
925 + return '';
926 + }
838 927 return '<div class="rtsb-elements-loading rtsb-ball-clip-rotate"><div></div></div>';
839 928 }
840 929
841 930 /**
@@ -876,10 +965,11 @@
876 965 *
877 966 * @return void
878 967 */
879 968 public static function register_scripts( $scripts ) {
880 - $caro = false;
881 - $script = [];
969 + $caro = false;
970 + $masonry = false;
971 + $script = [];
882 972
883 973 $script[] = 'jquery';
884 974
885 975 foreach ( $scripts as $sc => $value ) {
@@ -886,8 +976,12 @@
886 976 if ( ! empty( $sc ) ) {
887 977 if ( 'isCarousel' === $sc ) {
888 978 $caro = $value;
889 979 }
980 +
981 + if ( 'isMasonry' === $sc ) {
982 + $masonry = $value;
983 + }
890 984 }
891 985 }
892 986
893 987 if ( count( $scripts ) ) {
@@ -897,11 +991,15 @@
897 991 if ( $caro ) {
898 992 $script[] = 'swiper';
899 993 }
900 994
901 - $script[] = 'rtsb-imagesloaded';
902 - $script[] = 'rtsb-public';
995 + if ( $masonry ) {
996 + $script[] = 'masonry';
997 + }
903 998
999 + $script[] = 'imagesloaded';
1000 + $script[] = Fns::optimized_handle( 'rtsb-public' );
1001 +
904 1002 foreach ( $script as $sc ) {
905 1003 wp_enqueue_script( $sc );
906 1004 }
907 1005 }
@@ -943,6 +1041,754 @@
943 1041 $products_col = absint( get_option( 'woocommerce_catalog_columns', 4 ) );
944 1042 $products_per_page = apply_filters( 'rtsb/elementor/archive/products_per_page', $products_row * $products_col );
945 1043
946 1044 return ! empty( $products_per_page ) ? $products_per_page : 12;
1045 + }
1046 + /**
1047 + * Render Filters View.
1048 + *
1049 + * @param array $templates Template name.
1050 + * @param array $settings Control settings.
1051 + *
1052 + * @return string
1053 + */
1054 + public static function filters_view( $templates, $settings ) {
1055 + global $wp;
1056 + $filters = [];
1057 + $html = null;
1058 + $reset = ! empty( $settings['reset_btn'] );
1059 + $reset_mode = 'show' === $settings['reset_btn_behavior'] ? ' show-reset' : ' ondemand-reset';
1060 + $reset_text = ! empty( $settings['reset_btn_text'] ) ? $settings['reset_btn_text'] : esc_html__( 'Reset Filter', 'shopbuilder' );
1061 + $scroll_mode = ! empty( $settings['enable_scroll'] ) ? ' has-scroll' : ' no-scroll';
1062 + $scroll_height = ! empty( $settings['enable_scroll'] ) ? $settings['scroll_height']['size'] : 300;
1063 + $has_mobile_toggle = ! empty( $settings['filter_mobile_toggle'] );
1064 + $toggle_class = $has_mobile_toggle ? ' default-filter-has-toggle' : ' default-filter-no-toggle';
1065 + $mobile_toggle_text = ! empty( $settings['filter_mobile_toggle_text'] ) ? $settings['filter_mobile_toggle_text'] : esc_html__( 'Click to Filter', 'shopbuilder' );
1066 + $scroll_attr = '';
1067 +
1068 + if ( ! empty( $settings['enable_scroll'] ) ) {
1069 + $scroll_attr = ' style="--rtsb-filter-scroll-height: ' . absint( $scroll_height ) . 'px;"';
1070 + }
1071 +
1072 + foreach ( $settings['filter_types'] as $key => $item ) {
1073 + if ( ! defined( 'RTWPVS_PLUGIN_FILE' ) && in_array( $item['input_type_all'], [ 'color', 'button', 'image' ], true ) ) {
1074 + $item['input_type_all'] = 'checkbox';
1075 + }
1076 + $filters[] = [
1077 + 'filter_title' => $item['filter_title'],
1078 + 'filter_items' => $item['filter_items'],
1079 + 'filter_attr' => $item['filter_attr'],
1080 + 'input_type' => 'product_attr' === $item['filter_items'] ? $item['input_type_all'] : $item['input_type'],
1081 + ];
1082 +
1083 + if ( 'rating_filter' === $item['filter_items'] ) {
1084 + $filters[ $key ]['template'] = $templates['rating'];
1085 + } elseif ( 'price_filter' === $item['filter_items'] ) {
1086 +
1087 + $filters[ $key ]['input_type'] = 'slider';
1088 + $filters[ $key ]['template'] = $templates['price'];
1089 + } else {
1090 + $filters[ $key ]['template'] = 'product_attr' === $item['filter_items'] ? $templates[ $item['input_type_all'] ] : $templates[ $item['input_type'] ];
1091 + }
1092 + }
1093 +
1094 + if ( '' === get_option( 'permalink_structure' ) ) {
1095 + $form_action = remove_query_arg( [ 'page', 'paged', 'product-page' ], add_query_arg( $wp->query_string, '', home_url( $wp->request ) ) );
1096 + } else {
1097 + $form_action = preg_replace( '%\/page/[0-9]+%', '', home_url( trailingslashit( $wp->request ) ) );
1098 + }
1099 + $args = [
1100 + 'filters' => $filters,
1101 + 'scroll_mode' => $scroll_mode,
1102 + 'reset_mode' => $reset_mode,
1103 + 'reset' => $reset,
1104 + 'scroll_attr' => $scroll_attr,
1105 + 'toggle_class' => $toggle_class,
1106 + 'reset_text' => $reset_text,
1107 + 'settings' => $settings,
1108 + 'form_action' => $form_action,
1109 + ];
1110 +
1111 + $html .= '<div class="rtsb-default-archive-filters' . esc_attr( $toggle_class ) . '">';
1112 +
1113 + if ( $has_mobile_toggle ) {
1114 + $html .= '<div class="rtsb-filter-mobile-toggle">
1115 + <button class="product-filter-toggle">
1116 + <span class="icon"><i aria-hidden="true" class="toggle-icon rtsb-icon rtsb-icon-filter"></i></span>
1117 + <span class="text reset-text">' . esc_html( $mobile_toggle_text ) . '</span>
1118 + <span></span>
1119 + </button>
1120 + </div>';
1121 + }
1122 +
1123 + $html .= Fns::load_template( $templates['layout'], $args, true );
1124 + $html .= '</div>';
1125 + return $html;
1126 + }
1127 + /**
1128 + * Get taxonomy type.
1129 + *
1130 + * @param string $tax_type Taxonomy type.
1131 + * @param string $attr_type Attribute type.
1132 + *
1133 + * @return string
1134 + */
1135 + public static function get_product_filters_tax_type( $tax_type, $attr_type = '' ) {
1136 + if ( 'product_attr' !== $tax_type ) {
1137 + return $tax_type;
1138 + }
1139 +
1140 + if ( empty( $attr_type ) ) {
1141 + return $tax_type;
1142 + }
1143 +
1144 + return $attr_type;
1145 + }
1146 + /**
1147 + * Get attribute terms.
1148 + *
1149 + * @param string $tax Taxonomy type.
1150 + * @return int[]|string|string[]|\WP_Error|\WP_Term[]
1151 + */
1152 + public static function get_product_filters_attribute_terms( $tax ) {
1153 + $cache_key = 'get_default_filter_attribute_terms_' . $tax;
1154 + if ( isset( self::$cache[ $cache_key ] ) ) {
1155 + return self::$cache[ $cache_key ];
1156 + }
1157 +
1158 + $attributes = wc_get_attribute_taxonomies();
1159 + $att_name = str_replace( 'pa_', '', $tax );
1160 + $exist = array_search( $att_name, array_column( $attributes, 'attribute_name' ), true );
1161 + if ( false === $exist ) {
1162 + self::$cache[ $cache_key ] = [];
1163 + return self::$cache[ $cache_key ];
1164 + }
1165 + $attribute = $tax;
1166 +
1167 + if ( ! is_shop() && is_product_taxonomy() ) {
1168 + $term = get_queried_object();
1169 +
1170 + if ( ! $term instanceof WP_Term ) {
1171 + return [];
1172 + }
1173 +
1174 + $args = [
1175 + 'status' => 'publish',
1176 + 'limit' => -1,
1177 + 'return' => 'ids',
1178 + ];
1179 +
1180 + if ( 'product_cat' === $term->taxonomy ) {
1181 + $args['category'] = [ $term->slug ];
1182 + }
1183 +
1184 + if ( 'product_tag' === $term->taxonomy ) {
1185 + $args['tag'] = [ $term->slug ];
1186 + }
1187 +
1188 + if ( strpos( $term->taxonomy, 'pa_' ) !== false ) {
1189 + $args['tax_query'] = [ // phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_tax_query
1190 + [
1191 + 'taxonomy' => $term->taxonomy,
1192 + 'field' => 'term_id',
1193 + 'terms' => $term->term_id,
1194 + 'operator' => 'IN',
1195 + ],
1196 + ];
1197 + }
1198 +
1199 + $query = new WC_Product_Query( $args );
1200 + $products = $query->get_products();
1201 + $attr_terms = [];
1202 +
1203 + foreach ( $products as $product_id ) {
1204 + $product_attr = wp_get_post_terms( $product_id, $attribute );
1205 +
1206 + foreach ( $product_attr as $attr ) {
1207 + $attr_terms[] = $attr;
1208 + }
1209 + }
1210 + self::$cache[ $cache_key ] = self::filter_products_array_unique( $attr_terms );
1211 + return self::$cache[ $cache_key ];
1212 + } else {
1213 + self::$cache[ $cache_key ] = get_terms(
1214 + [
1215 + 'taxonomy' => $attribute,
1216 + 'hide_empty' => false,
1217 + ]
1218 + );
1219 + return self::$cache[ $cache_key ];
1220 + }
1221 + }
1222 + /**
1223 + * Remove duplicate values from an array.
1224 + *
1225 + * @param array $array The input array.
1226 + * @param bool $keep_key_assoc Whether to keep the key associations after removing duplicates.
1227 + * @return array The array with duplicates removed.
1228 + */
1229 + public static function filter_products_array_unique( $array, $keep_key_assoc = false ) {
1230 + $duplicate_keys = [];
1231 + $tmp = [];
1232 +
1233 + foreach ( $array as $key => $val ) {
1234 + // convert objects to arrays, in_array() does not support objects.
1235 + if ( is_object( $val ) ) {
1236 + $val = (array) $val;
1237 + }
1238 +
1239 + if ( ! in_array( $val, $tmp, true ) ) {
1240 + $tmp[] = $val;
1241 + } else {
1242 + $duplicate_keys[] = $key;
1243 + }
1244 + }
1245 +
1246 + foreach ( $duplicate_keys as $key ) {
1247 + unset( $array[ $key ] );
1248 + }
1249 +
1250 + return $keep_key_assoc ? $array : array_values( $array );
1251 + }
1252 + /**
1253 + * Retrieve product categories (including hierarchical support)
1254 + *
1255 + * @param string $taxonomy Taxonomy name.
1256 + * @return int[]|string|string[]|\WP_Error|\WP_Term[]
1257 + */
1258 + public static function get_all_terms( $taxonomy ) {
1259 + $args = [
1260 + 'taxonomy' => $taxonomy,
1261 + 'suppress_filter' => true,
1262 + 'hide_empty' => false,
1263 + 'pad_counts' => true,
1264 + 'hierarchical' => true,
1265 + ];
1266 +
1267 + $cache_key = 'rtsb_get_terms_filter_products' . $taxonomy;
1268 + $taxonomy_terms = wp_cache_get( $cache_key, 'shopbuilder' );
1269 +
1270 + if ( false === $taxonomy_terms ) {
1271 + $queried_object = get_queried_object();
1272 +
1273 + if ( 'archive' === apply_filters( 'rtsb/builder/set/current/page/type', '' ) && $queried_object instanceof WP_Term && $queried_object->taxonomy === $taxonomy ) {
1274 + $term_id = $queried_object->term_id;
1275 + $taxonomy = $queried_object->taxonomy;
1276 + $archive_cache_key = 'rtsb_get_terms_filter_products_' . $taxonomy . $term_id;
1277 + $taxonomy_terms = wp_cache_get( $archive_cache_key, 'shopbuilder' );
1278 + if ( false === $taxonomy_terms ) {
1279 + $taxonomy_terms = [ $queried_object ];
1280 + $child_args = [
1281 + 'taxonomy' => $taxonomy,
1282 + 'child_of' => $term_id,
1283 + 'hide_empty' => false,
1284 + ];
1285 +
1286 + $child_terms = get_terms( $child_args );
1287 +
1288 + if ( ! empty( $child_terms ) ) {
1289 + $taxonomy_terms = array_merge( $taxonomy_terms, $child_terms );
1290 + }
1291 +
1292 + wp_cache_set( $archive_cache_key, $taxonomy_terms, 'shopbuilder' );
1293 + Cache::set_data_cache_key( $archive_cache_key );
1294 + }
1295 + } else {
1296 + $taxonomy_terms = get_terms( $args );
1297 + }
1298 +
1299 + wp_cache_set( $cache_key, $taxonomy_terms, 'shopbuilder' );
1300 + Cache::set_data_cache_key( $cache_key );
1301 + }
1302 +
1303 + return $taxonomy_terms;
1304 + }
1305 + /**
1306 + * Generates an error message block.
1307 + *
1308 + * @param array $title The title array of the error message block.
1309 + * @param string $wrapper Additional CSS class for the wrapper div.
1310 + *
1311 + * @return string The HTML representation of the error message block.
1312 + */
1313 + public static function filter_error_message( $title, $wrapper ) {
1314 + $html = '<div class="rtsb-product-default-filters ' . esc_attr( $wrapper ) . '">';
1315 + $html .= self::get_default_filter_title( $title );
1316 + $html .= '<div class="default-filter-content">';
1317 + $html .= '<p class="no-filter">' . esc_html__( 'Nothing found.', 'shopbuilder' ) . '</p>';
1318 + $html .= '</div>';
1319 + $html .= '</div>';
1320 +
1321 + return $html;
1322 + }
1323 + /**
1324 + * Get filter title.
1325 + *
1326 + * @param array $title Filter title.
1327 + * @return string
1328 + */
1329 + public static function get_default_filter_title( $title ) {
1330 + $html = '';
1331 +
1332 + if ( empty( $title['title'] ) ) {
1333 + return $html;
1334 + }
1335 +
1336 + $html .= '<div class="default-filter-title-wrapper">';
1337 +
1338 + $html .= '<h3 class="widget-title rtsb-d-flex rtsb-align-items-center"><span class="title">' . $title['title'] . '</span></h3>';
1339 +
1340 + $html .= '</div>';
1341 +
1342 + return apply_filters( 'rtsb/elementor/default/filter/title', $html, $title );
1343 + }
1344 + /**
1345 + * Recursive function to generate the filter list with hierarchy.
1346 + *
1347 + * @param array $data Array of required data.
1348 + * @param string $input Type of input field for the filter (e.g., checkbox).
1349 + * @param array $additional_data Data for additional filtering.
1350 + * @param int $parent ID of the parent term (default: 0).
1351 + *
1352 + * @return string The generated HTML for the product filter list.
1353 + */
1354 + public static function get_product_default_filter_list_html( $data, $input = 'checkbox', $additional_data = [], $parent = 0 ) {
1355 +
1356 + $html = '';
1357 + $default_tax = [];
1358 + $is_attribute = ! empty( $data['is_attribute'] );
1359 + $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
1360 + $counter = 0;
1361 +
1362 + if ( $is_attribute ) {
1363 + list(
1364 + 'filter_name' => $filter_name,
1365 + 'base_link' => $base_link
1366 + ) = self::get_product_filters_attribute_term_info( $additional_data['taxonomy'] );
1367 + }
1368 +
1369 + $html .= '<ul class="product-default-filters input-type-' . esc_attr( $input ) . '">';
1370 +
1371 + foreach ( $data['taxonomy'] as $tax ) {
1372 + if ( $tax->parent !== $parent ) {
1373 + continue;
1374 + }
1375 +
1376 + if ( $is_attribute ) {
1377 + $tax_link = remove_query_arg( $filter_name, $base_link );
1378 + $tax_link = add_query_arg( $filter_name, $tax->slug, $tax_link );
1379 + $active_option = isset( $_GET[ $filter_name ] ) ? explode( ',', sanitize_text_field( wp_unslash( $_GET[ $filter_name ] ) ) ) : []; // phpcs:ignore WordPress.Security.NonceVerification.Recommended
1380 + } else {
1381 + $tax_link = get_term_link( $tax );
1382 + }
1383 +
1384 + $unique_id = substr( uniqid(), -4 );
1385 +
1386 + $active_tax = in_array( $tax->slug, $active_option, true ) ? ' checked' : '';
1387 + $active_tax_parent = in_array( $tax->slug, $active_option, true ) ? ' active' : '';
1388 + $term_children = in_array( $tax->taxonomy, [ 'product_cat', 'product_brand' ], true ) ? get_term_children( $tax->term_id, $tax->taxonomy ) : [];
1389 + $taxonomy = $tax->taxonomy;
1390 + $product_count = $tax->count;
1391 +
1392 + // Show count.
1393 + if ( 'archive' === apply_filters( 'rtsb/builder/set/current/page/type', '' ) && ! empty( $data['count_display'] ) && 'block' === $data['count_display'] ) {
1394 + $product_count = self::count_tax_data( $tax, $tax->count );
1395 + }
1396 +
1397 + // Show Empty Categories.
1398 + if ( empty( $data['show_empty_terms'] ) && 0 === $product_count ) {
1399 + continue;
1400 + }
1401 +
1402 + $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' : '' ) . '">
1403 + <div class="rtsb-default-filter-group' . esc_attr( $active_tax_parent ) . '">
1404 + <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 ) . '>
1405 + <label class="rtsb-default-' . esc_attr( $input ) . '-filter-label" for="rtsb-default-term-filter-' . $unique_id . absint( $tax->term_id ) . '">
1406 + <span class="name">' . esc_html( $tax->name ) . '</span>
1407 + </label>
1408 + <div class="rtsb-product-count">(' . esc_html( $product_count ) . ')</div>
1409 + ' . ( ! empty( $term_children ) && $data['show_child'] ? '<i class="rtsb-plus-icon"></i>' : '' ) . '
1410 + </div>';
1411 +
1412 + // Show Sub-categories.
1413 + if ( $data['show_child'] ) {
1414 + $children = self::get_product_default_filter_list_html( $data, $input, $additional_data, $tax->term_id );
1415 +
1416 + if ( ! empty( $children ) ) {
1417 + $html .= '<div class="filter-child">' . $children . '</div>';
1418 + }
1419 + }
1420 +
1421 + $counter++;
1422 +
1423 + $html .= '</li>';
1424 + }
1425 +
1426 + $html .= '</ul>';
1427 +
1428 + // Check if the output contains any child elements.
1429 + $has_children = strpos( $html, '<li class="rtsb-default-filter-term-item' ) !== false;
1430 +
1431 + if ( ! $has_children ) {
1432 + // Remove the outer <ul> if there are no child elements.
1433 + $html = '';
1434 + }
1435 + return $html;
1436 + }
1437 + /**
1438 + * Get attribute term info.
1439 + *
1440 + * @param string $tax Taxonomy type.
1441 + * @return array
1442 + */
1443 + public static function get_product_filters_attribute_term_info( $tax ) {
1444 + $result = [];
1445 + $attributes = wc_get_attribute_taxonomies();
1446 +
1447 + foreach ( $attributes as $attr ) {
1448 + if ( str_replace( 'pa_', '', $tax ) === $attr->attribute_name ) {
1449 + $term_type = $attr->attribute_type;
1450 + $attribute_slug = $attr->attribute_name;
1451 + $attribute = wc_attribute_taxonomy_name( $attr->attribute_name );
1452 + break;
1453 + }
1454 + }
1455 +
1456 + $filter_name = 'filter_' . wc_attribute_taxonomy_slug( $attribute_slug );
1457 +
1458 + $result['attribute'] = $attribute ?? '';
1459 + $result['term_type'] = $term_type ?? '';
1460 + $result['attribute_slug'] = $attribute_slug ?? '';
1461 + $result['filter_name'] = $filter_name;
1462 + $result['base_link'] = self::get_base_url();
1463 +
1464 + return $result;
1465 + }
1466 + /**
1467 + * Get base URL.
1468 + *
1469 + * @return string|null
1470 + */
1471 + public static function get_base_url() {
1472 + global $wp;
1473 + return home_url( add_query_arg( [], $wp->request ) );
1474 + }
1475 + /**
1476 + * Count the number of occurrences for a specific term in a taxonomy for the current queried object.
1477 + *
1478 + * @param object|array $tax The term object for the taxonomy.
1479 + * @param int $count The initial count value.
1480 + *
1481 + * @return int The updated count value.
1482 + */
1483 + public static function count_tax_data( $tax, $count ) {
1484 + $page = get_queried_object();
1485 +
1486 + if ( is_array( $tax ) && strpos( $tax['taxonomy'], 'attribute_' ) !== false ) {
1487 + $taxonomy = str_replace( 'attribute_', '', $tax['taxonomy'] );
1488 + $term_id = $tax['term_id'];
1489 + } else {
1490 + $taxonomy = $tax->taxonomy;
1491 + $term_id = $tax->term_id;
1492 + }
1493 +
1494 + if ( strpos( $page->taxonomy, 'pa_' ) !== false ) {
1495 + $args['status'] = 'publish';
1496 + $args['limit'] = -1;
1497 + $args['return'] = 'ids';
1498 + $args['tax_query'] = [ // phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_tax_query
1499 + 'relation' => 'AND',
1500 + [
1501 + 'taxonomy' => $page->taxonomy,
1502 + 'field' => 'term_id',
1503 + 'terms' => $page->term_id,
1504 + 'operator' => 'IN',
1505 + ],
1506 + [
1507 + 'taxonomy' => $tax->taxonomy,
1508 + 'field' => 'term_id',
1509 + 'terms' => $tax->term_id,
1510 + 'operator' => 'IN',
1511 + ],
1512 + ];
1513 +
1514 + $query = new WC_Product_Query( $args );
1515 + $products = $query->get_products();
1516 +
1517 + return count( $products );
1518 + }
1519 +
1520 + if ( $taxonomy !== $page->taxonomy ) {
1521 + $args = [
1522 + 'limit' => -1,
1523 + 'return' => 'ids',
1524 + 'status' => 'publish',
1525 + 'tax_query' => [ // phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_tax_query
1526 + [
1527 + 'taxonomy' => $taxonomy,
1528 + 'field' => 'term_id',
1529 + 'terms' => $term_id,
1530 + ],
1531 + ],
1532 + ];
1533 +
1534 + if ( 'product_cat' === $page->taxonomy ) {
1535 + $args['category'] = [ $page->slug ];
1536 + }
1537 +
1538 + if ( 'product_tag' === $page->taxonomy ) {
1539 + $args['tag'] = [ $page->slug ];
1540 + }
1541 +
1542 + $query = new WC_Product_Query( $args );
1543 + $products = $query->get_products();
1544 +
1545 + $count = count( $products );
1546 + }
1547 +
1548 + return $count;
1549 + }
1550 + /**
1551 + * Get filter HTML.
1552 + *
1553 + * @param string $filter_type Filter type.
1554 + * @param array $options Options.
1555 + * @param array $additional_data Data for additional filtering.
1556 + * @param string $input Input type.
1557 + *
1558 + * @return string The generated HTML for the attribute filter list.
1559 + */
1560 + public static function get_default_filter_html( $filter_type, $options, $additional_data = [], $input = 'checkbox' ) {
1561 + $html = '<ul class="product-filters input-type-' . esc_attr( $input ) . '" ';
1562 + $active_option = isset( $_GET[ $filter_type ] ) ? explode( ',', wc_clean( wp_unslash( $_GET[ $filter_type ] ) ) ) : []; // phpcs:ignore WordPress.Security.NonceVerification.Recommended, WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
1563 + $option_link = self::get_base_url() . '/' . $filter_type . '/';
1564 +
1565 + foreach ( $options as $option => $option_name ) {
1566 + $unique_id = substr( uniqid(), -6 );
1567 + $active_tax = in_array( $option, $active_option, true ) ? ' checked' : '';
1568 + $active_group = in_array( $option, $active_option, true ) ? ' active' : '';
1569 +
1570 + $html .= '
1571 + <li class="rtsb-term-item">
1572 + <div class="rtsb-default-filter-group' . esc_attr( $active_group ) . '">
1573 + <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 . '>
1574 + <label class="rtsb-default-' . esc_attr( $input ) . '-filter-label" for="rtsb-term-default-filter-' . $unique_id . '">
1575 + <span class="name">' . esc_html( $option_name ) . '</span>
1576 + </label>
1577 + </div>
1578 + </li>';
1579 + }
1580 +
1581 + $html .= '</ul>';
1582 +
1583 + return $html;
1584 + }
1585 + /**
1586 + * Get the count of products with a specific star rating.
1587 + *
1588 + * @param int $star_rating The star rating value.
1589 + *
1590 + * @return int
1591 + */
1592 + public static function get_product_rating_count( $star_rating ) {
1593 + $args = [
1594 + 'status' => 'publish',
1595 + 'limit' => -1,
1596 + 'product_rating' => sprintf( '%.1f', $star_rating ),
1597 + ];
1598 +
1599 + if ( is_product_taxonomy() ) {
1600 + $term = get_queried_object();
1601 + $term_type = 'product_cat' === $term->taxonomy ? 'product_category_id' : 'product_tag_id';
1602 +
1603 + if ( $term instanceof WP_Term ) {
1604 + $args[ $term_type ] = [ $term->term_id ];
1605 + }
1606 + }
1607 +
1608 + $query = new WC_Product_Query( $args );
1609 + $products = $query->get_products();
1610 +
1611 + return count( $products );
1612 + }
1613 + /**
1614 + * Get attribute filter HTML.
1615 + *
1616 + * @param array $data Array of required data.
1617 + * @param string $input Type of input field for the filter (e.g., color).
1618 + *
1619 + * @return string The generated HTML for the attribute filter list.
1620 + */
1621 + public static function get_attribute_filter_list_html( $data, $input = 'color' ) {
1622 + if ( ! function_exists( 'rtwpvs' ) ) {
1623 + return '';
1624 + }
1625 +
1626 + $terms = $data['terms'];
1627 + $term_info = $data['term_info'];
1628 + $show_tooltips = $data['show_tooltips'];
1629 + $show_empty_terms = $data['show_empty_terms'];
1630 + $counter = 0;
1631 +
1632 + $html = '<ul class="product-default-filters rtsb-terms-wrapper ' . esc_attr( $term_info['type'] ) . '-variable-wrapper' . esc_attr( $data['show_label'] ) . '">';
1633 +
1634 + foreach ( $terms as $attr_term ) {
1635 + $count = $attr_term->count;
1636 + $term_link = remove_query_arg( $term_info['filter_name'], $term_info['base_link'] );
1637 + $term_link = add_query_arg( $term_info['filter_name'], $attr_term->slug, $term_link );
1638 + $unique_id = substr( uniqid(), -6 );
1639 + $name = 'term-' . wc_variation_attribute_name( $term_info['attribute'] ) . '-' . $unique_id;
1640 + $selected_class = in_array( $attr_term->slug, $term_info['current_filter'], true ) ? ' selected' : '';
1641 + $selected_item = in_array( $attr_term->slug, $term_info['current_filter'], true ) ? ' checked' : '';
1642 + $active_class = in_array( $attr_term->slug, $term_info['current_filter'], true ) ? ' active' : '';
1643 +
1644 + $args = [
1645 + 'id' => $name,
1646 + 'name' => $attr_term->name,
1647 + 'link' => $term_link,
1648 + 'type' => $term_info['type'],
1649 + 'term_id' => $attr_term->term_id,
1650 + 'term_slug' => $attr_term->slug,
1651 + 'taxonomy' => wc_variation_attribute_name( $term_info['attribute'] ),
1652 + 'tooltips' => $show_tooltips,
1653 + 'attribute_name' => $term_info['attribute'],
1654 + 'selected_item' => $selected_item,
1655 + ];
1656 +
1657 + if ( 'archive' === apply_filters( 'rtsb/builder/set/current/page/type', '' ) && ! empty( $data['count_display'] ) && 'block' === $data['count_display'] ) {
1658 + $count = self::count_tax_data( $args, $attr_term->count );
1659 + }
1660 +
1661 + $args['count'] = $count;
1662 +
1663 + if ( ! $show_empty_terms && 0 === $count ) {
1664 + continue;
1665 + }
1666 +
1667 + $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 ) . '">';
1668 + $html .= '<div class="rtsb-default-filter-group' . esc_attr( $active_class ) . '">';
1669 + $html .= self::get_input_type_html( $input, $args );
1670 +
1671 + $counter++;
1672 +
1673 + $html .= '</div>';
1674 + $html .= '</li>';
1675 + }
1676 +
1677 + $html .= '</ul>';
1678 +
1679 + return $html;
1680 + }
1681 + /**
1682 + * Get input type HTML.
1683 + *
1684 + * @param string $input Input type.
1685 + * @param array $args Args.
1686 + * @return mixed|string|null
1687 + */
1688 + public static function get_input_type_html( $input, $args ) {
1689 + $html = '';
1690 + $count = $args['count'];
1691 +
1692 + switch ( $input ) {
1693 + case 'color':
1694 + $color = sanitize_hex_color( get_term_meta( $args['term_id'], 'product_attribute_color', true ) );
1695 +
1696 + $html .= sprintf(
1697 + // phpcs:ignore Generic.Strings.UnnecessaryStringConcat.Found
1698 + '<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>',
1699 + esc_attr( $args['id'] ),
1700 + esc_attr( $args['type'] ),
1701 + $args['tooltips'] ? esc_attr( ' tipsy' ) : '',
1702 + esc_attr( $color ),
1703 + esc_html( $args['name'] ),
1704 + absint( $count )
1705 + );
1706 + break;
1707 +
1708 + case 'image':
1709 + if ( ! function_exists( 'rtwpvs' ) ) {
1710 + return $html;
1711 + }
1712 +
1713 + $attachment_id = absint( get_term_meta( $args['term_id'], 'product_attribute_image', true ) );
1714 + $image_size = rtwpvs()->get_option( 'attribute_image_size' );
1715 + $image_url = wp_get_attachment_image_url( $attachment_id, apply_filters( 'rtwpvs_product_attribute_image_size', $image_size ) );
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-image-filter rtsb-term-span rtsb-term-span-%s%s"><img class="rtsb-default-attr-filter" alt="%s" src="%s" /></label>',
1720 + esc_attr( $args['id'] ),
1721 + esc_attr( $args['type'] ),
1722 + $args['tooltips'] ? esc_attr( ' tipsy' ) : '',
1723 + esc_attr( $args['name'] ),
1724 + esc_url( $image_url )
1725 + );
1726 + break;
1727 +
1728 + case 'button':
1729 + $html .= sprintf(
1730 + // phpcs:ignore Generic.Strings.UnnecessaryStringConcat.Found
1731 + '<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>',
1732 + esc_attr( $args['id'] ),
1733 + esc_attr( $args['type'] ),
1734 + $args['tooltips'] ? esc_attr( ' tipsy' ) : '',
1735 + esc_html( $args['name'] ),
1736 + absint( $count )
1737 + );
1738 + break;
1739 +
1740 + default:
1741 + }
1742 +
1743 + return apply_filters( 'rtsb/elementor/default/filter/get_input_type_html', $html );
1744 + }
1745 + /**
1746 + * Get reset button.
1747 + *
1748 + * @param string $btn_text Button text.
1749 + * @param array $settings Settings array.
1750 + *
1751 + * @return string
1752 + */
1753 + public static function get_default_filter_reset_button( $btn_text, $settings ) {
1754 + $html = '';
1755 +
1756 + ob_start();
1757 +
1758 + $active = ! empty( $_SERVER['QUERY_STRING'] ) ? ' active' : '';
1759 + $reset = ! empty( $settings['reset_btn'] );
1760 + $apply_text = ! empty( $settings['apply_filters_btn_text'] ) ? $settings['apply_filters_btn_text'] : esc_html__( 'Apply Filters', 'shopbuilder' );
1761 + $apply_icon = ! empty( $settings['apply_filters_btn_icon'] ) ? $settings['apply_filters_btn_icon'] : [];
1762 + echo '<div class="default-filter-btn-wrapper">';
1763 + ?>
1764 + <?php if ( $settings['show_filter_btn'] ) { ?>
1765 + <div class="rtsb-product-default-filters rtsb-apply-filters-btn">
1766 + <div class="reset-btn-item">
1767 + <button class="rtsb-apply-filters init">
1768 + <span class="icon"><?php Fns::print_html( Fns::icons_manager( $apply_icon, 'icon-default' ) ); ?></span>
1769 + <span class="text reset-text"><?php echo esc_html( $apply_text ); ?></span>
1770 + <span></span>
1771 + </button>
1772 + </div>
1773 + </div>
1774 + <?php } ?>
1775 + <?php
1776 + if ( $reset ) {
1777 + ?>
1778 + <div class="rtsb-product-default-filters rtsb-reset<?php echo esc_attr( $active ); ?>">
1779 + <div class="reset-btn-item">
1780 + <button class="product-default-filter-reset">
1781 + <span class="text reset-text"><?php echo esc_html( $btn_text ); ?></span>
1782 + <span></span>
1783 + </button>
1784 + </div>
1785 + </div>
1786 + <?php
1787 + }
1788 + echo '</div>';
1789 +
1790 + $html .= ob_get_clean();
1791 +
1792 + return $html;
947 1793 }
948 1794 }