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