PluginProbe
ShopBuilder – WooCommerce Builder For Elementor / 2.5.2
ShopBuilder – WooCommerce Builder For Elementor v2.5.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
shopbuilder / app / Elementor / Render / Render.php

Render.php in ShopBuilder – WooCommerce Builder For Elementor 2.5.2, at app/Elementor/Render/Render.php

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