PluginProbe
ShopBuilder – WooCommerce Builder For Elementor / 2.0.2
ShopBuilder – WooCommerce Builder For Elementor v2.0.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/Render/Render.php +367 -982 3.4.22.0.2 View file →
@@ -1,9 +1,9 @@
1 1 <?php
2 2 /**
3 3 * Elementor Render Class.
4 4 *
5 - * This class contains render logics & output. It utilizes WC_Products_Query().
5 + * This class contains render logics & output.
6 6 *
7 7 * @package RadiusTheme\SB
8 8 */
9 9
@@ -8,14 +8,9 @@
8 8 */
9 9
10 10 namespace RadiusTheme\SB\Elementor\Render;
11 11
12 -use RadiusTheme\SBPRO\Modules\CatalogMode\CatalogModeFns;
13 -use WC_Query;
14 12 use WP_Query;
15 -use WC_Product;
16 -use Elementor\Utils;
17 -use WC_Product_Query;
18 13 use RadiusTheme\SB\Helpers\Fns;
19 14 use RadiusTheme\SB\Models\QueryArgs;
20 15 use RadiusTheme\SB\Helpers\BuilderFns;
21 16 use RadiusTheme\SB\Traits\SingletonTrait;
@@ -55,15 +50,8 @@
55 50 */
56 51 public $get_settings;
57 52
58 53 /**
59 - * Element attributes.
60 - *
61 - * @var array
62 - */
63 - private $attributes = [];
64 -
65 - /**
66 54 * Get elementor settings.
67 55 *
68 56 * @return array
69 57 */
@@ -78,87 +66,101 @@
78 66 * @param array $settings Settings.
79 67 * @param string $class Class.
80 68 * @param string $template Template name.
81 69 * @param bool $fullwidth Fullwidth check.
82 - * @param bool $ajax Ajax attributes.
83 70 *
84 71 * @return string
85 72 */
86 - public function container( $content, $settings, $class = '', $template = '', $fullwidth = false, $ajax = true ) {
87 - $rand = wp_rand();
88 - $layout_id = 'rtsb-container-' . $rand;
89 - $metas = RenderHelpers::meta_dataset( $settings, $template );
90 - $raw_layout = esc_html( $metas['layout'] );
91 - $layout = RenderHelpers::filter_layout( $raw_layout, $template );
92 - $style_attr = '--rtsb-default-columns: ' . esc_attr( RenderHelpers::default_columns( $layout ) );
93 - $view_mode = $settings['view_mode'] ?? 'grid';
94 - $view_mode = isset( $_GET['displayview'] ) ? sanitize_text_field( wp_unslash( $_GET['displayview'] ) ) : $view_mode; // phpcs:ignore WordPress.Security.NonceVerification.Recommended
95 - $tooltip_attr = 'list' == $view_mode && ! empty( $metas['tooltip_position_list'] ) ? esc_attr( $metas['tooltip_position_list'] ) : $metas['tooltip_position'];
96 - $has_pro = rtsb()->has_pro();
97 - $has_filters = $has_pro && ! empty( $settings['tax_filter'] );
98 - $grid_style = $settings['grid_style'] ?? 'even';
73 + public function container( $content, $settings, $class = '', $template = '', $fullwidth = false ) {
74 + $layout_id = 'rtsb-container-' . absint( wp_rand() );
75 + $container_attr = null;
76 + $cart_txt_class = '';
77 + $container_class = 'rtsb-elementor-container products rtsb-pos-r ' . esc_attr( $class );
78 + $metas = RenderHelpers::meta_dataset( $settings, $template );
99 79
100 - // Set default layout.
101 - if ( ! $has_pro && ! in_array( $layout, array_keys( Fns::free_layouts() ), true ) ) {
80 + $layout = $metas['layout'];
81 + $animation = $metas['hover_animation'];
82 +
83 + $is_cat = preg_match( '/category/', $layout );
84 + $is_carousel = preg_match( '/slider/', $layout );
85 +
86 + if ( ! $is_cat ) {
87 + $cart_txt_class = $metas['show_cart_text'] ? ' has-cart-text' : ' no-cart-text';
88 + }
89 +
90 + if ( $is_carousel ) {
91 + $fullwidth = true;
92 + }
93 +
94 + $badge_class = [
95 + 'position' => $metas['badge_position'],
96 + 'alignment' => $metas['badge_alignment'],
97 + ];
98 +
99 + if ( ! in_array( $layout, array_keys( Fns::free_layouts() ), true ) ) {
102 100 $layout = RenderHelpers::set_default_layout( $layout );
103 101 }
104 102
105 - if ( $has_pro && 'masonry' === $grid_style ) {
106 - $style_attr .= '; --rtsb-masonry-columns: ' . esc_attr( RenderHelpers::default_columns( $layout ) );
107 - $style_attr .= '; --rtsb-masonry-list-columns: ' . esc_attr( RenderHelpers::default_columns( $layout ) );
103 + if ( $is_carousel ) {
104 + $pagination_attr = ! empty( $metas['show_filter'] ) ? RenderHelpers::pagination_data( $settings, $template ) : '';
105 + } elseif ( $is_cat ) {
106 + $pagination_attr = '';
107 + } else {
108 + $pagination_attr = RenderHelpers::pagination_data( $settings, $template );
108 109 }
109 110
110 - // Container classes.
111 - $container_classes = RenderHelpers::prepare_container_classes( $metas, $settings, $class );
111 + if ( ! in_array( 'clear-btn', $metas['visibility'], true ) ) {
112 + $container_class .= ' no-clear-btn';
113 + }
112 114
113 - // Pagination attributes.
114 - $pagination_attributes = RenderHelpers::prepare_pagination_attr( $layout, $has_filters, $template, $settings, $ajax );
115 + $container_class .= ! empty( $metas['pagination'] ) ? ' rtsb-has-pagination' : ' rtsb-no-pagination';
116 + $style_attr = ' style="--rtsb-default-columns: ' . esc_attr( RenderHelpers::default_columns( $layout ) ) . '"';
117 + $tooltip_attr = ' data-tooltip-position="' . esc_attr( $metas['tooltip_position'] ) . '"';
115 118
116 - // Attributes for the container.
117 - $container_attributes = [
118 - 'id' => $layout_id,
119 - 'class' => $container_classes,
120 - 'style' => apply_filters( 'rtsb/product/container/attr', $style_attr, $settings ),
121 - 'data-layout' => $layout,
122 - 'data-tooltip-position' => $tooltip_attr,
123 - ];
119 + $view_mode = $settings['view_mode'] ?? 'grid';
124 120
125 - if ( ! empty( $pagination_attributes ) ) {
126 - $container_attributes['data-rtsb-ajax'] = $pagination_attributes;
121 + if ( isset( $_GET['displayview'] ) ) {
122 + $view_mode = sanitize_text_field( wp_unslash( $_GET['displayview'] ) );
127 123 }
128 124
129 - // Opt-out of the scroll-to-top behaviour on Ajax filter/pagination when
130 - // the "Enable Scroll To Top?" switch is turned off.
131 - if ( isset( $settings['enable_ajax_scroll'] ) && empty( $settings['enable_ajax_scroll'] ) ) {
132 - $container_attributes['data-rtsb-disable-scroll'] = '1';
125 + if ( 'list' == $view_mode && ! empty( $metas['tooltip_position_list'] ) ) {
126 + $tooltip_attr = ' data-tooltip-position="' . esc_attr( $metas['tooltip_position_list'] ) . '"';
133 127 }
134 128
135 - // Adding render attributes.
136 - $this->add_attribute( 'rtsb_container_attr_' . $rand, $container_attributes );
129 + $container_attr .= ' data-layout="' . esc_attr( $layout ) . '"' . $style_attr . $tooltip_attr . $pagination_attr;
130 + $container_class .= ' 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'] );
137 131
138 - // Start rendering.
139 - $this->html = '<div ' . $this->get_attribute_string( 'rtsb_container_attr_' . $rand ) . '>';
132 + if ( $metas['show_overlay'] ) {
133 + $container_class .= ' has-overlay';
134 + }
140 135
141 - // Section title.
142 - $this->html .= $this->render_section_title( $settings );
136 + if ( in_array( 'single-cat', $metas['visibility'], true ) ) {
137 + $container_class .= ' show-single-cat';
138 + }
143 139
144 - // Content.
140 + $container_class = apply_filters( 'rtsb/product/container/class', $container_class, $settings );
141 + $this->html = '<div class="' . esc_attr( $container_class ) . '" id="' . esc_attr( $layout_id ) . '" ' . $container_attr . '>';
142 +
143 + if ( ! empty( $settings['query_products'] ) && count( $settings['query_products'] ) && 'yes' === $settings['show_section_title'] ) {
144 + $this->html .= '<div class="rtsb-section-title-wrapper">';
145 + $this->html .= '<' . esc_attr( $settings['section_title_tag'] ) . ' class="rtsb-section-title" >';
146 + $this->html .= esc_html( $settings['section_title_text'] );
147 + $this->html .= '</' . esc_attr( $settings['section_title_tag'] ) . '>';
148 + $this->html .= '</div>';
149 + }
150 +
145 151 $this->html .= $content;
146 152
147 - // End rendering.
148 153 $this->html .= '</div><!-- .rtsb-elementor-container -->';
149 154
150 155 // Action button icon reset.
151 156 $this->action_button_icon_set_default();
152 157
153 - // Script generator.
154 158 $script_generator = [];
155 159 $script_generator['layout'] = $layout_id;
156 - $script_generator['rand'] = absint( $rand );
157 - $script_generator['isCarousel'] = preg_match( '/slider/', $layout );
158 - $script_generator['isMasonry'] = $has_pro && 'masonry' === $grid_style;
160 + $script_generator['rand'] = absint( wp_rand() );
161 + $script_generator['isCarousel'] = $is_carousel;
159 162
160 - // Register scripts in the wp_footer action.
161 163 add_action(
162 164 'wp_footer',
163 165 static function () use ( $script_generator ) {
164 166 RenderHelpers::register_scripts( $script_generator );
@@ -178,42 +180,39 @@
178 180 *
179 181 * @return string
180 182 */
181 183 public function row( $content, $settings, $hook_html = '', $raw_settings = [] ) {
182 - $raw_layout = esc_html( $settings['layout'] );
183 - $layout = RenderHelpers::filter_layout( $raw_layout );
184 + $masonry_class = null;
185 + $loader_class = ' rtsb-pre-loader';
184 186
185 - $rand = wp_rand();
186 - $is_carousel = preg_match( '/slider/', $raw_layout );
187 + $layout = $settings['layout'];
188 + $grid_type = $settings['grid_type'];
189 + $is_carousel = preg_match( '/slider/', $layout );
187 190
188 - if ( preg_match( '/category/', $raw_layout ) && ( ! empty( $settings['active_cat_slider'] ) ) ) {
189 - $is_carousel = true;
191 + if ( 'even' === $grid_type ) {
192 + $masonry_class = ' rtsb-even';
193 + } elseif ( 'masonry' === $grid_type ) {
194 + $masonry_class = ' rtsb-masonry';
190 195 }
191 196
192 - // Row classes.
193 - $row_classes = RenderHelpers::prepare_row_classes( $settings );
197 + if ( ! rtsb()->has_pro() || $is_carousel ) {
198 + $masonry_class = ' rtsb-even';
199 + }
194 200
195 - // Adding render attributes.
196 - $this->add_attribute( 'rtsb_row_attr_' . $rand, 'class', $row_classes );
201 + $row_start_class = apply_filters( 'rtsb/custom/layout/row/classes', esc_attr( 'rtsb-row rtsb-content-loader element-loading rtsb-' . $layout . $masonry_class . $loader_class ), $settings );
202 + $row_wrapper = '<div data-title="' . esc_html__( 'Loading ...', 'shopbuilder' ) . '" class="' . $row_start_class . '">';
203 + $start_wrapper = apply_filters( 'rtsb/custom/layout/row/start', $row_wrapper, $row_start_class );
204 + if ( ! empty( $settings['show_filter'] ) ) {
205 + $this->html = $hook_html;
206 + $this->html .= $start_wrapper;
207 + } else {
208 + $this->html = $start_wrapper;
209 + }
197 210
198 - // Start rendering.
199 - $row_wrapper = '<div ' . $this->get_attribute_string( 'rtsb_row_attr_' . $rand ) . '>';
200 - $start_wrapper = apply_filters( 'rtsb/elementor/row/start', $row_wrapper, $raw_settings );
201 -
202 - $this->html = ! empty( $settings['show_filter'] ) ? $hook_html . $start_wrapper : $start_wrapper;
203 -
204 211 if ( $is_carousel ) {
205 212 $slider_data = RenderHelpers::slider_data( $settings, $raw_settings );
206 - // Adding slider render attributes.
207 - $this->add_attribute(
208 - 'rtsb_slider_attr_' . $rand,
209 - [
210 - 'class' => 'rtsb-col-grid ' . $slider_data['class'],
211 - 'data-options' => $slider_data['data'],
212 - ]
213 - );
214 213
215 - $this->html .= '<div ' . $this->get_attribute_string( 'rtsb_slider_attr_' . $rand ) . '>';
214 + $this->html .= '<div class="rtsb-col-grid ' . esc_attr( $slider_data['class'] ) . '" ' . $slider_data['data'] . '>';
216 215 $this->html .= '<div class="swiper-wrapper">';
217 216 }
218 217
219 218 $this->html .= $content;
@@ -220,18 +219,32 @@
220 219
221 220 if ( $is_carousel ) {
222 221 $this->html .= '</div><!-- .swiper-wrapper -->';
223 222
224 - // Slider buttons.
225 - $this->html .= $this->render_slider_buttons( $settings );
223 + $left_icon = $settings['left_arrow_icon'];
224 + $right_icon = $settings['right_arrow_icon'];
225 +
226 + if ( ! empty( $settings['slider_nav'] ) ) {
227 + $this->html .=
228 + '<div class="swiper-nav">
229 + <div class="swiper-arrow swiper-button-next">
230 + ' . Fns::icons_manager( $right_icon ) . '
231 + </div>
232 + <div class="swiper-arrow swiper-button-prev">
233 + ' . Fns::icons_manager( $left_icon ) . '
234 + </div>
235 + </div>';
236 + }
237 +
238 + $this->html .= ! empty( $settings['slider_dot'] ) ? '<div class="swiper-pagination rtsb-pos-s"></div>' : '';
239 +
226 240 $this->html .= '</div><!-- .rtsb-carousel-slider -->';
227 241 }
228 242
229 243 $row_end = '</div><!-- .rtsb-row -->';
230 244
231 - $this->html .= apply_filters( 'rtsb/elementor/row/end', $row_end );
245 + $this->html .= apply_filters( 'rtsb/custom/layout/row/end', $row_end );
232 246
233 - // Preloader.
234 247 $this->html .= RenderHelpers::pre_loader( $layout );
235 248
236 249 return $this->html;
237 250 }
@@ -238,63 +251,8 @@
238 251
239 252 /**
240 253 * Product loop.
241 254 *
242 - * @param object $products Products.
243 - * @param array $settings Settings.
244 - * @param string $template Template.
245 - *
246 - * @return string|null
247 - */
248 - public function product_loop( $products, $settings, $template ) {
249 - $html = null;
250 -
251 - if ( empty( $products ) ) {
252 - return null;
253 - }
254 -
255 - $i = 0;
256 -
257 - global $product;
258 -
259 - $isGlobalProduct = false;
260 -
261 - if ( $product instanceof WC_Product ) {
262 - $isGlobalProduct = $product;
263 - }
264 -
265 - $layout = RenderHelpers::filter_layout( esc_html( $settings['layout'] ), $template );
266 -
267 - foreach ( $products as $_product ) {
268 - $i++;
269 - $GLOBALS['product'] = $_product; // phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedVariableFound -- Global variable is intentionally used to share the current product context with hooks and templates during rendering.
270 - /**
271 - * Before product template render hook.
272 - */
273 - do_action( 'rtsb_before_product_template_render' );
274 -
275 - // Loop arg.
276 - $arg = $this->arg_dataset( $settings, $_product, $settings['lazy_load'], $i );
277 -
278 - // Get template.
279 - $html .= Fns::load_template( $template . $layout, $arg, true );
280 -
281 - /**
282 - * After product template render hook.
283 - */
284 - do_action( 'rtsb_after_product_template_render' );
285 -
286 - unset( $GLOBALS['product'] );
287 - }
288 - if ( $isGlobalProduct ) {
289 - $GLOBALS['product'] = $isGlobalProduct; // phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedVariableFound -- Global variable is intentionally used to share the current product context with hooks and templates during rendering.
290 - }
291 - return $html;
292 - }
293 -
294 - /**
295 - * WC Product loop.
296 - *
297 255 * @param object $query The query.
298 256 * @param array $settings Settings.
299 257 * @param string $template Template.
300 258 *
@@ -299,9 +257,9 @@
299 257 * @param string $template Template.
300 258 *
301 259 * @return string|null
302 260 */
303 - public function wc_product_loop( $query, $settings, $template ) {
261 + public function product_loop( $query, $settings, $template ) {
304 262 $html = null;
305 263
306 264 if ( empty( $query ) ) {
307 265 return null;
@@ -306,20 +264,19 @@
306 264 if ( empty( $query ) ) {
307 265 return null;
308 266 }
309 267
310 - $i = 0;
311 - $layout = RenderHelpers::filter_layout( esc_html( $settings['layout'] ), $template );
268 + $i = 0;
312 269
313 270 while ( $query->have_posts() ) {
314 271 $query->the_post();
315 272 $i++;
316 - global $product;
273 +
317 274 // Loop arg.
318 - $arg = $this->arg_dataset( $settings, $product, $settings['lazy_load'], $i );
275 + $arg = $this->arg_dataset( $settings, get_the_ID(), $settings['lazy_load'], $i );
319 276
320 277 // Get template.
321 - $html .= Fns::load_template( $template . $layout, $arg, true );
278 + $html .= Fns::load_template( $template . $settings['layout'], $arg, true );
322 279 }
323 280
324 281 return $html;
325 282 }
@@ -324,9 +281,9 @@
324 281 return $html;
325 282 }
326 283
327 284 /**
328 - * Category loop.
285 + * Product loop.
329 286 *
330 287 * @param object $query The query.
331 288 * @param array $settings Settings.
332 289 * @param string $template Template.
@@ -334,18 +291,13 @@
334 291 *
335 292 * @return string|null
336 293 */
337 294 public function category_loop( $query, $settings, $template, $is_single = false ) {
338 - $html = null;
339 - $category_loop = false;
295 + $html = null;
340 296
341 - if ( 'category-layout3' === $settings['raw_settings']['layout'] || 'category-single-layout2' === $settings['raw_settings']['layout'] ) {
342 - $category_loop = true;
343 - }
344 -
345 297 if ( $is_single ) {
346 298 // Loop arg.
347 - $arg = $this->cat_arg_dataset( $settings, $query, true, false, $category_loop );
299 + $arg = $this->cat_arg_dataset( $settings, $query, true );
348 300
349 301 // Get template.
350 302 $html .= Fns::load_template( $template . $settings['layout'], $arg, true );
351 303 } else {
@@ -350,9 +302,9 @@
350 302 $html .= Fns::load_template( $template . $settings['layout'], $arg, true );
351 303 } else {
352 304 foreach ( $query as $term ) {
353 305 // Loop arg.
354 - $arg = $this->cat_arg_dataset( $settings, $term, false, false, $category_loop );
306 + $arg = $this->cat_arg_dataset( $settings, $term );
355 307
356 308 // Get template.
357 309 $html .= Fns::load_template( $template . $settings['layout'], $arg, true );
358 310 }
@@ -379,56 +331,42 @@
379 331
380 332 // Query Args.
381 333 $args = ( new QueryArgs() )->buildArgs( $metas, 'product', $is_carousel );
382 334
383 - $temp_args = $args;
384 - $default_args = [
385 - 'visibility' => 'visible',
386 - 'status' => 'publish',
387 - ];
388 - $custom_args = apply_filters( 'rtsb/elementor/args_before_loop', $args, $metas );
389 - $args = wp_parse_args( $custom_args, $default_args );
335 + $temp_args = $args;
336 + $args = apply_filters( 'rtsb/elementor/args_before_loop', $args, $metas );
390 337
391 - /**
392 - * Before Product query hook.
393 - *
394 - * @hooked RadiusTheme\SB\Controllers\Hooks\ActionHooks::modify_wc_query_args 10
395 - */
396 -
397 - do_action( 'rtsb/elements/render/before_query', $settings, $args );
398 338 // Query.
399 - $product_query = new WC_Product_Query( $args );
339 + $product_query = new WP_Query( $args );
400 340
401 - /**
402 - * Product query hook.
403 - */
404 - do_action( 'rtsb/elements/render/product_query', $product_query, $this );
341 + if ( $product_query->have_posts() ) {
342 + // Elementor Render hook before row.
343 + ob_start();
344 + do_action( 'rtsb/elementor/render/before_row', $metas, $settings, $product_query, $temp_args );
345 + $hook_html .= ob_get_clean();
405 346
406 - $products = $pagination ? $product_query->get_products()->products : $product_query->get_products();
407 -
408 - if ( ! empty( $products ) ) {
409 - // Start rendering.
410 - $hook_html .= $this->render_start( $metas, $settings, $temp_args );
411 -
412 347 // Row.
413 - $this->row( $this->product_loop( $products, $metas, $template ), $metas, $hook_html, $settings );
348 + $this->row( $this->product_loop( $product_query, $metas, $template ), $metas, $hook_html, $settings );
414 349
415 350 // Pagination.
416 351 if ( $pagination ) {
417 - $pagination_args = [
418 - 'query' => $product_query,
419 - 'meta' => $metas,
420 - 'limit' => $settings['posts_limit'],
421 - 'per_page' => $settings['pagination_per_page'],
422 - ];
352 + $this->html .= RenderHelpers::render_pagination(
353 + $product_query,
354 + $metas,
355 + $settings['posts_limit'],
356 + $settings['pagination_per_page']
357 + );
358 + }
423 359
424 - $this->html .= $this->render_products_pagination( $pagination_args );
425 - }
360 + // Elementor Render hook before row.
361 + ob_start();
362 + do_action( 'rtsb/elementor/render/after_row', $metas, $settings, $product_query );
363 + $this->html .= ob_get_clean();
426 364
427 - // End rendering.
428 - $this->html .= $this->render_end( $metas, $settings, $products );
429 365 } else {
430 - $this->no_products_msg( $metas );
366 + $content = '<div class="woocommerce-no-products-found"><div class="woocommerce-info">' . esc_html__( 'No products were found matching your selection.', 'shopbuilder-pro' ) . '</div></div>';
367 +
368 + $this->row( $content, $metas );
431 369 }
432 370
433 371 wp_reset_postdata();
434 372
@@ -433,15 +371,8 @@
433 371 wp_reset_postdata();
434 372
435 373 unset( $args['tax_query'] );
436 374
437 - /**
438 - * After Product query hook.
439 - *
440 - * @hooked RadiusTheme\SB\Controllers\Hooks\ActionHooks::reset_wc_query_args 10
441 - */
442 - do_action( 'rtsb/elements/render/after_query', $settings, $args );
443 -
444 375 // Container.
445 376 $this->container( $this->html, $settings, 'rtsb-products-container', $template, $is_carousel );
446 377
447 378 return $this->html;
@@ -446,8 +377,9 @@
446 377
447 378 return $this->html;
448 379 }
449 380
381 +
450 382 /**
451 383 * Render Product View.
452 384 *
453 385 * @param string $template Template name.
@@ -459,29 +391,24 @@
459 391 public function wc_loop_for_product_view( $template, $settings, $widget ) {
460 392 global $wp_query, $post;
461 393
462 394 $this->get_settings = $settings;
463 - $rand = wp_rand();
464 395 $metas = RenderHelpers::meta_dataset( $settings, $template, $widget->get_settings_for_display() );
465 396
466 - $order = strtoupper( $wp_query->query_vars['order'] ?? 'ASC' );
467 - $settings['rtsb_orderby'] = RenderHelpers::escaping_product_orderby( $wp_query->query_vars['orderby'] ?? 'menu_order' );
468 - $settings['rtsb_order'] = in_array( $order, [ 'ASC','DESC' ], true ) ? $order : 'ASC';
397 + $settings['rtsb_order'] = ! empty( $wp_query->query_vars['order'] ) ? $wp_query->query_vars['order'] : 'ASC';
398 + $settings['rtsb_orderby'] = ! empty( $wp_query->query_vars['orderby'] ) ? $wp_query->query_vars['orderby'] : 'menu_order';
469 399
470 400 $pagination = $metas['pagination'];
471 401
472 - $page_type = BuilderFns::builder_type( get_the_ID() );
473 - $is_preview = BuilderFns::is_builder_preview() && array_key_exists( $page_type, BuilderFns::builder_page_types() );
474 - $raw_settings = $widget->get_settings_for_display();
475 - $widget_per_page = ! empty( $raw_settings['posts_per_page'] ) ? absint( $raw_settings['posts_per_page'] ) : 0;
476 - $wc_per_page = wc_get_default_products_per_row() * wc_get_default_product_rows_per_page();
477 - $posts_per_page = $widget_per_page ? $widget_per_page : apply_filters( 'loop_shop_per_page', $wc_per_page ); // phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedHooknameFound -- woocommerce default hooks used.
478 - $restore_query = false;
402 + $page_type = BuilderFns::builder_type( get_the_ID() );
403 + $is_preview = BuilderFns::is_builder_preview() && array_key_exists( $page_type, BuilderFns::builder_page_types() );
404 + $posts_per_page = wc_get_default_products_per_row() * wc_get_default_product_rows_per_page();
405 +
479 406 if ( $is_preview ) {
480 407 $main_query = clone $wp_query;
481 408 $main_post = clone $post;
482 409
483 - $ordering = ( new WC_Query() )->get_catalog_ordering_args();
410 + $ordering = ( new \WC_Query() )->get_catalog_ordering_args();
484 411 $wp_query_args = [
485 412 'post_type' => 'product',
486 413 'posts_per_page' => $posts_per_page,
487 414 ];
@@ -493,112 +420,62 @@
493 420 if ( ! empty( $ordering['order'] ) ) {
494 421 $wp_query_args['order'] = $ordering['order'];
495 422 }
496 423
497 - $wp_query = new WP_Query( $wp_query_args ); // phpcs:ignore WordPress.WP.GlobalVariablesOverride.Prohibited
498 -
424 + $wp_query = new \WP_Query( $wp_query_args ); // phpcs:ignore WordPress.WP.GlobalVariablesOverride.Prohibited
499 425 wc_set_loop_prop( 'total', $wp_query->found_posts );
500 426 wc_set_loop_prop( 'total_pages', $wp_query->max_num_pages );
501 - } elseif ( ! is_admin() && ( is_shop() || is_product_taxonomy() ) && absint( $wp_query->get( 'posts_per_page' ) ) !== $posts_per_page ) {
502 - // Apply widget's posts_per_page to the main query on the live frontend.
503 - $main_query = clone $wp_query;
504 - $main_post = clone $post;
505 -
506 - $query_vars = $wp_query->query_vars;
507 - $query_vars['posts_per_page'] = $posts_per_page;
508 -
509 - $wp_query = new WP_Query( $query_vars ); // phpcs:ignore WordPress.WP.GlobalVariablesOverride.Prohibited
510 -
511 - wc_set_loop_prop( 'total', $wp_query->found_posts );
512 - wc_set_loop_prop( 'total_pages', $wp_query->max_num_pages );
513 -
514 - $restore_query = true;
515 427 }
516 428
517 - if ( rtsb()->has_pro() && ( Fns::product_has_applied_filters( 'shop' ) || Fns::product_has_applied_filters( 'archive' ) || 'rtsb_builder' === get_post_type( get_the_ID() ) ) ) {
518 - $rtsb_active_filters_html = Fns::get_active_filters_html();
519 - $rtsb_wrapper_style = '' !== $rtsb_active_filters_html ? ' style="' . esc_attr( 'display:block;' ) . '"' : '';
520 - echo '<div class="rtsb-active-filters-wrapper"' . $rtsb_wrapper_style . '>'; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- Style value is escaped above.
521 - Fns::print_html( $rtsb_active_filters_html, true );
522 - echo '</div>';
523 - }
524 -
525 429 // column_per_row.
526 430 if ( woocommerce_product_loop() ) {
527 431 if ( wc_get_loop_prop( 'total' ) ) {
432 + if ( Fns::product_has_applied_filters( 'shop' ) || Fns::product_has_applied_filters( 'archive' ) || 'rtsb_builder' === get_post_type( get_the_ID() ) ) {
433 + echo '<div class="rtsb-active-filters-wrapper"></div>';
434 + }
528 435
529 436 // Row.
530 - $this->row( $this->wc_product_loop( $wp_query, $metas, $template ), $metas, '', $settings );
437 + $this->row( $this->product_loop( $wp_query, $metas, $template ), $metas );
531 438 }
532 439
533 440 // Pagination.
534 - $this->html .= '<div class="rtsb-archive-pagination-wrap" data-per-page="' . absint( $posts_per_page ) . '">';
441 + $this->html .= '<div class="rtsb-archive-pagination-wrap">';
535 442
536 443 if ( $pagination ) {
537 - if ( Fns::product_filters_has_ajax( apply_filters( 'rtsb/builder/set/current/page/type', '' ) ) ) {
444 + if ( Fns::product_filters_has_ajax( 'shop' ) || Fns::product_filters_has_ajax( 'archive' ) ) {
538 445 if ( $wp_query->max_num_pages > 1 ) {
539 - $posts_loading_type = ! empty( $metas['posts_loading_type'] ) ? $metas['posts_loading_type'] : 'pagination';
540 -
541 - if ( 'pagination_ajax' === $posts_loading_type ) {
542 - $this->html .= Fns::custom_pagination( $wp_query->max_num_pages, $posts_per_page, true, $metas['visible_range'] ?? null );
543 - } elseif ( 'pagination' === $posts_loading_type ) {
544 - $this->html .= Fns::custom_pagination( $wp_query->max_num_pages, $posts_per_page, false, $metas['visible_range'] ?? null );
545 - } elseif ( 'load_on_scroll' === $posts_loading_type ) {
546 - $this->html .= "<div class='rtsb-infinite-scroll' data-trigger='1' data-paged='2' data-max-page='{$wp_query->max_num_pages}'>
547 - <div class='rtsb-infinite-action'>
548 - <div class='rtsb-loadmore-loading rtsb-ball-clip-rotate'><div></div></div>
549 - </div>
550 - </div>";
551 - } else {
552 - $load_more_text = ! empty( $metas['load_more_text'] ) ? $metas['load_more_text'] : esc_html__( 'Load More', 'shopbuilder' );
553 -
554 - $this->add_attribute(
555 - 'rtsb_load_more_btn_attr_' . $rand,
556 - [
557 - 'data-paged' => '2',
558 - 'data-max-page' => $wp_query->max_num_pages,
559 - ]
560 - );
561 -
562 - $this->html .=
563 - "<div class='rtsb-load-more rtsb-pos-r'>
564 - <button {$this->get_attribute_string( 'rtsb_load_more_btn_attr_' . $rand )}>
565 - <span>" . esc_html( $load_more_text ) . "</span>
566 - </button>
567 - <div class='rtsb-loadmore-loading rtsb-ball-clip-rotate'><div></div></div>
568 - </div>";
569 - }
446 + $this->html .= "
447 + <div class='rtsb-load-more rtsb-pos-r'>
448 + <button data-paged='2' data-max-page='{$wp_query->max_num_pages}'><span>" . esc_html__( 'Load More', 'shopbuilder-pro' ) . "</span></button>
449 + <div class='rtsb-loadmore-loading rtsb-ball-clip-rotate'><div></div></div>
450 + </div>
451 + ";
570 452 }
571 453 } else {
572 - $pagination_args = [
573 - 'query' => $wp_query,
574 - 'meta' => $metas,
575 - 'limit' => wc_get_loop_prop( 'total' ),
576 - 'per_page' => $posts_per_page,
577 - ];
578 -
579 - $this->html .= $this->render_products_pagination( $pagination_args, 'wp' );
454 + $this->html .= RenderHelpers::render_pagination(
455 + $wp_query,
456 + $metas,
457 + wc_get_loop_prop( 'total' ),
458 + $posts_per_page
459 + );
580 460 }
581 461 }
582 462
583 463 $this->html .= '</div>';
584 464 } else {
585 - $this->no_products_msg( $metas );
465 + $content = '<div class="woocommerce-no-products-found"><div class="woocommerce-info">' . esc_html__( 'No products were found matching your selection.', 'shopbuilder-pro' ) . '</div></div>';
466 +
467 + $this->row( $content, $metas );
586 468 }
587 469
588 - if ( $is_preview || ! empty( $restore_query ) ) {
589 - // phpcs:disable
470 + if ( $is_preview ) {
590 471 $wp_query = $main_query;
591 472 $post = $main_post;
592 473
593 474 wp_reset_query();
594 475 wp_reset_postdata();
595 - // phpcs:enable
596 476 }
597 477
598 - // Ensure the container's data-rtsb-ajax uses the same posts_per_page as the initial render.
599 - $settings['pagination_per_page'] = $posts_per_page;
600 -
601 478 // Container.
602 479 $this->container( $this->html, $settings, 'rtsb-products-container', $template );
603 480
604 481 return $this->html;
@@ -604,13 +481,12 @@
604 481 return $this->html;
605 482 }
606 483
607 484 /**
608 - * Loop Setup for Product View.
485 + * Render Product View.
609 486 *
610 487 * @param string $template Template name.
611 488 * @param array $settings Control settings.
612 - * @param object $widget Widget object.
613 489 *
614 490 * @return string
615 491 */
616 492 public function setup_loop_for_product_view( $template, $settings, $widget ) {
@@ -627,17 +503,17 @@
627 503
628 504 setup_postdata( $GLOBALS['post'] =& $post_object ); // phpcs:ignore WordPress.WP.GlobalVariablesOverride.Prohibited, Squiz.PHP.DisallowMultipleAssignments.Found
629 505
630 506 // Loop arg.
631 - $arg = $this->arg_dataset( $metas, $_product );
507 + $arg = $this->arg_dataset( $metas, $_product->get_id() );
632 508 // Get template.
633 509 $html .= Fns::load_template( $template . $settings['layout'], $arg, true );
634 510
635 - $this->row( $html, $metas, '', $settings );
511 + $this->row( $html, $metas );
636 512 }
637 513
638 514 // Container.
639 - $this->container( $this->html, $settings, 'rtsb-products-container', '', false, false );
515 + $this->container( $this->html, $settings, 'rtsb-products-container' );
640 516
641 517 wp_reset_postdata();
642 518
643 519 return $this->html;
@@ -652,13 +528,8 @@
652 528 *
653 529 * @return string
654 530 */
655 531 public function category_view( $template, $settings, $is_single = false ) {
656 - // Reset the shared singleton's html buffer so leftover markup from a
657 - // previously rendered widget (e.g. a products grid that ran earlier
658 - // in the same request) doesn't get folded into the categories
659 - // container by container() below.
660 - $this->html = '';
661 532 $this->get_settings = $settings;
662 533
663 534 $metas = RenderHelpers::meta_dataset( $settings, $template, $this->get_settings_for_display() );
664 535 $taxonomy = $metas['category_source'];
@@ -666,11 +537,8 @@
666 537
667 538 if ( rtsb()->has_pro() && ( ! empty( $metas['tag_term'] ) ) ) {
668 539 $term = $metas['tag_term'];
669 540 }
670 - if ( rtsb()->has_pro() && ( ! empty( $metas['brand_term'] ) ) ) {
671 - $term = $metas['brand_term'];
672 - }
673 541
674 542 // Query.
675 543 if ( $is_single ) {
676 544 if ( empty( $term ) ) {
@@ -684,13 +552,13 @@
684 552
685 553 $taxonomy_query = get_terms( $args );
686 554 }
687 555
688 - if ( ! is_wp_error( $taxonomy_query ) && ! empty( $taxonomy_query ) ) {
556 + if ( ! empty( $taxonomy_query ) ) {
689 557 // Row.
690 558 $this->row( $this->category_loop( $taxonomy_query, $metas, $template, $is_single ), $metas );
691 559 } else {
692 - $this->html = '<p>' . esc_html__( 'No categories found', 'shopbuilder' ) . '</p>';
560 + $this->html .= '<p>' . esc_html__( 'No categories found', 'shopbuilder' ) . '</p>';
693 561 }
694 562
695 563 // Container.
696 564 $this->container( $this->html, $settings, 'rtsb-categories-container', $is_single );
@@ -737,34 +605,8 @@
737 605
738 606 /**
739 607 * Builds an array with meta values.
740 608 *
741 - * @param array $meta Meta values.
742 - * @param object $product Product object.
743 - * @param bool $lazy_load Lazy Load.
744 - * @param int $i Integer.
745 - *
746 - * @return array
747 - */
748 - public function arg_dataset( array $meta, object $product, bool $lazy_load = false, $i = 0 ) {
749 - $post_id = $product->get_id();
750 - $arg = $this->build_product_arg(
751 - [
752 - 'product' => $product,
753 - 'id' => $product->get_id(),
754 - 'type' => $product->get_type(),
755 - 'meta' => $meta,
756 - 'lazy_load' => $lazy_load,
757 - 'i' => $i,
758 - ]
759 - );
760 -
761 - return apply_filters( 'rtsb/elementor/render/arg_dataset', $arg, $post_id, $meta, $lazy_load );
762 - }
763 -
764 - /**
765 - * Builds an array with meta values for WP_Query.
766 - *
767 609 * @param array $meta Meta values.
768 610 * @param int $post_id Post ID.
769 611 * @param bool $lazy_load Lazy Load.
770 612 * @param int $i Integer.
@@ -770,184 +612,19 @@
770 612 * @param int $i Integer.
771 613 *
772 614 * @return array
773 615 */
774 - public function wp_arg_dataset( array $meta, int $post_id, bool $lazy_load = false, $i = 0 ) {
775 - // phpcs:ignore WordPress.PHP.StrictInArray.MissingTrueStrict
616 + public function arg_dataset( array $meta, int $post_id, bool $lazy_load = false, $i = 0 ) {
776 617 if ( ( empty( $meta ) && ! $post_id ) || ! in_array( get_post_type( $post_id ), [ 'product_variation', 'product' ] ) ) {
777 618 return [];
778 619 }
779 620
780 - global $product;
621 + global $post;
781 622
782 - if ( ! $product instanceof WC_Product && $post_id ) {
783 - $product = wc_get_product( $post_id ); // phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedVariableFound -- Global variable is intentionally used to share the current product context with hooks and templates during rendering.
784 - }
623 + $arg = [];
624 + $_product = wc_get_product( $post_id );
625 + $p_type = $_product->get_type();
785 626
786 - $post_id = $product->get_id();
787 - $arg = $this->build_product_arg(
788 - [
789 - 'product' => $product,
790 - 'id' => $post_id,
791 - 'type' => $product->get_type(),
792 - 'meta' => $meta,
793 - 'lazy_load' => $lazy_load,
794 - 'i' => $i,
795 - ]
796 - );
797 -
798 - return apply_filters( 'rtsb/elementor/render/arg_dataset', $arg, $post_id, $meta, $lazy_load );
799 - }
800 -
801 - /**
802 - * Builds an array with meta values.
803 - *
804 - * @param array $meta Meta values.
805 - * @param Object $query Category object.
806 - * @param bool $fullwidth Fullwidth check.
807 - * @param bool $lazy_load Lazy Load.
808 - * @param bool $category_loop Category loop.
809 - *
810 - * @return array
811 - */
812 - public function cat_arg_dataset( $meta, $query = null, $fullwidth = false, $lazy_load = false, $category_loop = false ) {
813 - if ( empty( $meta ) ) {
814 - return [];
815 - }
816 -
817 - $arg = [];
818 -
819 - $products = null;
820 - $arg['class'] = null;
821 - $arg['grid'] = null;
822 - $arg['anchor_class'] = null;
823 - $arg['p_sale'] = null;
824 - $arg['count'] = max( $query->count, 0 );
825 - $arg['count_position'] = $meta['count_position'];
826 - $arg['excerpt_position'] = $meta['cat_excerpt_position'];
827 - $arg['cat_link'] = get_term_link( $query );
828 - $arg['target'] = '_self';
829 - $arg['raw_settings'] = ! empty( $meta['raw_settings'] ) ? $meta['raw_settings'] : [];
830 -
831 - if ( ! empty( $meta['tag_term'] ) ) {
832 - $arg['tag_term'] = $meta['tag_term'];
833 - }
834 -
835 - if ( ! empty( $meta['custom_link']['url'] ) ) {
836 - $arg['cat_link'] = $meta['custom_link']['url'];
837 - $arg['target'] = $meta['custom_link']['is_external'] ? '_blank' : '_self';
838 - }
839 -
840 - $title = $query->name;
841 - $excerpt = $query->description;
842 -
843 - if ( in_array( 'badges', $meta['visibility'], true ) ) {
844 - $arg['p_sale'] = $meta['custom_badge_text'];
845 - }
846 -
847 - $arg['badge_class'] = RenderHelpers::badge_class( $meta['badge_preset'] );
848 -
849 - if ( $arg['count'] >= 0 ) {
850 - $prefix = ! empty( $meta['before_count'] ) ? $meta['before_count'] : '';
851 - $suffix = ! empty( $meta['after_count'] ) ? $meta['after_count'] : '';
852 -
853 - $arg['count'] = $prefix . $arg['count'] . $suffix;
854 - }
855 -
856 - if ( $meta['show_custom_title'] && ! empty( $meta['cat_custom_title'] ) ) {
857 - $title = $meta['cat_custom_title'];
858 - }
859 -
860 - if ( $meta['show_custom_excerpt'] && ! empty( $meta['cat_custom_excerpt'] ) ) {
861 - $excerpt = $meta['cat_custom_excerpt'];
862 - }
863 -
864 - $arg['c_img'] = $meta['c_img'];
865 - $arg['items'] = $meta['visibility'];
866 - $arg['title_tag'] = $meta['title_tag'];
867 - $arg['title_class'] = 'category-title rtsb-text-limit limit-' . $meta['title_limit'] . ( ! $meta['title_link'] ? ' no-link' : '' );
868 - $arg['title'] = Fns::text_truncation( $title, $meta['title_limit_custom'] );
869 - $arg['excerpt_limit'] = $meta['excerpt_limit'];
870 - $arg['excerpt'] = wpautop( Fns::text_truncation( $excerpt, $meta['excerpt_limit_custom'] ) );
871 - $arg['title_link'] = $meta['title_link'];
872 - $arg['image_link'] = $meta['image_link'];
873 - $arg['grid'] .= 'rtsb-col-grid ';
874 -
875 - if ( ! $fullwidth ) {
876 - if ( 'masonry' === $meta['grid_type'] ) {
877 - $arg['class'] .= 'masonry-grid-item ';
878 - } else {
879 - $arg['class'] .= 'even-grid-item ';
880 - }
881 - }
882 -
883 - if ( ! empty( $meta['active_cat_slider'] ) ) {
884 - $arg['class'] .= ' rtsb-slide-item swiper-slide animated rtFadeIn ';
885 - }
886 -
887 - $arg['class'] .= 'rtsb-category-grid';
888 -
889 - ob_start();
890 - do_action( 'rtsb/categories/category_image_override', $meta, $query->term_id );
891 - $override_category_image = ob_get_clean();
892 -
893 - $arg['img_html'] = $meta['c_img'] ? Fns::get_product_image_html(
894 - 'category',
895 - $query->term_id,
896 - $meta['f_img_size'],
897 - $meta['default_img_id'],
898 - $meta['custom_img_size'],
899 - $lazy_load,
900 - false,
901 - false,
902 - $override_category_image
903 - ) : null;
904 -
905 - if ( $meta['show_custom_image'] && ! empty( $meta['custom_image'] ) ) {
906 - $arg['img_html'] = Fns::get_product_image_html(
907 - 'custom',
908 - null,
909 - $meta['f_img_size'],
910 - $meta['custom_image'],
911 - $meta['custom_img_size'],
912 - $lazy_load
913 - );
914 - }
915 -
916 - $arg['excerpt_class'] = 'category-info' . ( 'block' === $meta['count_position'] ? ' block-count' : ' inline-count' ) . ( 'above' === $meta['cat_excerpt_position'] ? ' excerpt-above' : '' ) . ( empty( $arg['excerpt'] ) ? ' no-excerpt' : '' );
917 -
918 - if ( $category_loop ) {
919 - $query_args = [
920 - 'product_category_id' => $query->term_id,
921 - 'limit' => -1,
922 - 'order' => 'DESC',
923 - 'orderby' => 'date',
924 - ];
925 -
926 - $products_query = new WC_Product_Query( $query_args );
927 - $products = $products_query->get_products();
928 - }
929 -
930 - return apply_filters( 'rtsb/elementor/render/cat_arg_dataset', $arg, $meta, $query, $fullwidth, $lazy_load, $products );
931 - }
932 -
933 - /**
934 - * Building product args.
935 - *
936 - * @param array $args Args.
937 - * @return array
938 - */
939 - public function build_product_arg( $args ) {
940 - list(
941 - 'product' => $product,
942 - 'id' => $post_id,
943 - 'type' => $p_type,
944 - 'meta' => $meta,
945 - 'lazy_load' => $lazy_load,
946 - 'i' => $i,
947 - ) = $args;
948 -
949 - $arg = [];
950 627 $arg['class'] = null;
951 628 $arg['grid'] = null;
952 629 $arg['anchor_class'] = null;
953 630 $arg['hover_img_html'] = null;
@@ -952,28 +629,25 @@
952 629 $arg['anchor_class'] = null;
953 630 $arg['hover_img_html'] = null;
954 631 $arg['s_link'] = [];
955 632 $arg['add_to_cart'] = '';
956 - $arg['p_counter'] = absint( $i );
957 633 $arg['p_id'] = $post_id;
958 - $arg['product'] = $product;
959 - $arg['p_link'] = $product->get_permalink();
634 + $arg['p_link'] = get_permalink();
960 635 $arg['p_sale'] = '';
961 - $arg['rating_args'] = [];
962 - $arg['has_attributes'] = $product->is_type( 'variable' ) && $product->get_attributes();
636 + $arg['has_attributes'] = $_product->is_type( 'variable' ) && $_product->get_attributes();
963 637 $arg['raw_settings'] = ! empty( $meta['raw_settings'] ) ? $meta['raw_settings'] : [];
964 638 $cart_icon_html = '';
965 - $layout = $meta['layout'];
966 639
967 - // Building the arg.
640 + $layout = $meta['layout'];
641 +
968 642 $arg['target'] = '_self';
969 643 $arg['f_img'] = $meta['f_img'];
970 644 $arg['items'] = $meta['visibility'];
971 645 $arg['title_tag'] = $meta['title_tag'];
972 646 $arg['title_class'] = 'product-title rtsb-text-limit limit-' . $meta['title_limit'] . ( ! $meta['title_link'] ? ' no-link' : '' );
973 - $arg['title'] = Fns::text_truncation( $product->get_title(), $meta['title_limit_custom'] );
647 + $arg['title'] = Fns::text_truncation( get_the_title(), $meta['title_limit_custom'] );
974 648 $arg['excerpt_limit'] = $meta['excerpt_limit'];
975 - $arg['excerpt'] = wpautop( Fns::text_truncation( do_shortcode( get_post_field( 'post_excerpt', $post_id ) ), $meta['excerpt_limit_custom'] ) );
649 + $arg['excerpt'] = wpautop( Fns::text_truncation( do_shortcode( $post->post_excerpt ), $meta['excerpt_limit_custom'] ) );
976 650 $arg['title_link'] = $meta['title_link'];
977 651 $arg['image_link'] = $meta['image_link'];
978 652 $arg['out_of_stock'] = $meta['out_of_stock_badge_text'];
979 653 $arg['action_btn_preset'] = $meta['btn_preset'];
@@ -985,15 +659,10 @@
985 659 $is_list = preg_match( '/list/', $layout );
986 660 $is_carousel = preg_match( '/slider/', $layout );
987 661
988 662 if ( ! $is_carousel ) {
989 - $arg['grid'] .= 'rtsb-col-grid ';
990 -
991 - if ( 'masonry' === $meta['grid_type'] ) {
992 - $arg['class'] .= 'masonry-grid-item ';
993 - } else {
994 - $arg['class'] .= 'even-grid-item ';
995 - }
663 + $arg['grid'] .= 'rtsb-col-grid ';
664 + $arg['class'] .= ' even-grid-item ';
996 665 } else {
997 666 $arg['grid'] .= 'rtsb-col-grid rtsb-col-full rtsb-slide-item swiper-slide ';
998 667 }
999 668
@@ -1013,21 +682,17 @@
1013 682
1014 683 $arg['class'] .= ' animated rtFadeIn';
1015 684
1016 685 if ( in_array( 'badges', $meta['visibility'], true ) ) {
1017 - $badge_module = ! empty( $meta['enable_badges_module'] );
1018 - $arg['p_sale'] = Fns::is_module_active( 'product_badges' ) && $badge_module ? 'rtsb_yes' : Fns::get_promo_badge(
1019 - $product,
686 + $arg['p_sale'] = Fns::get_sale_badge(
1020 687 $meta['sale_badge_type'],
1021 688 $meta['sale_badge_text'],
1022 - apply_filters( 'rtsb/elementor/render/out_of_stock_badge_text', $meta['out_of_stock_badge_text'] )
689 + $meta['out_of_stock_badge_text']
1023 690 );
1024 691 }
1025 692
1026 693 $arg['badge_class'] = RenderHelpers::badge_class( $meta['badge_preset'] );
1027 694
1028 - $meta['add_to_cart_text'] = apply_filters( 'rtsb/elementor/render/add_to_cart_text', $meta['add_to_cart_text'], $product );
1029 -
1030 695 if ( ! $meta['show_cart_text'] ) {
1031 696 $meta['add_to_cart_text'] = '';
1032 697 $meta['add_to_cart_success_text'] = '';
1033 698 }
@@ -1040,41 +705,23 @@
1040 705 if ( ! empty( $meta['add_to_cart_success_icon'] ) ) {
1041 706 $cart_icon_html .= Fns::icons_manager( $meta['add_to_cart_success_icon'], 'cart-success-icon' );
1042 707 }
1043 708
1044 - $cart_icon = ! empty( $cart_icon_html ) ? '<span class="icon">' . $cart_icon_html . '</span>' : '';
709 + $cart_icon = '<span class="icon">' . $cart_icon_html . '</span>';
1045 710
1046 - if ( $product->is_purchasable() || 'grouped' === $p_type || 'external' === $p_type ) {
1047 - if ( $product->is_in_stock() ) {
711 + if ( $_product->is_purchasable() || 'grouped' === $p_type || 'external' === $p_type ) {
712 + if ( $_product->is_in_stock() ) {
1048 713 $arg['add_to_cart'] = $this->render_add_to_cart_button(
1049 - [
1050 - 'link' => $product->get_permalink(),
1051 - 'id' => $post_id,
1052 - 'type' => $p_type,
1053 - 'text' => $meta['add_to_cart_text'],
1054 - 'success' => $meta['add_to_cart_success_text'],
1055 - 'icon_html' => $cart_icon,
1056 - 'alignment' => $meta['add_to_cart_alignment'],
1057 - 'product' => $product,
1058 - ]
714 + get_permalink(),
715 + $post_id,
716 + $p_type,
717 + $meta['add_to_cart_text'],
718 + $meta['add_to_cart_success_text'],
719 + $cart_icon,
720 + $meta['add_to_cart_alignment']
1059 721 );
1060 722 }
1061 723 }
1062 - if ( Fns::is_catalog_mode() && empty( $arg['add_to_cart'] ) ) {
1063 - if ( ! empty( $meta['add_to_cart_icon'] ) ) {
1064 - $cart_icon_html = Fns::icons_manager( $meta['add_to_cart_icon'], 'cart-icon' );
1065 - }
1066 - $cart_icon = ! empty( $cart_icon_html ) ? '<span class="icon">' . $cart_icon_html . '</span>' : '';
1067 - $arg['add_to_cart'] = CatalogModeFns::render_elementor_widget_catalog_mode_button(
1068 - [
1069 - 'id' => $post_id,
1070 - 'type' => $p_type,
1071 - 'text' => $meta['add_to_cart_text'],
1072 - 'icon_html' => $cart_icon,
1073 - 'alignment' => $meta['add_to_cart_alignment'],
1074 - ]
1075 - );
1076 - }
1077 724 }
1078 725
1079 726 if ( in_array( 'quick_view', $meta['visibility'], true ) ) {
1080 727 add_filter( 'rtsb/module/quick_view/button_params', [ $this, 'button_classes' ] );
@@ -1090,26 +737,8 @@
1090 737 add_filter( 'rtsb/module/wishlist/button_params', [ $this, 'button_classes' ] );
1091 738 add_filter( 'rtsb/module/wishlist/icon_html', [ $this, 'wishlist_icon' ] );
1092 739 }
1093 740
1094 - // Eager-load the above-the-fold product images so the LCP candidate is
1095 - // fetched immediately instead of being lazy-loaded after render-blocking
1096 - // CSS and layout. Defaults to the mobile viewport row count (Lighthouse
1097 - // scores mobile); eagering below-the-fold images would only steal
1098 - // bandwidth from the visible ones. Filterable per layout.
1099 - $eager_count = (int) apply_filters( 'rtsb/loop/eager_image_count', 6, $meta );
1100 -
1101 - // The mobile LCP is often NOT the first card but the top-right one in a
1102 - // 2-column grid, so the first *row* of images gets fetchpriority=high to
1103 - // promote the real LCP candidate ahead of render-blocking CSS. Kept small
1104 - // (default 2 = one mobile row) to avoid competing high-priority requests.
1105 - $high_count = (int) apply_filters( 'rtsb/loop/fetchpriority_high_count', 2, $meta );
1106 - $img_priority = false;
1107 -
1108 - if ( $i <= $eager_count ) {
1109 - $img_priority = $i <= $high_count ? 'high' : 'eager';
1110 - }
1111 -
1112 741 $arg['img_html'] = $meta['f_img'] ? Fns::get_product_image_html(
1113 742 'product',
1114 743 $post_id,
1115 744 $meta['f_img_size'],
@@ -1114,17 +743,13 @@
1114 743 $post_id,
1115 744 $meta['f_img_size'],
1116 745 $meta['default_img_id'],
1117 746 $meta['custom_img_size'],
1118 - $lazy_load,
1119 - false,
1120 - false,
1121 - 0,
1122 - $img_priority
747 + $lazy_load
1123 748 ) : null;
1124 749
1125 - if ( ! ( function_exists( 'rtwpvsp' ) && $product->is_type( 'variable' ) && $product->get_attributes() ) ) {
1126 - $gallery_ids = $product->get_gallery_image_ids();
750 + if ( ! ( function_exists( 'rtwpvsp' ) && $_product->is_type( 'variable' ) && $_product->get_attributes() ) ) {
751 + $gallery_ids = $_product->get_gallery_image_ids();
1127 752
1128 753 if ( $meta['hover_img'] && ! empty( $gallery_ids ) ) {
1129 754 $arg['class'] .= ! $meta['gallery_img'] ? ' rtsb-double-img' : '';
1130 755
@@ -1159,470 +784,230 @@
1159 784 'hover_img_html' => $arg['hover_img_html'],
1160 785 'meta' => $meta,
1161 786 ];
1162 787
1163 - return $arg;
788 + return apply_filters( 'rtsb/elementor/render/arg_dataset', $arg, $post_id, $meta, $lazy_load );
1164 789 }
790 +
1165 791 /**
1166 - * Renders add to cart button.
792 + * Builds an array with meta values.
1167 793 *
1168 - * @param array $args Cart args.
794 + * @param array $meta Meta values.
795 + * @param Object $query Category object.
796 + * @param bool $fullwidth Fullwidth check.
797 + * @param bool $lazy_load Lazy Load.
1169 798 *
1170 - * @return string
799 + * @return array
1171 800 */
1172 - public function render_add_to_cart_button( $args ) {
1173 - list(
1174 - 'link' => $link,
1175 - 'id' => $id,
1176 - 'type' => $type,
1177 - 'text' => $text,
1178 - 'success' => $success,
1179 - 'icon_html' => $icon_html,
1180 - 'alignment' => $alignment,
1181 - 'product' => $product
1182 - ) = $args;
801 + public function cat_arg_dataset( $meta, $query = null, $fullwidth = false, $lazy_load = false ) {
802 + if ( empty( $meta ) ) {
803 + return [];
804 + }
1183 805
1184 - $content = null;
1185 - $rand = wp_rand();
1186 - $ext_link = get_post_meta( $id, '_product_url', true );
1187 - $btn_txt = get_post_meta( $id, '_button_text', true );
806 + $arg = [];
1188 807
1189 - ob_start();
1190 - do_action( 'rtsb/before/cart/button' );
1191 - $content .= ob_get_clean();
808 + $arg['class'] = null;
809 + $arg['grid'] = null;
810 + $arg['anchor_class'] = null;
811 + $arg['p_sale'] = null;
812 + $arg['count'] = max( $query->count, 0 );
813 + $arg['count_position'] = $meta['count_position'];
814 + $arg['excerpt_position'] = $meta['cat_excerpt_position'];
815 + $arg['cat_link'] = get_term_link( $query );
816 + $arg['target'] = '_self';
817 + $arg['raw_settings'] = ! empty( $meta['raw_settings'] ) ? $meta['raw_settings'] : [];
1192 818
1193 - $cart_attr = [
1194 - 'class' => 'rtsb-action-btn ' . $type . '-product tipsy icon-' . $alignment . ' ' . ( empty( $text ) ? 'no-text' : 'has-text' ),
1195 - 'href' => esc_url( $link ),
1196 - 'data-quantity' => '1',
1197 - 'data-product_id' => absint( $id ),
1198 - 'data-id' => absint( $id ),
1199 - ];
1200 -
1201 - if ( empty( $text ) ) {
1202 - $tooltip_mapping = [
1203 - 'simple' => esc_attr__( 'Add to Cart', 'shopbuilder' ),
1204 - 'variable' => esc_attr__( 'Select Options', 'shopbuilder' ),
1205 - 'grouped' => esc_attr__( 'View Products', 'shopbuilder' ),
1206 - 'external' => ! empty( $btn_txt ) ? esc_html( $btn_txt ) : esc_html__( 'Buy Product', 'shopbuilder' ),
1207 - 'rtsb-gift-card' => esc_attr__( 'Select Gift Card', 'shopbuilder' ),
1208 - ];
1209 -
1210 - $cart_attr['title'] = $tooltip_mapping[ $type ];
819 + if ( ! empty( $meta['tag_term'] ) ) {
820 + $arg['tag_term'] = $meta['tag_term'];
1211 821 }
1212 822
1213 - $content .= '<div class="rtsb-wc-add-to-cart-wrap">';
1214 - if ( 'variable' === $type ) {
1215 - $cart_attr['class'] = $cart_attr['class'] . ' rtsb_vs_add_to_cart ';
823 + if ( ! empty( $meta['custom_link']['url'] ) ) {
824 + $arg['cat_link'] = $meta['custom_link']['url'];
825 + $arg['target'] = $meta['custom_link']['is_external'] ? '_blank' : '_self';
1216 826 }
1217 - if ( 'variable' === $type || 'grouped' === $type ) {
1218 - $cart_attr = apply_filters( 'rtsb/elementor/render/cart_attributes', $cart_attr, $product );
1219 827
1220 - $this->add_attribute( 'rtsb_add_to_cart_button_' . $id . $rand, $cart_attr );
828 + $title = $query->name;
829 + $excerpt = $query->description;
1221 830
1222 - $text_btn = apply_filters(
1223 - 'rtsb/elementor/render/add_to_cart_text',
1224 - 'grouped' === $type ? __( 'View Products', 'shopbuilder' ) : __( 'Select Options', 'shopbuilder' ),
1225 - $product,
1226 - $type
1227 - );
831 + if ( in_array( 'badges', $meta['visibility'], true ) ) {
832 + $arg['p_sale'] = $meta['custom_badge_text'];
833 + }
1228 834
1229 - $content .= '<a ' . $this->get_attribute_string( 'rtsb_add_to_cart_button_' . $id . $rand ) . '>';
1230 - $content .= $icon_html;
1231 - $content .= '<span class="button-text text ' . ( ! empty( $success ) ? 'has-success-text' : 'no-success-text' ) . '" data-success="' . esc_html( $success ) . '" data-cart-text="' . ( ! empty( $text ) ? esc_attr( $text ) : $tooltip_mapping['simple'] ) . '" data-variable-text="' . esc_attr( $text_btn ) . '">' . esc_html( $text_btn ) . '</span>';
1232 - } elseif ( 'external' === $type ) {
1233 - if ( ! empty( $ext_link ) ) {
1234 - $cart_attr['target'] = '_blank';
1235 - }
835 + $arg['badge_class'] = RenderHelpers::badge_class( $meta['badge_preset'] );
1236 836
1237 - $cart_attr['href'] = ! empty( $ext_link ) ? esc_url( $ext_link ) : esc_url( $link );
837 + if ( $arg['count'] >= 0 ) {
838 + $prefix = ! empty( $meta['before_count'] ) ? $meta['before_count'] : '';
839 + $suffix = ! empty( $meta['after_count'] ) ? $meta['after_count'] : '';
1238 840
1239 - $this->add_attribute( 'rtsb_add_to_cart_button_' . $id . $rand, $cart_attr );
1240 -
1241 - $content .= '<a ' . $this->get_attribute_string( 'rtsb_add_to_cart_button_' . $id . $rand ) . '>';
1242 - $content .= $icon_html;
1243 - $content .= '<span class="button-text text">' . ( ! empty( $btn_txt ) ? esc_html( $btn_txt ) : esc_html__( 'Buy Product', 'shopbuilder' ) ) . '</span>';
1244 - } else {
1245 - $cart_attr['href'] = $cart_attr['href'] . '?add-to-cart=' . absint( $id );
1246 - $cart_attr['class'] .= ' rtsb-add-to-cart-btn';
1247 - $cart_attr['data-type'] = $type;
1248 - $cart_attr = apply_filters( 'rtsb/elementor/render/cart_attributes', $cart_attr, $product );
1249 -
1250 - $this->add_attribute( 'rtsb_add_to_cart_button_' . $id . $rand, $cart_attr );
1251 -
1252 - $content .= '<a ' . $this->get_attribute_string( 'rtsb_add_to_cart_button_' . $id . $rand ) . '>';
1253 - $content .= $icon_html;
1254 - $content .= '<span class="button-text text ' . ( ! empty( $success ) ? 'has-success-text' : 'no-success-text' ) . '" data-success="' . esc_html( $success ) . '">' . esc_html( $text ) . '</span>';
841 + $arg['count'] = $prefix . $arg['count'] . $suffix;
1255 842 }
1256 843
1257 - $content .= '</a>';
1258 - $content .= '</div>';
1259 -
1260 - ob_start();
1261 - do_action( 'rtsb/after/cart/button' );
1262 - $content .= ob_get_clean();
1263 -
1264 - return apply_filters( 'rtsb/render/cart/button', $content, $args );
1265 - }
1266 -
1267 - /**
1268 - * Button classes.
1269 - *
1270 - * @param array $params Button params.
1271 - *
1272 - * @return array
1273 - */
1274 - public function button_classes( $params ) {
1275 - $params['classes'] = array_merge( $params['classes'], [ 'rtsb-action-btn', 'tipsy' ] );
1276 -
1277 - return $params;
1278 - }
1279 -
1280 - /**
1281 - * Render the section title.
1282 - *
1283 - * @param array $settings The Elementor settings.
1284 - *
1285 - * @return string
1286 - */
1287 - public function render_section_title( $settings ) {
1288 - $html = '';
1289 - $rand = wp_rand();
1290 -
1291 - if ( empty( $settings['show_section_title'] ) || ( empty( $settings['query_products'] ) && 0 === count( $settings['query_products'] ) ) ) {
1292 - return $html;
844 + if ( $meta['show_custom_title'] && ! empty( $meta['cat_custom_title'] ) ) {
845 + $title = $meta['cat_custom_title'];
1293 846 }
1294 847
1295 - // Set attributes for the section title.
1296 - $this->add_attribute( 'rtsb_section_title_wrapper_' . $rand, 'class', 'rtsb-section-title-wrapper' );
1297 - $this->add_attribute( 'rtsb_section_title_' . $rand, 'class', 'rtsb-section-title' );
1298 -
1299 - // Start rendering.
1300 - $html .= '<div ' . $this->get_attribute_string( 'rtsb_section_title_wrapper_' . $rand ) . '>';
1301 - $html .= '<' . esc_attr( $settings['section_title_tag'] ) . ' ' . $this->get_attribute_string( 'rtsb_section_title_' . $rand ) . '>';
1302 - $html .= esc_html( $settings['section_title_text'] );
1303 - $html .= '</' . esc_attr( $settings['section_title_tag'] ) . '>';
1304 - $html .= '</div>';
1305 -
1306 - return $html;
1307 - }
1308 -
1309 - /**
1310 - * Renders products pagination
1311 - *
1312 - * @param array $args Pagination args.
1313 - * @param string $query_type Query type.
1314 - *
1315 - * @return string
1316 - */
1317 - public function render_products_pagination( $args, $query_type = 'wc' ) {
1318 - list(
1319 - 'query' => $query,
1320 - 'meta' => $meta,
1321 - 'limit' => $limit,
1322 - 'per_page' => $per_page
1323 - ) = $args;
1324 -
1325 - $html_utility = null;
1326 - $html = null;
1327 - $ajax = false;
1328 - $is_grid = preg_match( '/grid-layout/', $meta['layout'] ) || preg_match( '/list-layout/', $meta['layout'] );
1329 - $posts_per_page = 'wp' === $query_type ? $query->query_vars['posts_per_page'] : null;
1330 - $total_page = 'wp' === $query_type ? $query->max_num_pages : $query->get_products()->max_num_pages;
1331 -
1332 - if ( $limit ) {
1333 - if ( 'wc' === $query_type ) {
1334 - $found_post = $query->get_products()->total;
1335 - } elseif ( 'wp' === $query_type && ( empty( $wp_query->query['tax_query'] ) ) ) {
1336 - $found_post = $query->found_posts;
1337 - }
1338 -
1339 - if ( $per_page && $found_post > $per_page ) {
1340 - $found_post = $limit;
1341 - $total_page = ceil( $found_post / $per_page );
1342 - }
848 + if ( $meta['show_custom_excerpt'] && ! empty( $meta['cat_custom_excerpt'] ) ) {
849 + $excerpt = $meta['cat_custom_excerpt'];
1343 850 }
1344 851
1345 - $total_page = absint( $total_page );
852 + $layout = $meta['layout'];
1346 853
1347 - $args = [
1348 - 'total_page' => $total_page,
1349 - 'posts_per_page' => 'wc' === $query_type ? $per_page : $posts_per_page,
1350 - 'ajax' => $ajax,
1351 - ];
854 + $arg['c_img'] = $meta['c_img'];
855 + $arg['items'] = $meta['visibility'];
856 + $arg['title_tag'] = $meta['title_tag'];
857 + $arg['title_class'] = 'category-title rtsb-text-limit limit-' . $meta['title_limit'] . ( ! $meta['title_link'] ? ' no-link' : '' );
858 + $arg['title'] = Fns::text_truncation( $title, $meta['title_limit_custom'] );
859 + $arg['excerpt_limit'] = $meta['excerpt_limit'];
860 + $arg['excerpt'] = wpautop( Fns::text_truncation( $excerpt, $meta['excerpt_limit_custom'] ) );
861 + $arg['title_link'] = $meta['title_link'];
862 + $arg['image_link'] = $meta['image_link'];
1352 863
1353 - if ( 'pagination' === $meta['posts_loading_type'] ) {
1354 - if ( $is_grid ) {
1355 - $html_utility .= Fns::custom_pagination(
1356 - $total_page,
1357 - 'wc' === $query_type ? $per_page : $posts_per_page,
1358 - false,
1359 - $meta['visible_range'] ?? null
1360 - );
1361 - }
1362 - } elseif ( 'pagination_ajax' === $meta['posts_loading_type'] && ! rtsb()->has_pro() ) {
1363 - // Free version fallback: render non-AJAX number pagination so filter
1364 - // params in the URL are preserved via get_pagenum_link().
1365 - if ( $is_grid ) {
1366 - $html_utility .= Fns::custom_pagination(
1367 - $total_page,
1368 - 'wc' === $query_type ? $per_page : $posts_per_page,
1369 - false,
1370 - $meta['visible_range'] ?? null
1371 - );
1372 - }
864 + if ( ! $fullwidth ) {
865 + $arg['grid'] .= 'rtsb-col-grid ';
866 + $arg['class'] .= ' even-grid-item ';
1373 867 } else {
1374 - ob_start();
1375 - do_action( 'rtsb/elementor/render/pagination', $meta, $query, $args );
1376 - $html_utility .= ob_get_clean();
868 + $arg['grid'] .= 'rtsb-col-grid ';
1377 869 }
1378 870
1379 - if ( $html_utility ) {
1380 - $rand = wp_rand();
871 + $arg['class'] .= 'rtsb-category-grid';
1381 872
1382 - // Adding pagination render attributes.
1383 - $this->add_attribute(
1384 - 'rtsb_pagination_attr_' . $rand,
1385 - [
1386 - 'class' => 'rtsb-pagination-wrap element-loading',
1387 - 'data-total-pages' => $total_page,
1388 - 'data-posts-per-page' => 'wc' === $query_type ? $per_page : $posts_per_page,
1389 - 'data-type' => $meta['posts_loading_type'],
1390 - ]
873 + $arg['img_html'] = $meta['c_img'] ? Fns::get_product_image_html(
874 + 'category',
875 + $query->term_id,
876 + $meta['f_img_size'],
877 + $meta['default_img_id'],
878 + $meta['custom_img_size'],
879 + $lazy_load
880 + ) : null;
881 +
882 + if ( $meta['show_custom_image'] && ! empty( $meta['custom_image'] ) ) {
883 + $arg['img_html'] = Fns::get_product_image_html(
884 + 'custom',
885 + null,
886 + $meta['f_img_size'],
887 + $meta['custom_image'],
888 + $meta['custom_img_size'],
889 + $lazy_load
1391 890 );
1392 -
1393 - // Start rendering.
1394 - $html = '<div ' . $this->get_attribute_string( 'rtsb_pagination_attr_' . $rand ) . '>';
1395 - $html .= $html_utility;
1396 - $html .= '</div><!-- .rtsb-pagination-wrap -->';
1397 891 }
1398 892
1399 - return $html;
1400 - }
893 + $arg['excerpt_class'] = 'category-info' . ( 'block' === $meta['count_position'] ? ' block-count' : ' inline-count' ) . ( 'above' === $meta['cat_excerpt_position'] ? ' excerpt-above' : '' ) . ( empty( $arg['excerpt'] ) ? ' no-excerpt' : '' );
1401 894
1402 - /**
1403 - * Renders slider buttons
1404 - *
1405 - * @param array $settings Settings array.
1406 - *
1407 - * @return string
1408 - */
1409 - public function render_slider_buttons( $settings ) {
1410 - $html = '';
1411 - $left_icon = $settings['left_arrow_icon'];
1412 - $right_icon = $settings['right_arrow_icon'];
1413 -
1414 - if ( ! empty( $settings['slider_nav'] ) ) {
1415 - $html .=
1416 - '<div class="swiper-nav">
1417 - <div class="swiper-arrow swiper-button-next">
1418 - ' . Fns::icons_manager( $right_icon ) . '
1419 - </div>
1420 - <div class="swiper-arrow swiper-button-prev">
1421 - ' . Fns::icons_manager( $left_icon ) . '
1422 - </div>
1423 - </div>';
1424 - }
1425 -
1426 - $html .= ! empty( $settings['slider_dot'] ) ? '<div class="swiper-pagination rtsb-pos-s"></div>' : '';
1427 -
1428 - return $html;
895 + return $arg;
1429 896 }
1430 897
1431 898 /**
1432 - * No products message.
899 + * Renders add to cart button.
1433 900 *
1434 - * @param array $metas Meta data.
901 + * @param string $link Product link.
902 + * @param int $id Product ID.
903 + * @param string $type Product type.
904 + * @param string $text Custom text.
905 + * @param string $success Success text.
906 + * @param string $icon_html Custom icon.
907 + * @param string $alignment Icon alignment.
1435 908 *
1436 - * @return void
1437 - */
1438 - public function no_products_msg( $metas ) {
1439 - $content =
1440 - '<div class="rtsb-notice woocommerce-no-products-found">
1441 - <div class="woocommerce-info">' . esc_html__( 'No products were found matching your selection.', 'shopbuilder' ) . '</div>
1442 - </div>';
1443 -
1444 - $this->row( $content, $metas );
1445 - }
1446 -
1447 - /**
1448 - * Start the rendering.
1449 - *
1450 - * @param array $metas Meta Data.
1451 - * @param array $settings Widget settings.
1452 - * @param array $temp_args Additional temporary arguments for rendering.
1453 - *
1454 909 * @return string
1455 910 */
1456 - public function render_start( $metas, $settings, $temp_args ) {
1457 - ob_start();
911 + public function render_add_to_cart_button( $link, $id, $type, $text, $success, $icon_html, $alignment ) {
912 + $content = null;
913 + $tooltip_attr = '';
914 + $ext_link = get_post_meta( $id, '_product_url', true );
915 + $btn_txt = get_post_meta( $id, '_button_text', true );
1458 916
1459 - /**
1460 - * Before render row hook.
1461 - */
1462 - do_action( 'rtsb/elementor/render/before_row', $metas, $settings, $temp_args, $this );
917 + if ( empty( $text ) ) {
918 + $tooltip_attr = ' title="' . esc_attr__( 'Add to Cart', 'shopbuilder' ) . '"';
1463 919
1464 - return ob_get_clean();
1465 - }
920 + if ( 'variable' === $type ) {
921 + $tooltip_attr = ' title="' . esc_attr__( 'Select Options', 'shopbuilder' ) . '"';
922 + }
1466 923
1467 - /**
1468 - * End the rendering.
1469 - *
1470 - * @param array $metas Meta Data.
1471 - * @param array $settings Widget settings.
1472 - * @param array $products Array of products being rendered.
1473 - *
1474 - * @return string
1475 - */
1476 - public function render_end( $metas, $settings, $products ) {
1477 - ob_start();
1478 -
1479 - /**
1480 - * After render row hook.
1481 - */
1482 - do_action( 'rtsb/elementor/render/after_row', $metas, $settings, $products );
1483 -
1484 - return ob_get_clean();
1485 - }
1486 -
1487 - /**
1488 - * Add render attribute.
1489 - *
1490 - * @param array|string $element The HTML element.
1491 - * @param array|string $key Optional. Attribute key. Default is null.
1492 - * @param array|string $value Optional. Attribute value. Default is null.
1493 - * @param bool $overwrite Optional. Whether to overwrite existing.
1494 - *
1495 - * @return self
1496 - */
1497 - public function add_attribute( $element, $key = null, $value = null, $overwrite = false ) {
1498 - if ( is_array( $element ) ) {
1499 - foreach ( $element as $element_key => $attributes ) {
1500 - $this->add_attribute( $element_key, $attributes, null, $overwrite );
924 + if ( 'grouped' === $type ) {
925 + $tooltip_attr = ' title="' . esc_attr__( 'View Products', 'shopbuilder' ) . '"';
1501 926 }
1502 927
1503 - return $this;
1504 - }
1505 -
1506 - if ( is_array( $key ) ) {
1507 - foreach ( $key as $attribute_key => $attributes ) {
1508 - $this->add_attribute( $element, $attribute_key, $attributes, $overwrite );
928 + if ( 'external' === $type ) {
929 + $tooltip_txt = ! empty( $btn_txt ) ? esc_html( $btn_txt ) : esc_html__( 'Buy Product', 'shopbuilder' );
930 + $tooltip_attr = ' title="' . esc_attr( $tooltip_txt ) . '"';
1509 931 }
1510 -
1511 - return $this;
1512 932 }
1513 933
1514 - if ( empty( $this->attributes[ $element ][ $key ] ) ) {
1515 - $this->attributes[ $element ][ $key ] = [];
1516 - }
934 + ob_start();
935 + do_action( 'rtsb/before/cart/button' );
936 + $content .= ob_get_clean();
1517 937
1518 - settype( $value, 'array' );
1519 -
1520 - if ( $overwrite ) {
1521 - $this->attributes[ $element ][ $key ] = $value;
938 + if ( 'variable' === $type ) {
939 + $content .= sprintf(
940 + '<div class="rtsb-wc-add-to-cart-wrap">
941 + <a href="%1$s" data-quantity="1" class="rtsb-action-btn variable-product tipsy icon-%4$s %5$s" data-product_id="%3$s" rel="nofollow"%6$s>%7$s<span class="text">%2$s</span></a>
942 + </div>',
943 + esc_url( $link ),
944 + esc_html__( 'Select Options', 'shopbuilder' ),
945 + absint( $id ),
946 + esc_attr( $alignment ),
947 + empty( $text ) ? 'no-text' : 'has-text',
948 + $tooltip_attr,
949 + $icon_html,
950 + );
951 + } elseif ( 'grouped' === $type ) {
952 + $content .= sprintf(
953 + '<div class="rtsb-wc-add-to-cart-wrap">
954 + <a href="%1$s" data-quantity="1" class="rtsb-action-btn variable-product tipsy icon-%4$s %5$s" data-product_id="%3$s" rel="nofollow"%6$s>%7$s<span class="text">%2$s</span></a>
955 + </div>',
956 + esc_url( $link ),
957 + esc_html__( 'View Products', 'shopbuilder' ),
958 + absint( $id ),
959 + esc_attr( $alignment ),
960 + empty( $text ) ? 'no-text' : 'has-text',
961 + $tooltip_attr,
962 + $icon_html,
963 + );
964 + } elseif ( 'external' === $type ) {
965 + $content .= sprintf(
966 + '<div class="rtsb-wc-add-to-cart-wrap">
967 + <a href="%1$s" data-quantity="1" class="rtsb-action-btn variable-product tipsy icon-%4$s %5$s" data-product_id="%3$s" rel="nofollow"%6$s %8$s>%7$s<span class="text">%2$s</span></a>
968 + </div>',
969 + ! empty( $ext_link ) ? esc_url( $ext_link ) : esc_url( $link ),
970 + ! empty( $btn_txt ) ? esc_html( $btn_txt ) : esc_html__( 'Buy Product', 'shopbuilder' ),
971 + absint( $id ),
972 + esc_attr( $alignment ),
973 + empty( $text ) ? 'no-text' : 'has-text',
974 + $tooltip_attr,
975 + $icon_html,
976 + ! empty( $ext_link ) ? ' target="_blank"' : ''
977 + );
1522 978 } else {
1523 - $this->attributes[ $element ][ $key ] = array_merge( $this->attributes[ $element ][ $key ], $value );
979 + $content .= sprintf(
980 + '<a href="%1$s?add-to-cart=%2$d" data-quantity="1" class="rtsb-action-btn rtsb-add-to-cart-btn tipsy icon-%6$s %7$s" data-id="%2$d" data-type="%3$s"%8$s>%4$s<span class="text %10$s" data-success="%9$s">%5$s</span><span></span></a>',
981 + esc_url( $link ),
982 + absint( $id ),
983 + esc_attr( $type ),
984 + $icon_html,
985 + esc_html( $text ),
986 + esc_attr( $alignment ),
987 + empty( $text ) ? 'no-text' : 'has-text',
988 + $tooltip_attr,
989 + esc_html( $success ),
990 + ! empty( $success ) ? 'has-success-text' : 'no-success-text',
991 + );
1524 992 }
1525 993
1526 - return $this;
1527 - }
994 + ob_start();
995 + do_action( 'rtsb/after/cart/button' );
996 + $content .= ob_get_clean();
1528 997
1529 - /**
1530 - * Add link render attributes.
1531 - *
1532 - * @param array|string $element The HTML element.
1533 - * @param array $url_control Array of link settings.
1534 - * @param bool $overwrite Optional. Whether to overwrite existing
1535 - * attribute. Default is false, not to overwrite.
1536 - *
1537 - * @return Render
1538 - */
1539 - public function add_link_attributes( $element, array $url_control, $overwrite = false ) {
1540 - $attributes = [];
1541 -
1542 - if ( ! empty( $url_control['url'] ) ) {
1543 - $allowed_protocols = array_merge( wp_allowed_protocols(), [ 'skype', 'viber' ] );
1544 -
1545 - $attributes['href'] = esc_url( $url_control['url'], $allowed_protocols );
1546 - }
1547 -
1548 - if ( ! empty( $url_control['is_external'] ) ) {
1549 - $attributes['target'] = '_blank';
1550 - }
1551 -
1552 - if ( ! empty( $url_control['nofollow'] ) ) {
1553 - $attributes['rel'] = 'nofollow';
1554 - }
1555 -
1556 - if ( ! empty( $url_control['custom_attributes'] ) ) {
1557 - $attributes = array_merge( $attributes, Utils::parse_custom_attributes( $url_control['custom_attributes'] ) );
1558 - }
1559 -
1560 - if ( $attributes ) {
1561 - $this->add_attribute( $element, $attributes, null, $overwrite );
1562 - }
1563 -
1564 - return $this;
998 + return $content;
1565 999 }
1566 1000
1567 1001 /**
1568 - * Get render attribute string.
1002 + * Button classes.
1569 1003 *
1570 - * @param string $element The element.
1004 + * @param array $params Button params.
1571 1005 *
1572 - * @return string
1006 + * @return array
1573 1007 */
1574 - public function get_attribute_string( $element ) {
1575 - if ( empty( $this->attributes[ $element ] ) ) {
1576 - return '';
1577 - }
1008 + public function button_classes( $params ) {
1009 + $params['classes'] = array_merge( $params['classes'], [ 'rtsb-action-btn', 'tipsy' ] );
1578 1010
1579 - if ( class_exists( '\Elementor\Utils' ) ) {
1580 - return Utils::render_html_attributes( $this->attributes[ $element ] );
1581 - }
1582 -
1583 - // Fallback.
1584 - return $this->render_fallback_attributes( $this->attributes[ $element ] );
1585 - }
1586 -
1587 - /**
1588 - * Function to render link attributes.
1589 - *
1590 - * @param string $id Element ID.
1591 - * @param array $control_name Control name.
1592 - * @param string $class_name Class name.
1593 - *
1594 - * @return string
1595 - */
1596 - public function render_link_attributes( $id, $control_name, $class_name = 'logo-img-link' ) {
1597 - $this->add_attribute( $id, 'class', $class_name );
1598 -
1599 - if ( ! empty( $control_name['url'] ) ) {
1600 - $this->add_link_attributes( $id, $control_name );
1601 - } else {
1602 - $this->add_attribute( $id, 'role', 'button' );
1603 - }
1604 -
1605 - return $this->get_attribute_string( $id );
1606 - }
1607 -
1608 - /**
1609 - * Render fallback attributes.
1610 - *
1611 - * @param array $attributes The attributes.
1612 - *
1613 - * @return string
1614 - */
1615 - private function render_fallback_attributes( $attributes ) {
1616 - $rendered_attributes = [];
1617 -
1618 - foreach ( $attributes as $attribute_key => $attribute_values ) {
1619 - if ( is_array( $attribute_values ) ) {
1620 - $attribute_values = implode( ' ', $attribute_values );
1621 - }
1622 -
1623 - $rendered_attributes[] = sprintf( '%1$s="%2$s"', $attribute_key, esc_attr( $attribute_values ) );
1624 - }
1625 -
1626 - return implode( ' ', $rendered_attributes );
1011 + return $params;
1627 1012 }
1628 1013 }