PluginProbe
ShopBuilder – WooCommerce Builder For Elementor / 2.1.13
ShopBuilder – WooCommerce Builder For Elementor v2.1.13
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 +713 -394 2.1.12.1.13 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.
5 + * This class contains render logics & output. It utilizes WC_Products_Query().
6 6 *
7 7 * @package RadiusTheme\SB
8 8 */
9 9
@@ -8,10 +8,13 @@
8 8 */
9 9
10 10 namespace RadiusTheme\SB\Elementor\Render;
11 11
12 +use WC_Query;
12 13 use WP_Query;
13 14 use WC_Product;
15 +use Elementor\Utils;
16 +use WC_Product_Query;
14 17 use RadiusTheme\SB\Helpers\Fns;
15 18 use RadiusTheme\SB\Models\QueryArgs;
16 19 use RadiusTheme\SB\Helpers\BuilderFns;
17 20 use RadiusTheme\SB\Traits\SingletonTrait;
@@ -51,8 +54,15 @@
51 54 */
52 55 public $get_settings;
53 56
54 57 /**
58 + * Element attributes.
59 + *
60 + * @var array
61 + */
62 + private $attributes = [];
63 +
64 + /**
55 65 * Get elementor settings.
56 66 *
57 67 * @return array
58 68 */
@@ -67,140 +77,74 @@
67 77 * @param array $settings Settings.
68 78 * @param string $class Class.
69 79 * @param string $template Template name.
70 80 * @param bool $fullwidth Fullwidth check.
71 - * @param bool $ajax_attr Ajax attributes.
81 + * @param bool $ajax Ajax attributes.
72 82 *
73 83 * @return string
74 84 */
75 - public function container( $content, $settings, $class = '', $template = '', $fullwidth = false, $ajax_attr = true ) {
76 - $layout_id = 'rtsb-container-' . absint( wp_rand() );
77 - $container_attr = null;
78 - $cart_txt_class = '';
79 - $container_class = 'rtsb-elementor-container products rtsb-pos-r ' . esc_attr( $class );
80 - $metas = RenderHelpers::meta_dataset( $settings, $template );
85 + public function container( $content, $settings, $class = '', $template = '', $fullwidth = false, $ajax = true ) {
86 + $rand = wp_rand();
87 + $layout_id = 'rtsb-container-' . $rand;
88 + $metas = RenderHelpers::meta_dataset( $settings, $template );
89 + $raw_layout = esc_html( $metas['layout'] );
90 + $layout = RenderHelpers::filter_layout( $raw_layout, $template );
91 + $style_attr = '--rtsb-default-columns: ' . esc_attr( RenderHelpers::default_columns( $layout ) );
92 + $view_mode = $settings['view_mode'] ?? 'grid';
93 + $view_mode = isset( $_GET['displayview'] ) ? sanitize_text_field( wp_unslash( $_GET['displayview'] ) ) : $view_mode; // phpcs:ignore WordPress.Security.NonceVerification.Recommended
94 + $tooltip_attr = 'list' == $view_mode && ! empty( $metas['tooltip_position_list'] ) ? esc_attr( $metas['tooltip_position_list'] ) : $metas['tooltip_position'];
95 + $has_pro = rtsb()->has_pro();
96 + $has_filters = $has_pro && ! empty( $settings['tax_filter'] );
81 97
82 - $layout = $metas['layout'];
83 - $animation = $metas['hover_animation'];
84 - $animation .= ' gallery-hover-' . ( ! empty( $settings['gallery_hover_animation'] ) ? $settings['gallery_hover_animation'] : 'fade' );
85 -
86 - $is_cat = preg_match( '/category/', $layout );
87 - $is_carousel = preg_match( '/slider/', $layout );
88 -
89 - if ( ! $is_cat ) {
90 - $cart_txt_class = $metas['show_cart_text'] ? ' has-cart-text' : ' no-cart-text';
91 - }
92 -
93 - if ( $is_carousel ) {
94 - $fullwidth = true;
95 - }
96 -
97 - $badge_class = [
98 - 'position' => $metas['badge_position'],
99 - 'alignment' => $metas['badge_alignment'],
100 - ];
101 -
102 - if ( ! rtsb()->has_pro() && ! in_array( $layout, array_keys( Fns::free_layouts() ), true ) ) {
98 + // Set default layout.
99 + if ( ! $has_pro && ! in_array( $layout, array_keys( Fns::free_layouts() ), true ) ) {
103 100 $layout = RenderHelpers::set_default_layout( $layout );
104 101 }
105 102
106 - $has_tab_filters = rtsb()->has_pro() && ! empty( $settings['tax_filter'] );
103 + // Container classes.
104 + $container_classes = RenderHelpers::prepare_container_classes( $metas, $settings, $class );
107 105
108 - if ( $is_carousel ) {
109 - $pagination_attr = $has_tab_filters ? RenderHelpers::pagination_data( $settings, $template ) : '';
110 - } elseif ( $is_cat ) {
111 - $pagination_attr = '';
112 - } else {
113 - $ajax_pagination = ! empty( $settings['show_pagination'] ) && 'pagination' !== $settings['pagination_type'];
114 - $page = Fns::product_filters_has_ajax( 'shop' ) || Fns::product_filters_has_ajax( 'archive' );
115 - $condition = rtsb()->has_pro() && $ajax_attr && ( $ajax_pagination || $has_tab_filters || $page );
116 - $pagination_attr = $condition ? RenderHelpers::pagination_data( $settings, $template ) : '';
117 - }
106 + // Pagination attributes.
107 + $pagination_attributes = RenderHelpers::prepare_pagination_attr( $layout, $has_filters, $template, $settings, $ajax );
118 108
119 - if ( ! in_array( 'clear-btn', $metas['visibility'], true ) ) {
120 - $container_class .= ' no-clear-btn';
121 - }
109 + // Attributes for the container.
110 + $container_attributes = [
111 + 'id' => $layout_id,
112 + 'class' => $container_classes,
113 + 'style' => $style_attr,
114 + 'data-layout' => $layout,
115 + 'data-tooltip-position' => $tooltip_attr,
116 + ];
122 117
123 - $container_class .= ! empty( $metas['pagination'] ) ? ' rtsb-has-pagination' : ' rtsb-no-pagination';
124 - $style_attr = ' style="--rtsb-default-columns: ' . esc_attr( RenderHelpers::default_columns( $layout ) ) . '"';
125 - $tooltip_attr = ' data-tooltip-position="' . esc_attr( $metas['tooltip_position'] ) . '"';
126 -
127 - $view_mode = $settings['view_mode'] ?? 'grid';
128 -
129 - // phpcs:ignore WordPress.Security.NonceVerification.Recommended
130 - if ( isset( $_GET['displayview'] ) ) {
131 - $view_mode = sanitize_text_field( wp_unslash( $_GET['displayview'] ) ); // phpcs:ignore WordPress.Security.NonceVerification.Recommended
118 + if ( ! empty( $pagination_attributes ) ) {
119 + $container_attributes['data-rtsb-ajax'] = $pagination_attributes;
132 120 }
133 121
134 - if ( 'list' == $view_mode && ! empty( $metas['tooltip_position_list'] ) ) {
135 - $tooltip_attr = ' data-tooltip-position="' . esc_attr( $metas['tooltip_position_list'] ) . '"';
136 - }
122 + // Adding render attributes.
123 + $this->add_attribute( 'rtsb_container_attr_' . $rand, $container_attributes );
137 124
138 - $container_attr .= ' data-layout="' . esc_attr( $layout ) . '"' . $style_attr . $tooltip_attr . $pagination_attr;
139 - $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'] );
125 + // Start rendering.
126 + $this->html = '<div ' . $this->get_attribute_string( 'rtsb_container_attr_' . $rand ) . '>';
140 127
141 - if ( $metas['show_overlay'] ) {
142 - $container_class .= ' has-overlay';
143 - }
128 + // Section title.
129 + $this->html .= $this->render_section_title( $settings );
144 130
145 - if ( in_array( 'single-cat', $metas['visibility'], true ) ) {
146 - $container_class .= ' show-single-cat';
147 - }
148 -
149 - if ( ! empty( $settings['show_compare_text'] ) ) {
150 - $container_class .= ' has-compare-text';
151 - }
152 -
153 - if ( ! empty( $settings['show_quick_view_text'] ) ) {
154 - $container_class .= ' has-quick-view-text';
155 - }
156 -
157 - if ( ! empty( $settings['show_wishlist_text'] ) ) {
158 - $container_class .= ' has-wishlist-text';
159 - }
160 -
161 - if ( empty( $settings['show_compare_icon'] ) ) {
162 - $container_class .= ' no-compare-icon';
163 - }
164 -
165 - if ( empty( $settings['show_quick_view_icon'] ) ) {
166 - $container_class .= ' no-quick-view-icon';
167 - }
168 -
169 - if ( empty( $settings['show_wishlist_icon'] ) ) {
170 - $container_class .= ' no-wishlist-icon';
171 - }
172 -
173 - if ( empty( $settings['show_quick_checkout_icon'] ) ) {
174 - $container_class .= ' no-quick_checkout-icon';
175 - }
176 - if ( $is_cat && empty( $settings['show_overlay'] ) ) {
177 - $container_class .= ' no-category-bg-overlay';
178 - }
179 -
180 - $container_class = apply_filters( 'rtsb/product/container/class', $container_class, $settings );
181 - $this->html = '<div class="' . esc_attr( $container_class ) . '" id="' . esc_attr( $layout_id ) . '" ' . $container_attr . '>';
182 -
183 - if ( ! empty( $settings['query_products'] ) && count( $settings['query_products'] ) && 'yes' === $settings['show_section_title'] ) {
184 - $this->html .= '<div class="rtsb-section-title-wrapper">';
185 - $this->html .= '<' . esc_attr( $settings['section_title_tag'] ) . ' class="rtsb-section-title" >';
186 - $this->html .= esc_html( $settings['section_title_text'] );
187 - $this->html .= '</' . esc_attr( $settings['section_title_tag'] ) . '>';
188 - $this->html .= '</div>';
189 - }
190 -
131 + // Content.
191 132 $this->html .= $content;
192 133
134 + // End rendering.
193 135 $this->html .= '</div><!-- .rtsb-elementor-container -->';
194 136
195 137 // Action button icon reset.
196 138 $this->action_button_icon_set_default();
197 139
140 + // Script generator.
198 141 $script_generator = [];
199 142 $script_generator['layout'] = $layout_id;
200 - $script_generator['rand'] = absint( wp_rand() );
201 - $script_generator['isCarousel'] = $is_carousel;
143 + $script_generator['rand'] = absint( $rand );
144 + $script_generator['isCarousel'] = preg_match( '/slider/', $layout );
202 145
146 + // Register scripts in the wp_footer action.
203 147 add_action(
204 148 'wp_footer',
205 149 static function () use ( $script_generator ) {
206 150 RenderHelpers::register_scripts( $script_generator );
@@ -220,39 +164,43 @@
220 164 *
221 165 * @return string
222 166 */
223 167 public function row( $content, $settings, $hook_html = '', $raw_settings = [] ) {
224 - $masonry_class = null;
225 - $loader_class = ' rtsb-pre-loader';
168 + $raw_layout = esc_html( $settings['layout'] );
169 + $layout = RenderHelpers::filter_layout( $raw_layout );
226 170
227 - $layout = $settings['layout'];
228 - $grid_type = $settings['grid_type'];
229 - $is_carousel = preg_match( '/slider/', $layout );
171 + $rand = wp_rand();
172 + $is_carousel = preg_match( '/slider/', $raw_layout );
230 173
231 - if ( 'even' === $grid_type ) {
232 - $masonry_class = ' rtsb-even';
233 - } elseif ( 'masonry' === $grid_type ) {
234 - $masonry_class = ' rtsb-masonry';
174 + if ( preg_match( '/category/', $raw_layout ) && ( ! empty( $settings['active_cat_slider'] ) ) ) {
175 + $is_carousel = true;
235 176 }
236 177
237 - if ( ! rtsb()->has_pro() || $is_carousel ) {
238 - $masonry_class = ' rtsb-even';
239 - }
178 + // Row classes.
179 + $row_classes = RenderHelpers::prepare_row_classes( $settings );
240 180
241 - $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 );
242 - $row_wrapper = '<div data-title="' . esc_html__( 'Loading ...', 'shopbuilder' ) . '" class="' . $row_start_class . '">';
243 - $start_wrapper = apply_filters( 'rtsb/custom/layout/row/start', $row_wrapper, $row_start_class );
244 - if ( ! empty( $settings['show_filter'] ) ) {
245 - $this->html = $hook_html;
246 - $this->html .= $start_wrapper;
247 - } else {
248 - $this->html = $start_wrapper;
249 - }
181 + // Adding render attributes.
182 + $this->add_attribute( 'rtsb_row_attr_' . $rand, 'class', $row_classes );
250 183
184 + // Start rendering.
185 + $row_wrapper = '<div ' . $this->get_attribute_string( 'rtsb_row_attr_' . $rand ) . '>';
186 + $start_wrapper = apply_filters( 'rtsb/elementor/row/start', $row_wrapper, $raw_settings );
187 +
188 + $this->html = ! empty( $settings['show_filter'] ) ? $hook_html . $start_wrapper : $start_wrapper;
189 +
251 190 if ( $is_carousel ) {
252 191 $slider_data = RenderHelpers::slider_data( $settings, $raw_settings );
253 192
254 - $this->html .= '<div class="rtsb-col-grid ' . esc_attr( $slider_data['class'] ) . '" ' . $slider_data['data'] . '>';
193 + // Adding slider render attributes.
194 + $this->add_attribute(
195 + 'rtsb_slider_attr_' . $rand,
196 + [
197 + 'class' => 'rtsb-col-grid ' . $slider_data['class'],
198 + 'data-options' => $slider_data['data'],
199 + ]
200 + );
201 +
202 + $this->html .= '<div ' . $this->get_attribute_string( 'rtsb_slider_attr_' . $rand ) . '>';
255 203 $this->html .= '<div class="swiper-wrapper">';
256 204 }
257 205
258 206 $this->html .= $content;
@@ -259,32 +207,18 @@
259 207
260 208 if ( $is_carousel ) {
261 209 $this->html .= '</div><!-- .swiper-wrapper -->';
262 210
263 - $left_icon = $settings['left_arrow_icon'];
264 - $right_icon = $settings['right_arrow_icon'];
265 -
266 - if ( ! empty( $settings['slider_nav'] ) ) {
267 - $this->html .=
268 - '<div class="swiper-nav">
269 - <div class="swiper-arrow swiper-button-next">
270 - ' . Fns::icons_manager( $right_icon ) . '
271 - </div>
272 - <div class="swiper-arrow swiper-button-prev">
273 - ' . Fns::icons_manager( $left_icon ) . '
274 - </div>
275 - </div>';
276 - }
277 -
278 - $this->html .= ! empty( $settings['slider_dot'] ) ? '<div class="swiper-pagination rtsb-pos-s"></div>' : '';
279 -
211 + // Slider buttons.
212 + $this->html .= $this->render_slider_buttons( $settings );
280 213 $this->html .= '</div><!-- .rtsb-carousel-slider -->';
281 214 }
282 215
283 216 $row_end = '</div><!-- .rtsb-row -->';
284 217
285 - $this->html .= apply_filters( 'rtsb/custom/layout/row/end', $row_end );
218 + $this->html .= apply_filters( 'rtsb/elementor/row/end', $row_end );
286 219
220 + // Preloader.
287 221 $this->html .= RenderHelpers::pre_loader( $layout );
288 222
289 223 return $this->html;
290 224 }
@@ -291,8 +225,53 @@
291 225
292 226 /**
293 227 * Product loop.
294 228 *
229 + * @param object $products Products.
230 + * @param array $settings Settings.
231 + * @param string $template Template.
232 + *
233 + * @return string|null
234 + */
235 + public function product_loop( $products, $settings, $template ) {
236 + $html = null;
237 +
238 + if ( empty( $products ) ) {
239 + return null;
240 + }
241 +
242 + $i = 0;
243 +
244 + foreach ( $products as $product ) {
245 + $i++;
246 + $GLOBALS['product'] = $product;
247 + $layout = RenderHelpers::filter_layout( esc_html( $settings['layout'] ), $template );
248 +
249 + /**
250 + * Before product template render hook.
251 + */
252 + do_action( 'rtsb_before_product_template_render' );
253 +
254 + // Loop arg.
255 + $arg = $this->arg_dataset( $settings, $product, $settings['lazy_load'], $i );
256 +
257 + // Get template.
258 + $html .= Fns::load_template( $template . $layout, $arg, true );
259 +
260 + /**
261 + * After product template render hook.
262 + */
263 + do_action( 'rtsb_after_product_template_render' );
264 +
265 + unset( $GLOBALS['product'] );
266 + }
267 +
268 + return $html;
269 + }
270 +
271 + /**
272 + * WC Product loop.
273 + *
295 274 * @param object $query The query.
296 275 * @param array $settings Settings.
297 276 * @param string $template Template.
298 277 *
@@ -297,9 +276,9 @@
297 276 * @param string $template Template.
298 277 *
299 278 * @return string|null
300 279 */
301 - public function product_loop( $query, $settings, $template ) {
280 + public function wc_product_loop( $query, $settings, $template ) {
302 281 $html = null;
303 282
304 283 if ( empty( $query ) ) {
305 284 return null;
@@ -311,9 +290,9 @@
311 290 $query->the_post();
312 291 $i++;
313 292
314 293 // Loop arg.
315 - $arg = $this->arg_dataset( $settings, get_the_ID(), $settings['lazy_load'], $i );
294 + $arg = $this->arg_dataset( $settings, wc_get_product( get_the_ID() ), $settings['lazy_load'], $i );
316 295
317 296 // Get template.
318 297 $html .= Fns::load_template( $template . $settings['layout'], $arg, true );
319 298 }
@@ -321,9 +300,9 @@
321 300 return $html;
322 301 }
323 302
324 303 /**
325 - * Product loop.
304 + * Category loop.
326 305 *
327 306 * @param object $query The query.
328 307 * @param array $settings Settings.
329 308 * @param string $template Template.
@@ -333,11 +312,13 @@
333 312 */
334 313 public function category_loop( $query, $settings, $template, $is_single = false ) {
335 314 $html = null;
336 315 $category_loop = false;
316 +
337 317 if ( 'category-layout3' === $settings['raw_settings']['layout'] || 'category-single-layout2' === $settings['raw_settings']['layout'] ) {
338 318 $category_loop = true;
339 319 }
320 +
340 321 if ( $is_single ) {
341 322 // Loop arg.
342 323 $arg = $this->cat_arg_dataset( $settings, $query, true, false, $category_loop );
343 324
@@ -374,42 +355,50 @@
374 355
375 356 // Query Args.
376 357 $args = ( new QueryArgs() )->buildArgs( $metas, 'product', $is_carousel );
377 358
378 - $temp_args = $args;
379 - $args = apply_filters( 'rtsb/elementor/args_before_loop', $args, $metas );
359 + $temp_args = $args;
360 + $default_args = [
361 + 'visibility' => 'visible',
362 + 'status' => 'publish',
363 + ];
364 + $custom_args = apply_filters( 'rtsb/elementor/args_before_loop', $args, $metas );
365 + $args = wp_parse_args( $custom_args, $default_args );
380 366
367 + /**
368 + * Before Product query hook.
369 + *
370 + * @hooked RadiusTheme\SB\Controllers\Hooks\ActionHooks::modify_wc_query_args 10
371 + */
372 + do_action( 'rtsb/elements/render/before_query', $settings, $args );
373 +
381 374 // Query.
382 - $product_query = new WP_Query( $args );
375 + $product_query = new WC_Product_Query( $args );
376 + $products = $pagination ? $product_query->get_products()->products : $product_query->get_products();
383 377
384 - if ( $product_query->have_posts() ) {
385 - // Elementor Render hook before row.
386 - ob_start();
387 - do_action( 'rtsb/elementor/render/before_row', $metas, $settings, $product_query, $temp_args );
388 - $hook_html .= ob_get_clean();
378 + if ( ! empty( $products ) ) {
379 + // Start rendering.
380 + $hook_html .= $this->render_start( $metas, $settings, $temp_args );
389 381
390 382 // Row.
391 - $this->row( $this->product_loop( $product_query, $metas, $template ), $metas, $hook_html, $settings );
383 + $this->row( $this->product_loop( $products, $metas, $template ), $metas, $hook_html, $settings );
392 384
393 385 // Pagination.
394 386 if ( $pagination ) {
395 - $this->html .= RenderHelpers::render_pagination(
396 - $product_query,
397 - $metas,
398 - $settings['posts_limit'],
399 - $settings['pagination_per_page']
400 - );
387 + $pagination_args = [
388 + 'query' => $product_query,
389 + 'meta' => $metas,
390 + 'limit' => $settings['posts_limit'],
391 + 'per_page' => $settings['pagination_per_page'],
392 + ];
393 +
394 + $this->html .= $this->render_products_pagination( $pagination_args );
401 395 }
402 396
403 - // Elementor Render hook before row.
404 - ob_start();
405 - do_action( 'rtsb/elementor/render/after_row', $metas, $settings, $product_query );
406 - $this->html .= ob_get_clean();
407 -
397 + // End rendering.
398 + $this->html .= $this->render_end( $metas, $settings, $products );
408 399 } else {
409 - $content = '<div class="woocommerce-no-products-found"><div class="woocommerce-info">' . esc_html__( 'No products were found matching your selection.', 'shopbuilder' ) . '</div></div>';
410 -
411 - $this->row( $content, $metas );
400 + $this->no_products_msg( $metas );
412 401 }
413 402
414 403 wp_reset_postdata();
415 404
@@ -414,8 +403,15 @@
414 403 wp_reset_postdata();
415 404
416 405 unset( $args['tax_query'] );
417 406
407 + /**
408 + * After Product query hook.
409 + *
410 + * @hooked RadiusTheme\SB\Controllers\Hooks\ActionHooks::reset_wc_query_args 10
411 + */
412 + do_action( 'rtsb/elements/render/after_query', $settings, $args );
413 +
418 414 // Container.
419 415 $this->container( $this->html, $settings, 'rtsb-products-container', $template, $is_carousel );
420 416
421 417 return $this->html;
@@ -420,9 +416,8 @@
420 416
421 417 return $this->html;
422 418 }
423 419
424 -
425 420 /**
426 421 * Render Product View.
427 422 *
428 423 * @param string $template Template name.
@@ -434,8 +429,9 @@
434 429 public function wc_loop_for_product_view( $template, $settings, $widget ) {
435 430 global $wp_query, $post;
436 431
437 432 $this->get_settings = $settings;
433 + $rand = wp_rand();
438 434 $metas = RenderHelpers::meta_dataset( $settings, $template, $widget->get_settings_for_display() );
439 435
440 436 $settings['rtsb_order'] = ! empty( $wp_query->query_vars['order'] ) ? $wp_query->query_vars['order'] : 'ASC';
441 437 $settings['rtsb_orderby'] = ! empty( $wp_query->query_vars['orderby'] ) ? $wp_query->query_vars['orderby'] : 'menu_order';
@@ -449,9 +445,9 @@
449 445 if ( $is_preview ) {
450 446 $main_query = clone $wp_query;
451 447 $main_post = clone $post;
452 448
453 - $ordering = ( new \WC_Query() )->get_catalog_ordering_args();
449 + $ordering = ( new WC_Query() )->get_catalog_ordering_args();
454 450 $wp_query_args = [
455 451 'post_type' => 'product',
456 452 'posts_per_page' => $posts_per_page,
457 453 ];
@@ -464,21 +460,23 @@
464 460 $wp_query_args['order'] = $ordering['order'];
465 461 }
466 462
467 463 $wp_query = new WP_Query( $wp_query_args ); // phpcs:ignore WordPress.WP.GlobalVariablesOverride.Prohibited
464 +
468 465 wc_set_loop_prop( 'total', $wp_query->found_posts );
469 466 wc_set_loop_prop( 'total_pages', $wp_query->max_num_pages );
470 467 }
471 468
469 + if ( Fns::product_has_applied_filters( 'shop' ) || Fns::product_has_applied_filters( 'archive' ) || 'rtsb_builder' === get_post_type( get_the_ID() ) ) {
470 + echo '<div class="rtsb-active-filters-wrapper"></div>';
471 + }
472 +
472 473 // column_per_row.
473 474 if ( woocommerce_product_loop() ) {
474 475 if ( wc_get_loop_prop( 'total' ) ) {
475 - if ( Fns::product_has_applied_filters( 'shop' ) || Fns::product_has_applied_filters( 'archive' ) || 'rtsb_builder' === get_post_type( get_the_ID() ) ) {
476 - echo '<div class="rtsb-active-filters-wrapper"></div>';
477 - }
478 476
479 477 // Row.
480 - $this->row( $this->product_loop( $wp_query, $metas, $template ), $metas );
478 + $this->row( $this->wc_product_loop( $wp_query, $metas, $template ), $metas, '', $settings );
481 479 }
482 480
483 481 // Pagination.
484 482 $this->html .= '<div class="rtsb-archive-pagination-wrap">';
@@ -483,40 +481,51 @@
483 481 // Pagination.
484 482 $this->html .= '<div class="rtsb-archive-pagination-wrap">';
485 483
486 484 if ( $pagination ) {
487 - if ( Fns::product_filters_has_ajax( 'shop' ) || Fns::product_filters_has_ajax( 'archive' ) ) {
485 + if ( Fns::product_filters_has_ajax( apply_filters( 'rtsb/builder/set/current/page/type', '' ) ) ) {
488 486 if ( $wp_query->max_num_pages > 1 ) {
489 - $this->html .= "
490 - <div class='rtsb-load-more rtsb-pos-r'>
491 - <button data-paged='2' data-max-page='{$wp_query->max_num_pages}'><span>" . esc_html__( 'Load More', 'shopbuilder' ) . "</span></button>
492 - <div class='rtsb-loadmore-loading rtsb-ball-clip-rotate'><div></div></div>
493 - </div>
494 - ";
487 + $this->add_attribute(
488 + 'rtsb_load_more_btn_attr_' . $rand,
489 + [
490 + 'data-paged' => '2',
491 + 'data-max-page' => $wp_query->max_num_pages,
492 + ]
493 + );
494 +
495 + $this->html .=
496 + "<div class='rtsb-load-more rtsb-pos-r'>
497 + <button {$this->get_attribute_string( 'rtsb_load_more_btn_attr_' . $rand )}>
498 + <span>" . esc_html__( 'Load More', 'shopbuilder' ) . "</span>
499 + </button>
500 + <div class='rtsb-loadmore-loading rtsb-ball-clip-rotate'><div></div></div>
501 + </div>";
495 502 }
496 503 } else {
497 - $this->html .= RenderHelpers::render_pagination(
498 - $wp_query,
499 - $metas,
500 - wc_get_loop_prop( 'total' ),
501 - $posts_per_page
502 - );
504 + $pagination_args = [
505 + 'query' => $wp_query,
506 + 'meta' => $metas,
507 + 'limit' => wc_get_loop_prop( 'total' ),
508 + 'per_page' => $posts_per_page,
509 + ];
510 +
511 + $this->html .= $this->render_products_pagination( $pagination_args, 'wp' );
503 512 }
504 513 }
505 514
506 515 $this->html .= '</div>';
507 516 } else {
508 - $content = '<div class="woocommerce-no-products-found"><div class="woocommerce-info">' . esc_html__( 'No products were found matching your selection.', 'shopbuilder' ) . '</div></div>';
509 -
510 - $this->row( $content, $metas );
517 + $this->no_products_msg( $metas );
511 518 }
512 519
513 520 if ( $is_preview ) {
521 + // phpcs:disable
514 522 $wp_query = $main_query;
515 523 $post = $main_post;
516 524
517 525 wp_reset_query();
518 526 wp_reset_postdata();
527 + // phpcs:enable
519 528 }
520 529
521 530 // Container.
522 531 $this->container( $this->html, $settings, 'rtsb-products-container', $template );
@@ -524,12 +533,13 @@
524 533 return $this->html;
525 534 }
526 535
527 536 /**
528 - * Render Product View.
537 + * Loop Setup for Product View.
529 538 *
530 539 * @param string $template Template name.
531 540 * @param array $settings Control settings.
541 + * @param object $widget Widget object.
532 542 *
533 543 * @return string
534 544 */
535 545 public function setup_loop_for_product_view( $template, $settings, $widget ) {
@@ -546,13 +556,13 @@
546 556
547 557 setup_postdata( $GLOBALS['post'] =& $post_object ); // phpcs:ignore WordPress.WP.GlobalVariablesOverride.Prohibited, Squiz.PHP.DisallowMultipleAssignments.Found
548 558
549 559 // Loop arg.
550 - $arg = $this->arg_dataset( $metas, $_product->get_id() );
560 + $arg = $this->arg_dataset( $metas, $_product );
551 561 // Get template.
552 562 $html .= Fns::load_template( $template . $settings['layout'], $arg, true );
553 563
554 - $this->row( $html, $metas );
564 + $this->row( $html, $metas, '', $settings );
555 565 }
556 566
557 567 // Container.
558 568 $this->container( $this->html, $settings, 'rtsb-products-container', '', false, false );
@@ -648,8 +658,34 @@
648 658
649 659 /**
650 660 * Builds an array with meta values.
651 661 *
662 + * @param array $meta Meta values.
663 + * @param object $product Product object.
664 + * @param bool $lazy_load Lazy Load.
665 + * @param int $i Integer.
666 + *
667 + * @return array
668 + */
669 + public function arg_dataset( array $meta, object $product, bool $lazy_load = false, $i = 0 ) {
670 + $post_id = $product->get_id();
671 + $arg = $this->build_product_arg(
672 + [
673 + 'product' => $product,
674 + 'id' => $product->get_id(),
675 + 'type' => $product->get_type(),
676 + 'meta' => $meta,
677 + 'lazy_load' => $lazy_load,
678 + 'i' => $i,
679 + ]
680 + );
681 +
682 + return apply_filters( 'rtsb/elementor/render/arg_dataset', $arg, $post_id, $meta, $lazy_load );
683 + }
684 +
685 + /**
686 + * Builds an array with meta values for WP_Query.
687 + *
652 688 * @param array $meta Meta values.
653 689 * @param int $post_id Post ID.
654 690 * @param bool $lazy_load Lazy Load.
655 691 * @param int $i Integer.
@@ -655,22 +691,179 @@
655 691 * @param int $i Integer.
656 692 *
657 693 * @return array
658 694 */
659 - public function arg_dataset( array $meta, int $post_id, bool $lazy_load = false, $i = 0 ) {
695 + public function wp_arg_dataset( array $meta, int $post_id, bool $lazy_load = false, $i = 0 ) {
660 696 if ( ( empty( $meta ) && ! $post_id ) || ! in_array( get_post_type( $post_id ), [ 'product_variation', 'product' ] ) ) {
661 697 return [];
662 698 }
663 699
664 - global $post, $product;
700 + global $product;
665 701
666 702 if ( ! $product instanceof WC_Product && $post_id ) {
667 703 $product = wc_get_product( $post_id );
668 704 }
669 705
670 - $arg = [];
671 - $p_type = $product->get_type();
706 + $post_id = $product->get_id();
707 + $arg = $this->build_product_arg(
708 + [
709 + 'product' => $product,
710 + 'id' => $post_id,
711 + 'type' => $product->get_type(),
712 + 'meta' => $meta,
713 + 'lazy_load' => $lazy_load,
714 + 'i' => $i,
715 + ]
716 + );
672 717
718 + return apply_filters( 'rtsb/elementor/render/arg_dataset', $arg, $post_id, $meta, $lazy_load );
719 + }
720 +
721 + /**
722 + * Builds an array with meta values.
723 + *
724 + * @param array $meta Meta values.
725 + * @param Object $query Category object.
726 + * @param bool $fullwidth Fullwidth check.
727 + * @param bool $lazy_load Lazy Load.
728 + * @param bool $category_loop Category loop.
729 + *
730 + * @return array
731 + */
732 + public function cat_arg_dataset( $meta, $query = null, $fullwidth = false, $lazy_load = false, $category_loop = false ) {
733 + if ( empty( $meta ) ) {
734 + return [];
735 + }
736 +
737 + $arg = [];
738 +
739 + $products = null;
740 + $arg['class'] = null;
741 + $arg['grid'] = null;
742 + $arg['anchor_class'] = null;
743 + $arg['p_sale'] = null;
744 + $arg['count'] = max( $query->count, 0 );
745 + $arg['count_position'] = $meta['count_position'];
746 + $arg['excerpt_position'] = $meta['cat_excerpt_position'];
747 + $arg['cat_link'] = get_term_link( $query );
748 + $arg['target'] = '_self';
749 + $arg['raw_settings'] = ! empty( $meta['raw_settings'] ) ? $meta['raw_settings'] : [];
750 +
751 + if ( ! empty( $meta['tag_term'] ) ) {
752 + $arg['tag_term'] = $meta['tag_term'];
753 + }
754 +
755 + if ( ! empty( $meta['custom_link']['url'] ) ) {
756 + $arg['cat_link'] = $meta['custom_link']['url'];
757 + $arg['target'] = $meta['custom_link']['is_external'] ? '_blank' : '_self';
758 + }
759 +
760 + $title = $query->name;
761 + $excerpt = $query->description;
762 +
763 + if ( in_array( 'badges', $meta['visibility'], true ) ) {
764 + $arg['p_sale'] = $meta['custom_badge_text'];
765 + }
766 +
767 + $arg['badge_class'] = RenderHelpers::badge_class( $meta['badge_preset'] );
768 +
769 + if ( $arg['count'] >= 0 ) {
770 + $prefix = ! empty( $meta['before_count'] ) ? $meta['before_count'] : '';
771 + $suffix = ! empty( $meta['after_count'] ) ? $meta['after_count'] : '';
772 +
773 + $arg['count'] = $prefix . $arg['count'] . $suffix;
774 + }
775 +
776 + if ( $meta['show_custom_title'] && ! empty( $meta['cat_custom_title'] ) ) {
777 + $title = $meta['cat_custom_title'];
778 + }
779 +
780 + if ( $meta['show_custom_excerpt'] && ! empty( $meta['cat_custom_excerpt'] ) ) {
781 + $excerpt = $meta['cat_custom_excerpt'];
782 + }
783 +
784 + $arg['c_img'] = $meta['c_img'];
785 + $arg['items'] = $meta['visibility'];
786 + $arg['title_tag'] = $meta['title_tag'];
787 + $arg['title_class'] = 'category-title rtsb-text-limit limit-' . $meta['title_limit'] . ( ! $meta['title_link'] ? ' no-link' : '' );
788 + $arg['title'] = Fns::text_truncation( $title, $meta['title_limit_custom'] );
789 + $arg['excerpt_limit'] = $meta['excerpt_limit'];
790 + $arg['excerpt'] = wpautop( Fns::text_truncation( $excerpt, $meta['excerpt_limit_custom'] ) );
791 + $arg['title_link'] = $meta['title_link'];
792 + $arg['image_link'] = $meta['image_link'];
793 + $arg['grid'] .= 'rtsb-col-grid ';
794 +
795 + if ( ! $fullwidth ) {
796 + $arg['class'] .= ' even-grid-item ';
797 + }
798 +
799 + if ( ! empty( $meta['active_cat_slider'] ) ) {
800 + $arg['class'] .= ' rtsb-slide-item swiper-slide animated rtFadeIn ';
801 + }
802 +
803 + $arg['class'] .= 'rtsb-category-grid';
804 +
805 + ob_start();
806 + do_action( 'rtsb/categories/category_image_override', $meta, $query->term_id );
807 + $override_category_image = ob_get_clean();
808 +
809 + $arg['img_html'] = $meta['c_img'] ? Fns::get_product_image_html(
810 + 'category',
811 + $query->term_id,
812 + $meta['f_img_size'],
813 + $meta['default_img_id'],
814 + $meta['custom_img_size'],
815 + $lazy_load,
816 + false,
817 + false,
818 + $override_category_image
819 + ) : null;
820 +
821 + if ( $meta['show_custom_image'] && ! empty( $meta['custom_image'] ) ) {
822 + $arg['img_html'] = Fns::get_product_image_html(
823 + 'custom',
824 + null,
825 + $meta['f_img_size'],
826 + $meta['custom_image'],
827 + $meta['custom_img_size'],
828 + $lazy_load
829 + );
830 + }
831 +
832 + $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' : '' );
833 +
834 + if ( $category_loop ) {
835 + $query_args = [
836 + 'product_category_id' => $query->term_id,
837 + 'limit' => -1,
838 + 'order' => 'DESC',
839 + 'orderby' => 'date',
840 + ];
841 +
842 + $products_query = new WC_Product_Query( $query_args );
843 + $products = $products_query->get_products();
844 + }
845 +
846 + return apply_filters( 'rtsb/elementor/render/cat_arg_dataset', $arg, $meta, $query, $fullwidth, $lazy_load, $products );
847 + }
848 +
849 + /**
850 + * Building product args.
851 + *
852 + * @param array $args Args.
853 + * @return array
854 + */
855 + public function build_product_arg( $args ) {
856 + list(
857 + 'product' => $product,
858 + 'id' => $post_id,
859 + 'type' => $p_type,
860 + 'meta' => $meta,
861 + 'lazy_load' => $lazy_load,
862 + 'i' => $i,
863 + ) = $args;
864 +
865 + $arg = [];
673 866 $arg['class'] = null;
674 867 $arg['grid'] = null;
675 868 $arg['anchor_class'] = null;
676 869 $arg['hover_img_html'] = null;
@@ -676,25 +869,26 @@
676 869 $arg['hover_img_html'] = null;
677 870 $arg['s_link'] = [];
678 871 $arg['add_to_cart'] = '';
679 872 $arg['p_id'] = $post_id;
680 - $arg['p_link'] = get_permalink();
873 + $arg['product'] = $product;
874 + $arg['p_link'] = $product->get_permalink();
681 875 $arg['p_sale'] = '';
682 876 $arg['rating_args'] = [];
683 877 $arg['has_attributes'] = $product->is_type( 'variable' ) && $product->get_attributes();
684 878 $arg['raw_settings'] = ! empty( $meta['raw_settings'] ) ? $meta['raw_settings'] : [];
685 879 $cart_icon_html = '';
880 + $layout = $meta['layout'];
686 881
687 - $layout = $meta['layout'];
688 -
882 + // Building the arg.
689 883 $arg['target'] = '_self';
690 884 $arg['f_img'] = $meta['f_img'];
691 885 $arg['items'] = $meta['visibility'];
692 886 $arg['title_tag'] = $meta['title_tag'];
693 887 $arg['title_class'] = 'product-title rtsb-text-limit limit-' . $meta['title_limit'] . ( ! $meta['title_link'] ? ' no-link' : '' );
694 - $arg['title'] = Fns::text_truncation( get_the_title(), $meta['title_limit_custom'] );
888 + $arg['title'] = Fns::text_truncation( $product->get_title(), $meta['title_limit_custom'] );
695 889 $arg['excerpt_limit'] = $meta['excerpt_limit'];
696 - $arg['excerpt'] = wpautop( Fns::text_truncation( do_shortcode( $post->post_excerpt ), $meta['excerpt_limit_custom'] ) );
890 + $arg['excerpt'] = wpautop( Fns::text_truncation( do_shortcode( get_post_field( 'post_excerpt', $post_id ) ), $meta['excerpt_limit_custom'] ) );
697 891 $arg['title_link'] = $meta['title_link'];
698 892 $arg['image_link'] = $meta['image_link'];
699 893 $arg['out_of_stock'] = $meta['out_of_stock_badge_text'];
700 894 $arg['action_btn_preset'] = $meta['btn_preset'];
@@ -729,12 +923,14 @@
729 923
730 924 $arg['class'] .= ' animated rtFadeIn';
731 925
732 926 if ( in_array( 'badges', $meta['visibility'], true ) ) {
733 - $arg['p_sale'] = Fns::get_sale_badge(
927 + $badge_module = ! empty( $meta['enable_badges_module'] );
928 + $arg['p_sale'] = Fns::is_module_active( 'product_badges' ) && $badge_module ? 'rtsb_yes' : Fns::get_promo_badge(
929 + $product,
734 930 $meta['sale_badge_type'],
735 931 $meta['sale_badge_text'],
736 - $meta['out_of_stock_badge_text']
932 + apply_filters( 'rtsb/elementor/render/out_of_stock_badge_text', $meta['out_of_stock_badge_text'] )
737 933 );
738 934 }
739 935
740 936 $arg['badge_class'] = RenderHelpers::badge_class( $meta['badge_preset'] );
@@ -752,20 +948,22 @@
752 948 if ( ! empty( $meta['add_to_cart_success_icon'] ) ) {
753 949 $cart_icon_html .= Fns::icons_manager( $meta['add_to_cart_success_icon'], 'cart-success-icon' );
754 950 }
755 951
756 - $cart_icon = '<span class="icon">' . $cart_icon_html . '</span>';
952 + $cart_icon = ! empty( $cart_icon_html ) ? '<span class="icon">' . $cart_icon_html . '</span>' : '';
757 953
758 954 if ( $product->is_purchasable() || 'grouped' === $p_type || 'external' === $p_type ) {
759 955 if ( $product->is_in_stock() ) {
760 956 $arg['add_to_cart'] = $this->render_add_to_cart_button(
761 - get_permalink(),
762 - $post_id,
763 - $p_type,
764 - $meta['add_to_cart_text'],
765 - $meta['add_to_cart_success_text'],
766 - $cart_icon,
767 - $meta['add_to_cart_alignment']
957 + [
958 + 'link' => $product->get_permalink(),
959 + 'id' => $post_id,
960 + 'type' => $p_type,
961 + 'text' => $meta['add_to_cart_text'],
962 + 'success' => $meta['add_to_cart_success_text'],
963 + 'icon_html' => $cart_icon,
964 + 'alignment' => $meta['add_to_cart_alignment'],
965 + ]
768 966 );
769 967 }
770 968 }
771 969 }
@@ -831,243 +1029,364 @@
831 1029 'hover_img_html' => $arg['hover_img_html'],
832 1030 'meta' => $meta,
833 1031 ];
834 1032
835 - return apply_filters( 'rtsb/elementor/render/arg_dataset', $arg, $post_id, $meta, $lazy_load );
1033 + return $arg;
836 1034 }
837 1035
838 1036 /**
839 - * Builds an array with meta values.
1037 + * Renders add to cart button.
840 1038 *
841 - * @param array $meta Meta values.
842 - * @param Object $query Category object.
843 - * @param bool $fullwidth Fullwidth check.
844 - * @param bool $lazy_load Lazy Load.
1039 + * @param array $args Cart args.
845 1040 *
846 - * @return array
1041 + * @return string
847 1042 */
848 - public function cat_arg_dataset( $meta, $query = null, $fullwidth = false, $lazy_load = false, $category_loop = false ) {
849 - if ( empty( $meta ) ) {
850 - return [];
1043 + public function render_add_to_cart_button( $args ) {
1044 + list(
1045 + 'link' => $link,
1046 + 'id' => $id,
1047 + 'type' => $type,
1048 + 'text' => $text,
1049 + 'success' => $success,
1050 + 'icon_html' => $icon_html,
1051 + 'alignment' => $alignment
1052 + ) = $args;
1053 +
1054 + $content = null;
1055 + $rand = wp_rand();
1056 + $ext_link = get_post_meta( $id, '_product_url', true );
1057 + $btn_txt = get_post_meta( $id, '_button_text', true );
1058 +
1059 + ob_start();
1060 + do_action( 'rtsb/before/cart/button' );
1061 + $content .= ob_get_clean();
1062 +
1063 + $cart_attr = [
1064 + 'class' => 'rtsb-action-btn ' . $type . '-product tipsy icon-' . $alignment . ' ' . ( empty( $text ) ? 'no-text' : 'has-text' ),
1065 + 'href' => esc_url( $link ),
1066 + 'rel' => 'nofollow',
1067 + 'data-quantity' => '1',
1068 + 'data-product_id' => absint( $id ),
1069 + 'data-id' => absint( $id ),
1070 + ];
1071 +
1072 + if ( empty( $text ) ) {
1073 + $tooltip_mapping = [
1074 + 'simple' => esc_attr__( 'Add to Cart', 'shopbuilder' ),
1075 + 'variable' => esc_attr__( 'Select Options', 'shopbuilder' ),
1076 + 'grouped' => esc_attr__( 'View Products', 'shopbuilder' ),
1077 + 'external' => ! empty( $btn_txt ) ? esc_html( $btn_txt ) : esc_html__( 'Buy Product', 'shopbuilder' ),
1078 + ];
1079 +
1080 + $cart_attr['title'] = $tooltip_mapping[ $type ];
851 1081 }
852 1082
853 - $arg = [];
1083 + $content .= '<div class="rtsb-wc-add-to-cart-wrap">';
854 1084
855 - $products = null;
856 - $arg['class'] = null;
857 - $arg['grid'] = null;
858 - $arg['anchor_class'] = null;
859 - $arg['p_sale'] = null;
860 - $arg['count'] = max( $query->count, 0 );
861 - $arg['count_position'] = $meta['count_position'];
862 - $arg['excerpt_position'] = $meta['cat_excerpt_position'];
863 - $arg['cat_link'] = get_term_link( $query );
864 - $arg['target'] = '_self';
865 - $arg['raw_settings'] = ! empty( $meta['raw_settings'] ) ? $meta['raw_settings'] : [];
1085 + if ( 'variable' === $type || 'grouped' === $type ) {
1086 + $this->add_attribute( 'rtsb_add_to_cart_button_' . $id . $rand, $cart_attr );
866 1087
867 - if ( ! empty( $meta['tag_term'] ) ) {
868 - $arg['tag_term'] = $meta['tag_term'];
1088 + $text_btn = 'grouped' === $type ? __( 'View Products', 'shopbuilder' ) : __( 'Select Options', 'shopbuilder' );
1089 +
1090 + $content .= '<a ' . $this->get_attribute_string( 'rtsb_add_to_cart_button_' . $id . $rand ) . '>';
1091 + $content .= $icon_html;
1092 + $content .= '<span class="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>';
1093 + $content .= '<span></span>';
1094 + } elseif ( 'external' === $type ) {
1095 + if ( ! empty( $ext_link ) ) {
1096 + $cart_attr['target'] = '_blank';
1097 + }
1098 +
1099 + $cart_attr['href'] = ! empty( $ext_link ) ? esc_url( $ext_link ) : esc_url( $link );
1100 +
1101 + $this->add_attribute( 'rtsb_add_to_cart_button_' . $id . $rand, $cart_attr );
1102 +
1103 + $content .= '<a ' . $this->get_attribute_string( 'rtsb_add_to_cart_button_' . $id . $rand ) . '>';
1104 + $content .= $icon_html;
1105 + $content .= '<span class="text">' . ( ! empty( $btn_txt ) ? esc_html( $btn_txt ) : esc_html__( 'Buy Product', 'shopbuilder' ) ) . '</span>';
1106 + } else {
1107 + $cart_attr['href'] = $cart_attr['href'] . '?add-to-cart=' . absint( $id );
1108 + $cart_attr['class'] .= ' rtsb-add-to-cart-btn';
1109 + $cart_attr['data-type'] = $type;
1110 +
1111 + $this->add_attribute( 'rtsb_add_to_cart_button_' . $id . $rand, $cart_attr );
1112 +
1113 + $content .= '<a ' . $this->get_attribute_string( 'rtsb_add_to_cart_button_' . $id . $rand ) . '>';
1114 + $content .= $icon_html;
1115 + $content .= '<span class="text ' . ( ! empty( $success ) ? 'has-success-text' : 'no-success-text' ) . '" data-success="' . esc_html( $success ) . '">' . esc_html( $text ) . '</span>';
1116 + $content .= '<span></span>';
869 1117 }
870 1118
871 - if ( ! empty( $meta['custom_link']['url'] ) ) {
872 - $arg['cat_link'] = $meta['custom_link']['url'];
873 - $arg['target'] = $meta['custom_link']['is_external'] ? '_blank' : '_self';
1119 + $content .= '</a>';
1120 + $content .= '</div>';
1121 +
1122 + ob_start();
1123 + do_action( 'rtsb/after/cart/button' );
1124 + $content .= ob_get_clean();
1125 +
1126 + return apply_filters( 'rtsb/render/cart/button', $content, $args );
1127 + }
1128 +
1129 + /**
1130 + * Button classes.
1131 + *
1132 + * @param array $params Button params.
1133 + *
1134 + * @return array
1135 + */
1136 + public function button_classes( $params ) {
1137 + $params['classes'] = array_merge( $params['classes'], [ 'rtsb-action-btn', 'tipsy' ] );
1138 +
1139 + return $params;
1140 + }
1141 +
1142 + /**
1143 + * Render the section title.
1144 + *
1145 + * @param array $settings The Elementor settings.
1146 + *
1147 + * @return string
1148 + */
1149 + public function render_section_title( $settings ) {
1150 + $html = '';
1151 + $rand = wp_rand();
1152 +
1153 + if ( empty( $settings['show_section_title'] ) || ( empty( $settings['query_products'] ) && 0 === count( $settings['query_products'] ) ) ) {
1154 + return $html;
874 1155 }
875 1156
876 - $title = $query->name;
877 - $excerpt = $query->description;
1157 + // Set attributes for the section title.
1158 + $this->add_attribute( 'rtsb_section_title_wrapper_' . $rand, 'class', 'rtsb-section-title-wrapper' );
1159 + $this->add_attribute( 'rtsb_section_title_' . $rand, 'class', 'rtsb-section-title' );
878 1160
879 - if ( in_array( 'badges', $meta['visibility'], true ) ) {
880 - $arg['p_sale'] = $meta['custom_badge_text'];
881 - }
1161 + // Start rendering.
1162 + $html .= '<div ' . $this->get_attribute_string( 'rtsb_section_title_wrapper_' . $rand ) . '>';
1163 + $html .= '<' . esc_attr( $settings['section_title_tag'] ) . ' ' . $this->get_attribute_string( 'rtsb_section_title_' . $rand ) . '>';
1164 + $html .= esc_html( $settings['section_title_text'] );
1165 + $html .= '</' . esc_attr( $settings['section_title_tag'] ) . '>';
1166 + $html .= '</div>';
882 1167
883 - $arg['badge_class'] = RenderHelpers::badge_class( $meta['badge_preset'] );
1168 + return $html;
1169 + }
884 1170
885 - if ( $arg['count'] >= 0 ) {
886 - $prefix = ! empty( $meta['before_count'] ) ? $meta['before_count'] : '';
887 - $suffix = ! empty( $meta['after_count'] ) ? $meta['after_count'] : '';
1171 + /**
1172 + * Renders products pagination
1173 + *
1174 + * @param array $args Pagination args.
1175 + * @param string $query_type Query type.
1176 + *
1177 + * @return string
1178 + */
1179 + public function render_products_pagination( $args, $query_type = 'wc' ) {
1180 + list(
1181 + 'query' => $query,
1182 + 'meta' => $meta,
1183 + 'limit' => $limit,
1184 + 'per_page' => $per_page
1185 + ) = $args;
888 1186
889 - $arg['count'] = $prefix . $arg['count'] . $suffix;
890 - }
1187 + $html_utility = null;
1188 + $html = null;
1189 + $ajax = false;
1190 + $is_grid = preg_match( '/grid-layout/', $meta['layout'] ) || preg_match( '/list-layout/', $meta['layout'] );
1191 + $posts_per_page = 'wp' === $query_type ? $query->query_vars['posts_per_page'] : null;
1192 + $total_page = 'wp' === $query_type ? $query->max_num_pages : $query->get_products()->max_num_pages;
891 1193
892 - if ( $meta['show_custom_title'] && ! empty( $meta['cat_custom_title'] ) ) {
893 - $title = $meta['cat_custom_title'];
894 - }
1194 + if ( $limit ) {
1195 + if ( 'wc' === $query_type ) {
1196 + $found_post = $query->get_products()->total;
1197 + } elseif ( 'wp' === $query_type && ( empty( $wp_query->query['tax_query'] ) ) ) {
1198 + $found_post = $query->found_posts;
1199 + }
895 1200
896 - if ( $meta['show_custom_excerpt'] && ! empty( $meta['cat_custom_excerpt'] ) ) {
897 - $excerpt = $meta['cat_custom_excerpt'];
1201 + if ( $per_page && $found_post > $per_page ) {
1202 + $found_post = $limit;
1203 + $total_page = ceil( $found_post / $per_page );
1204 + }
898 1205 }
899 1206
900 - $layout = $meta['layout'];
1207 + $total_page = absint( $total_page );
901 1208
902 - $arg['c_img'] = $meta['c_img'];
903 - $arg['items'] = $meta['visibility'];
904 - $arg['title_tag'] = $meta['title_tag'];
905 - $arg['title_class'] = 'category-title rtsb-text-limit limit-' . $meta['title_limit'] . ( ! $meta['title_link'] ? ' no-link' : '' );
906 - $arg['title'] = Fns::text_truncation( $title, $meta['title_limit_custom'] );
907 - $arg['excerpt_limit'] = $meta['excerpt_limit'];
908 - $arg['excerpt'] = wpautop( Fns::text_truncation( $excerpt, $meta['excerpt_limit_custom'] ) );
909 - $arg['title_link'] = $meta['title_link'];
910 - $arg['image_link'] = $meta['image_link'];
1209 + $args = [
1210 + 'total_page' => $total_page,
1211 + 'posts_per_page' => 'wc' === $query_type ? $per_page : $posts_per_page,
1212 + 'ajax' => $ajax,
1213 + ];
911 1214
912 - if ( ! $fullwidth ) {
913 - $arg['grid'] .= 'rtsb-col-grid ';
914 - $arg['class'] .= ' even-grid-item ';
1215 + if ( 'pagination' === $meta['posts_loading_type'] ) {
1216 + if ( $is_grid ) {
1217 + $html_utility .= Fns::custom_pagination(
1218 + $total_page,
1219 + 'wc' === $query_type ? $per_page : $posts_per_page
1220 + );
1221 + }
915 1222 } else {
916 - $arg['grid'] .= 'rtsb-col-grid ';
1223 + ob_start();
1224 + do_action( 'rtsb/elementor/render/pagination', $meta, $query, $args );
1225 + $html_utility .= ob_get_clean();
917 1226 }
918 1227
919 - $arg['class'] .= 'rtsb-category-grid';
1228 + if ( $html_utility ) {
1229 + $rand = wp_rand();
920 1230
921 - $arg['img_html'] = $meta['c_img'] ? Fns::get_product_image_html(
922 - 'category',
923 - $query->term_id,
924 - $meta['f_img_size'],
925 - $meta['default_img_id'],
926 - $meta['custom_img_size'],
927 - $lazy_load
928 - ) : null;
1231 + // Adding pagination render attributes.
1232 + $this->add_attribute(
1233 + 'rtsb_pagination_attr_' . $rand,
1234 + [
1235 + 'class' => 'rtsb-pagination-wrap element-loading',
1236 + 'data-total-pages' => $total_page,
1237 + 'data-posts-per-page' => 'wc' === $query_type ? $per_page : $posts_per_page,
1238 + 'data-type' => $meta['posts_loading_type'],
1239 + ]
1240 + );
929 1241
930 - if ( $meta['show_custom_image'] && ! empty( $meta['custom_image'] ) ) {
931 - $arg['img_html'] = Fns::get_product_image_html(
932 - 'custom',
933 - null,
934 - $meta['f_img_size'],
935 - $meta['custom_image'],
936 - $meta['custom_img_size'],
937 - $lazy_load
938 - );
1242 + // Start rendering.
1243 + $html = '<div ' . $this->get_attribute_string( 'rtsb_pagination_attr_' . $rand ) . '>';
1244 + $html .= $html_utility;
1245 + $html .= '</div><!-- .rtsb-pagination-wrap -->';
939 1246 }
940 1247
941 - $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' : '' );
1248 + return $html;
1249 + }
942 1250
943 - if ( $category_loop ) {
944 - $query_args = [
945 - 'product_category_id' => $query->term_id,
946 - 'limit' => -1,
947 - 'order' => 'DESC',
948 - 'orderby' => 'date',
949 - ];
1251 + /**
1252 + * Renders slider buttons
1253 + *
1254 + * @param array $settings Settings array.
1255 + *
1256 + * @return string
1257 + */
1258 + public function render_slider_buttons( $settings ) {
1259 + $html = '';
1260 + $left_icon = $settings['left_arrow_icon'];
1261 + $right_icon = $settings['right_arrow_icon'];
950 1262
951 - $products_query = new \WC_Product_Query( $query_args );
952 - $products = $products_query->get_products();
1263 + if ( ! empty( $settings['slider_nav'] ) ) {
1264 + $html .=
1265 + '<div class="swiper-nav">
1266 + <div class="swiper-arrow swiper-button-next">
1267 + ' . Fns::icons_manager( $right_icon ) . '
1268 + </div>
1269 + <div class="swiper-arrow swiper-button-prev">
1270 + ' . Fns::icons_manager( $left_icon ) . '
1271 + </div>
1272 + </div>';
953 1273 }
954 1274
955 - return apply_filters( 'rtsb/elementor/render/cat_arg_dataset', $arg, $meta, $query, $fullwidth, $lazy_load, $products );
1275 + $html .= ! empty( $settings['slider_dot'] ) ? '<div class="swiper-pagination rtsb-pos-s"></div>' : '';
1276 +
1277 + return $html;
956 1278 }
957 1279
958 1280 /**
959 - * Renders add to cart button.
1281 + * No products message.
960 1282 *
961 - * @param string $link Product link.
962 - * @param int $id Product ID.
963 - * @param string $type Product type.
964 - * @param string $text Custom text.
965 - * @param string $success Success text.
966 - * @param string $icon_html Custom icon.
967 - * @param string $alignment Icon alignment.
1283 + * @param array $metas Meta data.
968 1284 *
1285 + * @return void
1286 + */
1287 + public function no_products_msg( $metas ) {
1288 + $content =
1289 + '<div class="rtsb-notice woocommerce-no-products-found">
1290 + <div class="woocommerce-info">' . esc_html__( 'No products were found matching your selection.', 'shopbuilder' ) . '</div>
1291 + </div>';
1292 +
1293 + $this->row( $content, $metas );
1294 + }
1295 +
1296 + /**
1297 + * Start the rendering.
1298 + *
1299 + * @param array $metas Meta Data.
1300 + * @param array $settings Widget settings.
1301 + * @param array $temp_args Additional temporary arguments for rendering.
1302 + *
969 1303 * @return string
970 1304 */
971 - public function render_add_to_cart_button( $link, $id, $type, $text, $success, $icon_html, $alignment ) {
972 - $content = null;
973 - $tooltip_attr = '';
974 - $ext_link = get_post_meta( $id, '_product_url', true );
975 - $btn_txt = get_post_meta( $id, '_button_text', true );
1305 + public function render_start( $metas, $settings, $temp_args ) {
1306 + ob_start();
976 1307
977 - if ( empty( $text ) ) {
978 - $tooltip_attr = ' title="' . esc_attr__( 'Add to Cart', 'shopbuilder' ) . '"';
1308 + /**
1309 + * Before render row hook.
1310 + */
1311 + do_action( 'rtsb/elementor/render/before_row', $metas, $settings, $temp_args, $this );
979 1312
980 - if ( 'variable' === $type ) {
981 - $tooltip_attr = ' title="' . esc_attr__( 'Select Options', 'shopbuilder' ) . '"';
1313 + return ob_get_clean();
1314 + }
1315 +
1316 + /**
1317 + * End the rendering.
1318 + *
1319 + * @param array $metas Meta Data.
1320 + * @param array $settings Widget settings.
1321 + * @param array $products Array of products being rendered.
1322 + *
1323 + * @return string
1324 + */
1325 + public function render_end( $metas, $settings, $products ) {
1326 + ob_start();
1327 +
1328 + /**
1329 + * After render row hook.
1330 + */
1331 + do_action( 'rtsb/elementor/render/after_row', $metas, $settings, $products );
1332 +
1333 + return ob_get_clean();
1334 + }
1335 +
1336 + /**
1337 + * Add render attribute.
1338 + *
1339 + * @param array|string $element The HTML element.
1340 + * @param array|string $key Optional. Attribute key. Default is null.
1341 + * @param array|string $value Optional. Attribute value. Default is null.
1342 + * @param bool $overwrite Optional. Whether to overwrite existing.
1343 + *
1344 + * @return self
1345 + */
1346 + public function add_attribute( $element, $key = null, $value = null, $overwrite = false ) {
1347 + if ( is_array( $element ) ) {
1348 + foreach ( $element as $element_key => $attributes ) {
1349 + $this->add_attribute( $element_key, $attributes, null, $overwrite );
982 1350 }
983 1351
984 - if ( 'grouped' === $type ) {
985 - $tooltip_attr = ' title="' . esc_attr__( 'View Products', 'shopbuilder' ) . '"';
1352 + return $this;
1353 + }
1354 +
1355 + if ( is_array( $key ) ) {
1356 + foreach ( $key as $attribute_key => $attributes ) {
1357 + $this->add_attribute( $element, $attribute_key, $attributes, $overwrite );
986 1358 }
987 1359
988 - if ( 'external' === $type ) {
989 - $tooltip_txt = ! empty( $btn_txt ) ? esc_html( $btn_txt ) : esc_html__( 'Buy Product', 'shopbuilder' );
990 - $tooltip_attr = ' title="' . esc_attr( $tooltip_txt ) . '"';
991 - }
1360 + return $this;
992 1361 }
993 1362
994 - ob_start();
995 - do_action( 'rtsb/before/cart/button' );
996 - $content .= ob_get_clean();
1363 + if ( empty( $this->attributes[ $element ][ $key ] ) ) {
1364 + $this->attributes[ $element ][ $key ] = [];
1365 + }
997 1366
998 - if ( 'variable' === $type ) {
999 - $content .= sprintf(
1000 - '<div class="rtsb-wc-add-to-cart-wrap">
1001 - <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>
1002 - </div>',
1003 - esc_url( $link ),
1004 - esc_html__( 'Select Options', 'shopbuilder' ),
1005 - absint( $id ),
1006 - esc_attr( $alignment ),
1007 - empty( $text ) ? 'no-text' : 'has-text',
1008 - $tooltip_attr,
1009 - $icon_html,
1010 - );
1011 - } elseif ( 'grouped' === $type ) {
1012 - $content .= sprintf(
1013 - '<div class="rtsb-wc-add-to-cart-wrap">
1014 - <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>
1015 - </div>',
1016 - esc_url( $link ),
1017 - esc_html__( 'View Products', 'shopbuilder' ),
1018 - absint( $id ),
1019 - esc_attr( $alignment ),
1020 - empty( $text ) ? 'no-text' : 'has-text',
1021 - $tooltip_attr,
1022 - $icon_html,
1023 - );
1024 - } elseif ( 'external' === $type ) {
1025 - $content .= sprintf(
1026 - '<div class="rtsb-wc-add-to-cart-wrap">
1027 - <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>
1028 - </div>',
1029 - ! empty( $ext_link ) ? esc_url( $ext_link ) : esc_url( $link ),
1030 - ! empty( $btn_txt ) ? esc_html( $btn_txt ) : esc_html__( 'Buy Product', 'shopbuilder' ),
1031 - absint( $id ),
1032 - esc_attr( $alignment ),
1033 - empty( $text ) ? 'no-text' : 'has-text',
1034 - $tooltip_attr,
1035 - $icon_html,
1036 - ! empty( $ext_link ) ? ' target="_blank"' : ''
1037 - );
1367 + settype( $value, 'array' );
1368 +
1369 + if ( $overwrite ) {
1370 + $this->attributes[ $element ][ $key ] = $value;
1038 1371 } else {
1039 - $content .= sprintf(
1040 - '<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>',
1041 - esc_url( $link ),
1042 - absint( $id ),
1043 - esc_attr( $type ),
1044 - $icon_html,
1045 - esc_html( $text ),
1046 - esc_attr( $alignment ),
1047 - empty( $text ) ? 'no-text' : 'has-text',
1048 - $tooltip_attr,
1049 - esc_html( $success ),
1050 - ! empty( $success ) ? 'has-success-text' : 'no-success-text',
1051 - );
1372 + $this->attributes[ $element ][ $key ] = array_merge( $this->attributes[ $element ][ $key ], $value );
1052 1373 }
1053 1374
1054 - ob_start();
1055 - do_action( 'rtsb/after/cart/button' );
1056 - $content .= ob_get_clean();
1057 -
1058 - return $content;
1375 + return $this;
1059 1376 }
1060 1377
1061 1378 /**
1062 - * Button classes.
1379 + * Get render attribute string.
1063 1380 *
1064 - * @param array $params Button params.
1381 + * @param string $element The element.
1065 1382 *
1066 - * @return array
1383 + * @return string
1067 1384 */
1068 - public function button_classes( $params ) {
1069 - $params['classes'] = array_merge( $params['classes'], [ 'rtsb-action-btn', 'tipsy' ] );
1385 + public function get_attribute_string( $element ) {
1386 + if ( empty( $this->attributes[ $element ] ) ) {
1387 + return '';
1388 + }
1070 1389
1071 - return $params;
1390 + return Utils::render_html_attributes( $this->attributes[ $element ] );
1072 1391 }
1073 1392 }