PluginProbe
ShopBuilder – WooCommerce Builder For Elementor / 3.2.2
ShopBuilder – WooCommerce Builder For Elementor v3.2.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 3.2.2, at app/Elementor/Render/Render.php

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