# shopbuilder/2.1.1/app/Elementor/Render/Render.php

ShopBuilder – WooCommerce Builder For Elementor, version 2.1.1. 1,074 lines.

- Page: https://pluginprobe.com/plugins/shopbuilder/2.1.1/code/app/Elementor/Render/Render.php
- Raw: https://pluginprobe.com/plugins/shopbuilder/2.1.1/raw/app/Elementor/Render/Render.php
- Modified: 2024-01-19T11:10:30+00:00

Line numbers below start at 1. Link to a line or a range by appending a fragment to the
page URL, for example `https://pluginprobe.com/plugins/shopbuilder/2.1.1/code/app/Elementor/Render/Render.php#L10-L20`.

```php
<?php
/**
 * Elementor Render Class.
 *
 * This class contains render logics & output.
 *
 * @package RadiusTheme\SB
 */

namespace RadiusTheme\SB\Elementor\Render;

use WP_Query;
use WC_Product;
use RadiusTheme\SB\Helpers\Fns;
use RadiusTheme\SB\Models\QueryArgs;
use RadiusTheme\SB\Helpers\BuilderFns;
use RadiusTheme\SB\Traits\SingletonTrait;
use RadiusTheme\SB\Traits\ActionBtnTraits;
use RadiusTheme\SB\Elementor\Helper\RenderHelpers;

// Do not allow directly accessing this file.
if ( ! defined( 'ABSPATH' ) ) {
	exit( 'This script cannot be accessed directly.' );
}

/**
 * Elementor Render Class.
 */
class Render {
	/**
	 * Singleton Trait.
	 */
	use SingletonTrait;

	/**
	 * Action button trait.
	 */
	use ActionBtnTraits;

	/**
	 * HTML.
	 *
	 * @var string
	 */
	private $html = null;

	/**
	 * Settings array
	 *
	 * @var array
	 */
	public $get_settings;

	/**
	 * Get elementor settings.
	 *
	 * @return array
	 */
	public function get_settings_for_display() {
		return $this->get_settings;
	}

	/**
	 * Container Wrapper HTML.
	 *
	 * @param string $content The content.
	 * @param array  $settings Settings.
	 * @param string $class Class.
	 * @param string $template Template name.
	 * @param bool   $fullwidth Fullwidth check.
	 * @param bool   $ajax_attr Ajax attributes.
	 *
	 * @return string
	 */
	public function container( $content, $settings, $class = '', $template = '', $fullwidth = false, $ajax_attr = true ) {
		$layout_id       = 'rtsb-container-' . absint( wp_rand() );
		$container_attr  = null;
		$cart_txt_class  = '';
		$container_class = 'rtsb-elementor-container  products rtsb-pos-r ' . esc_attr( $class );
		$metas           = RenderHelpers::meta_dataset( $settings, $template );

		$layout     = $metas['layout'];
		$animation  = $metas['hover_animation'];
		$animation .= ' gallery-hover-' . ( ! empty( $settings['gallery_hover_animation'] ) ? $settings['gallery_hover_animation'] : 'fade' );

		$is_cat      = preg_match( '/category/', $layout );
		$is_carousel = preg_match( '/slider/', $layout );

		if ( ! $is_cat ) {
			$cart_txt_class = $metas['show_cart_text'] ? ' has-cart-text' : ' no-cart-text';
		}

		if ( $is_carousel ) {
			$fullwidth = true;
		}

		$badge_class = [
			'position'  => $metas['badge_position'],
			'alignment' => $metas['badge_alignment'],
		];

		if ( ! rtsb()->has_pro() && ! in_array( $layout, array_keys( Fns::free_layouts() ), true ) ) {
			$layout = RenderHelpers::set_default_layout( $layout );
		}

		$has_tab_filters = rtsb()->has_pro() && ! empty( $settings['tax_filter'] );

		if ( $is_carousel ) {
			$pagination_attr = $has_tab_filters ? RenderHelpers::pagination_data( $settings, $template ) : '';
		} elseif ( $is_cat ) {
			$pagination_attr = '';
		} else {
			$ajax_pagination = ! empty( $settings['show_pagination'] ) && 'pagination' !== $settings['pagination_type'];
			$page            = Fns::product_filters_has_ajax( 'shop' ) || Fns::product_filters_has_ajax( 'archive' );
			$condition       = rtsb()->has_pro() && $ajax_attr && ( $ajax_pagination || $has_tab_filters || $page );
			$pagination_attr = $condition ? RenderHelpers::pagination_data( $settings, $template ) : '';
		}

		if ( ! in_array( 'clear-btn', $metas['visibility'], true ) ) {
			$container_class .= ' no-clear-btn';
		}

		$container_class .= ! empty( $metas['pagination'] ) ? ' rtsb-has-pagination' : ' rtsb-no-pagination';
		$style_attr       = ' style="--rtsb-default-columns: ' . esc_attr( RenderHelpers::default_columns( $layout ) ) . '"';
		$tooltip_attr     = ' data-tooltip-position="' . esc_attr( $metas['tooltip_position'] ) . '"';

		$view_mode = $settings['view_mode'] ?? 'grid';

		// phpcs:ignore WordPress.Security.NonceVerification.Recommended
		if ( isset( $_GET['displayview'] ) ) {
			$view_mode = sanitize_text_field( wp_unslash( $_GET['displayview'] ) ); // phpcs:ignore WordPress.Security.NonceVerification.Recommended
		}

		if ( 'list' == $view_mode && ! empty( $metas['tooltip_position_list'] ) ) {
			$tooltip_attr = ' data-tooltip-position="' . esc_attr( $metas['tooltip_position_list'] ) . '"';
		}

		$container_attr  .= ' data-layout="' . esc_attr( $layout ) . '"' . $style_attr . $tooltip_attr . $pagination_attr;
		$container_class .= ' badge-' . esc_attr( $badge_class['position'] ) . ' badge-' . esc_attr( $badge_class['alignment'] ) . esc_attr( $cart_txt_class ) . ' img-hover-' . esc_attr( $animation ) . ' excerpt-' . esc_attr( $metas['cat_excerpt_position'] );

		if ( $metas['show_overlay'] ) {
			$container_class .= ' has-overlay';
		}

		if ( in_array( 'single-cat', $metas['visibility'], true ) ) {
			$container_class .= ' show-single-cat';
		}

		if ( ! empty( $settings['show_compare_text'] ) ) {
			$container_class .= ' has-compare-text';
		}

		if ( ! empty( $settings['show_quick_view_text'] ) ) {
			$container_class .= ' has-quick-view-text';
		}

		if ( ! empty( $settings['show_wishlist_text'] ) ) {
			$container_class .= ' has-wishlist-text';
		}

		if ( empty( $settings['show_compare_icon'] ) ) {
			$container_class .= ' no-compare-icon';
		}

		if ( empty( $settings['show_quick_view_icon'] ) ) {
			$container_class .= ' no-quick-view-icon';
		}

		if ( empty( $settings['show_wishlist_icon'] ) ) {
			$container_class .= ' no-wishlist-icon';
		}

		if ( empty( $settings['show_quick_checkout_icon'] ) ) {
			$container_class .= ' no-quick_checkout-icon';
		}
		if ( $is_cat && empty( $settings['show_overlay'] ) ) {
			$container_class .= ' no-category-bg-overlay';
		}

		$container_class = apply_filters( 'rtsb/product/container/class', $container_class, $settings );
		$this->html      = '<div class="' . esc_attr( $container_class ) . '" id="' . esc_attr( $layout_id ) . '" ' . $container_attr . '>';

		if ( ! empty( $settings['query_products'] ) && count( $settings['query_products'] ) && 'yes' === $settings['show_section_title'] ) {
			$this->html .= '<div class="rtsb-section-title-wrapper">';
			$this->html .= '<' . esc_attr( $settings['section_title_tag'] ) . ' class="rtsb-section-title" >';
			$this->html .= esc_html( $settings['section_title_text'] );
			$this->html .= '</' . esc_attr( $settings['section_title_tag'] ) . '>';
			$this->html .= '</div>';
		}

		$this->html .= $content;

		$this->html .= '</div><!-- .rtsb-elementor-container -->';

		// Action button icon reset.
		$this->action_button_icon_set_default();

		$script_generator               = [];
		$script_generator['layout']     = $layout_id;
		$script_generator['rand']       = absint( wp_rand() );
		$script_generator['isCarousel'] = $is_carousel;

		add_action(
			'wp_footer',
			static function () use ( $script_generator ) {
				RenderHelpers::register_scripts( $script_generator );
			}
		);

		return $this->html;
	}

	/**
	 * Row Wrapper HTML.
	 *
	 * @param string $content The content.
	 * @param array  $settings Settings.
	 * @param string $hook_html Hook HTML.
	 * @param array  $raw_settings Raw Settings.
	 *
	 * @return string
	 */
	public function row( $content, $settings, $hook_html = '', $raw_settings = [] ) {
		$masonry_class = null;
		$loader_class  = ' rtsb-pre-loader';

		$layout      = $settings['layout'];
		$grid_type   = $settings['grid_type'];
		$is_carousel = preg_match( '/slider/', $layout );

		if ( 'even' === $grid_type ) {
			$masonry_class = ' rtsb-even';
		} elseif ( 'masonry' === $grid_type ) {
			$masonry_class = ' rtsb-masonry';
		}

		if ( ! rtsb()->has_pro() || $is_carousel ) {
			$masonry_class = ' rtsb-even';
		}

		$row_start_class = apply_filters( 'rtsb/custom/layout/row/classes', esc_attr( 'rtsb-row rtsb-content-loader element-loading rtsb-' . $layout . $masonry_class . $loader_class ), $settings );
		$row_wrapper     = '<div data-title="' . esc_html__( 'Loading ...', 'shopbuilder' ) . '" class="' . $row_start_class . '">';
		$start_wrapper   = apply_filters( 'rtsb/custom/layout/row/start', $row_wrapper, $row_start_class );
		if ( ! empty( $settings['show_filter'] ) ) {
			$this->html  = $hook_html;
			$this->html .= $start_wrapper;
		} else {
			$this->html = $start_wrapper;
		}

		if ( $is_carousel ) {
			$slider_data = RenderHelpers::slider_data( $settings, $raw_settings );

			$this->html .= '<div class="rtsb-col-grid ' . esc_attr( $slider_data['class'] ) . '" ' . $slider_data['data'] . '>';
			$this->html .= '<div class="swiper-wrapper">';
		}

		$this->html .= $content;

		if ( $is_carousel ) {
			$this->html .= '</div><!-- .swiper-wrapper -->';

			$left_icon  = $settings['left_arrow_icon'];
			$right_icon = $settings['right_arrow_icon'];

			if ( ! empty( $settings['slider_nav'] ) ) {
				$this->html .=
					'<div class="swiper-nav">
						<div class="swiper-arrow swiper-button-next">
							' . Fns::icons_manager( $right_icon ) . '
						</div>
						<div class="swiper-arrow swiper-button-prev">
							' . Fns::icons_manager( $left_icon ) . '
						</div>
					</div>';
			}

			$this->html .= ! empty( $settings['slider_dot'] ) ? '<div class="swiper-pagination rtsb-pos-s"></div>' : '';

			$this->html .= '</div><!-- .rtsb-carousel-slider -->';
		}

		$row_end = '</div><!-- .rtsb-row -->';

		$this->html .= apply_filters( 'rtsb/custom/layout/row/end', $row_end );

		$this->html .= RenderHelpers::pre_loader( $layout );

		return $this->html;
	}

	/**
	 * Product loop.
	 *
	 * @param object $query The query.
	 * @param array  $settings Settings.
	 * @param string $template Template.
	 *
	 * @return string|null
	 */
	public function product_loop( $query, $settings, $template ) {
		$html = null;

		if ( empty( $query ) ) {
			return null;
		}

		$i = 0;

		while ( $query->have_posts() ) {
			$query->the_post();
			$i++;

			// Loop arg.
			$arg = $this->arg_dataset( $settings, get_the_ID(), $settings['lazy_load'], $i );

			// Get template.
			$html .= Fns::load_template( $template . $settings['layout'], $arg, true );
		}

		return $html;
	}

	/**
	 * Product loop.
	 *
	 * @param object $query The query.
	 * @param array  $settings Settings.
	 * @param string $template Template.
	 * @param bool   $is_single Single category.
	 *
	 * @return string|null
	 */
	public function category_loop( $query, $settings, $template, $is_single = false ) {
		$html          = null;
		$category_loop = false;
		if ( 'category-layout3' === $settings['raw_settings']['layout'] || 'category-single-layout2' === $settings['raw_settings']['layout'] ) {
			$category_loop = true;
		}
		if ( $is_single ) {
			// Loop arg.
			$arg = $this->cat_arg_dataset( $settings, $query, true, false, $category_loop );

			// Get template.
			$html .= Fns::load_template( $template . $settings['layout'], $arg, true );
		} else {
			foreach ( $query as $term ) {
				// Loop arg.
				$arg = $this->cat_arg_dataset( $settings, $term, false, false, $category_loop );

				// Get template.
				$html .= Fns::load_template( $template . $settings['layout'], $arg, true );
			}
		}

		return $html;
	}

	/**
	 * Render Product View.
	 *
	 * @param string $template Template name.
	 * @param array  $settings Control settings.
	 *
	 * @return string
	 */
	public function product_view( $template, $settings ) {
		$this->get_settings = $settings;

		$metas       = RenderHelpers::meta_dataset( $settings, $template, $this->get_settings_for_display() );
		$is_carousel = preg_match( '/slider/', $metas['layout'] );
		$pagination  = $metas['pagination'];
		$hook_html   = '';

		// Query Args.
		$args = ( new QueryArgs() )->buildArgs( $metas, 'product', $is_carousel );

		$temp_args = $args;
		$args      = apply_filters( 'rtsb/elementor/args_before_loop', $args, $metas );

		// Query.
		$product_query = new WP_Query( $args );

		if ( $product_query->have_posts() ) {
			// Elementor Render hook before row.
			ob_start();
			do_action( 'rtsb/elementor/render/before_row', $metas, $settings, $product_query, $temp_args );
			$hook_html .= ob_get_clean();

			// Row.
			$this->row( $this->product_loop( $product_query, $metas, $template ), $metas, $hook_html, $settings );

			// Pagination.
			if ( $pagination ) {
				$this->html .= RenderHelpers::render_pagination(
					$product_query,
					$metas,
					$settings['posts_limit'],
					$settings['pagination_per_page']
				);
			}

			// Elementor Render hook before row.
			ob_start();
			do_action( 'rtsb/elementor/render/after_row', $metas, $settings, $product_query );
			$this->html .= ob_get_clean();

		} else {
			$content = '<div class="woocommerce-no-products-found"><div class="woocommerce-info">' . esc_html__( 'No products were found matching your selection.', 'shopbuilder' ) . '</div></div>';

			$this->row( $content, $metas );
		}

		wp_reset_postdata();

		unset( $args['tax_query'] );

		// Container.
		$this->container( $this->html, $settings, 'rtsb-products-container', $template, $is_carousel );

		return $this->html;
	}


	/**
	 * Render Product View.
	 *
	 * @param string $template Template name.
	 * @param array  $settings Control settings.
	 * @param object $widget Reference widget.
	 *
	 * @return string
	 */
	public function wc_loop_for_product_view( $template, $settings, $widget ) {
		global $wp_query, $post;

		$this->get_settings = $settings;
		$metas              = RenderHelpers::meta_dataset( $settings, $template, $widget->get_settings_for_display() );

		$settings['rtsb_order']   = ! empty( $wp_query->query_vars['order'] ) ? $wp_query->query_vars['order'] : 'ASC';
		$settings['rtsb_orderby'] = ! empty( $wp_query->query_vars['orderby'] ) ? $wp_query->query_vars['orderby'] : 'menu_order';

		$pagination = $metas['pagination'];

		$page_type      = BuilderFns::builder_type( get_the_ID() );
		$is_preview     = BuilderFns::is_builder_preview() && array_key_exists( $page_type, BuilderFns::builder_page_types() );
		$posts_per_page = wc_get_default_products_per_row() * wc_get_default_product_rows_per_page();

		if ( $is_preview ) {
			$main_query = clone $wp_query;
			$main_post  = clone $post;

			$ordering      = ( new \WC_Query() )->get_catalog_ordering_args();
			$wp_query_args = [
				'post_type'      => 'product',
				'posts_per_page' => $posts_per_page,
			];

			if ( ! empty( $ordering['orderby'] ) ) {
				$wp_query_args['orderby'] = $ordering['orderby'];
			}

			if ( ! empty( $ordering['order'] ) ) {
				$wp_query_args['order'] = $ordering['order'];
			}

			$wp_query = new WP_Query( $wp_query_args ); // phpcs:ignore WordPress.WP.GlobalVariablesOverride.Prohibited
			wc_set_loop_prop( 'total', $wp_query->found_posts );
			wc_set_loop_prop( 'total_pages', $wp_query->max_num_pages );
		}

		// column_per_row.
		if ( woocommerce_product_loop() ) {
			if ( wc_get_loop_prop( 'total' ) ) {
				if ( Fns::product_has_applied_filters( 'shop' ) || Fns::product_has_applied_filters( 'archive' ) || 'rtsb_builder' === get_post_type( get_the_ID() ) ) {
					echo '<div class="rtsb-active-filters-wrapper"></div>';
				}

				// Row.
				$this->row( $this->product_loop( $wp_query, $metas, $template ), $metas );
			}

			// Pagination.
			$this->html .= '<div class="rtsb-archive-pagination-wrap">';

			if ( $pagination ) {
				if ( Fns::product_filters_has_ajax( 'shop' ) || Fns::product_filters_has_ajax( 'archive' ) ) {
					if ( $wp_query->max_num_pages > 1 ) {
						$this->html .= "
						<div class='rtsb-load-more rtsb-pos-r'>
						    <button data-paged='2' data-max-page='{$wp_query->max_num_pages}'><span>" . esc_html__( 'Load More', 'shopbuilder' ) . "</span></button>
						    <div class='rtsb-loadmore-loading rtsb-ball-clip-rotate'><div></div></div>
						</div>
					 ";
					}
				} else {
					$this->html .= RenderHelpers::render_pagination(
						$wp_query,
						$metas,
						wc_get_loop_prop( 'total' ),
						$posts_per_page
					);
				}
			}

			$this->html .= '</div>';
		} else {
			$content = '<div class="woocommerce-no-products-found"><div class="woocommerce-info">' . esc_html__( 'No products were found matching your selection.', 'shopbuilder' ) . '</div></div>';

			$this->row( $content, $metas );
		}

		if ( $is_preview ) {
			$wp_query = $main_query;
			$post     = $main_post;

			wp_reset_query();
			wp_reset_postdata();
		}

		// Container.
		$this->container( $this->html, $settings, 'rtsb-products-container', $template );

		return $this->html;
	}

	/**
	 * Render Product View.
	 *
	 * @param string $template Template name.
	 * @param array  $settings Control settings.
	 *
	 * @return string
	 */
	public function setup_loop_for_product_view( $template, $settings, $widget ) {
		if ( empty( $settings['query_products'] ) ) {
			return $this->html;
		}

		$html = null;

		$metas = RenderHelpers::meta_dataset( $settings, '', $widget->get_settings_for_display() );

		foreach ( $settings['query_products'] as $_product ) {
			$post_object = get_post( $_product->get_id() );

			setup_postdata( $GLOBALS['post'] =& $post_object ); // phpcs:ignore WordPress.WP.GlobalVariablesOverride.Prohibited, Squiz.PHP.DisallowMultipleAssignments.Found

			// Loop arg.
			$arg = $this->arg_dataset( $metas, $_product->get_id() );
			// Get template.
			$html .= Fns::load_template( $template . $settings['layout'], $arg, true );

			$this->row( $html, $metas );
		}

		// Container.
		$this->container( $this->html, $settings, 'rtsb-products-container', '', false, false );

		wp_reset_postdata();

		return $this->html;
	}

	/**
	 * Render Category View.
	 *
	 * @param string $template Template name.
	 * @param array  $settings Control settings.
	 * @param bool   $is_single Single category.
	 *
	 * @return string
	 */
	public function category_view( $template, $settings, $is_single = false ) {
		$this->get_settings = $settings;

		$metas    = RenderHelpers::meta_dataset( $settings, $template, $this->get_settings_for_display() );
		$taxonomy = $metas['category_source'];
		$term     = $metas['category_term'];

		if ( rtsb()->has_pro() && ( ! empty( $metas['tag_term'] ) ) ) {
			$term = $metas['tag_term'];
		}

		// Query.
		if ( $is_single ) {
			if ( empty( $term ) ) {
				return '<p>' . esc_html__( 'Please select a category.', 'shopbuilder' ) . '</p>';
			}

			$taxonomy_query = get_term( $term, $taxonomy );
		} else {
			// Query Args.
			$args = ( new QueryArgs() )->buildArgs( $metas, 'category' );

			$taxonomy_query = get_terms( $args );
		}

		if ( ! is_wp_error( $taxonomy_query ) && ! empty( $taxonomy_query ) ) {
			// Row.
			$this->row( $this->category_loop( $taxonomy_query, $metas, $template, $is_single ), $metas );
		} else {
			$this->html .= '<p>' . esc_html__( 'No categories found', 'shopbuilder' ) . '</p>';
		}

		// Container.
		$this->container( $this->html, $settings, 'rtsb-categories-container', $is_single );

		return $this->html;
	}

	/**
	 * Render Category View.
	 *
	 * @param string $template Template name.
	 * @param array  $settings Control settings.
	 *
	 * @return string
	 */
	public function social_share_view( $template, $settings ) {
		$this->get_settings = $settings;
		$share_items        = [];

		foreach ( $settings['share_platforms'] as $platform ) {
			$share_items[] = [
				'share_items' => $platform['share_items'],
				'share_text'  => $platform['share_text'],
			];
		}

		if ( ! empty( $share_items ) && is_array( $share_items ) ) {
			$arg['p_id']           = get_the_ID();
			$arg['share_items']    = $share_items;
			$arg['preset']         = $settings['layout'];
			$arg['direction']      = ! empty( $settings['layout_direction'] ) ? $settings['layout_direction'] : 'horizontal';
			$arg['show_icon']      = ! empty( $settings['show_share_icon'] );
			$arg['show_text']      = ! empty( $settings['show_share_text'] );
			$arg['show_pre_text']  = ! empty( $settings['show_share_pre_text'] );
			$arg['share_pre_text'] = ! empty( $settings['share_pre_text'] ) ? $settings['share_pre_text'] : '';
			$arg['raw_settings']   = $this->get_settings_for_display();
			$this->html            = Fns::load_template( $template, $arg, true );
		} else {
			$this->html = '<p>' . esc_html__( 'Please select a social sharing platform.', 'shopbuilder' ) . '</p>';
		}

		return $this->html;
	}

	/**
	 * Builds an array with meta values.
	 *
	 * @param array $meta Meta values.
	 * @param int   $post_id Post ID.
	 * @param bool  $lazy_load Lazy Load.
	 * @param int   $i Integer.
	 *
	 * @return array
	 */
	public function arg_dataset( array $meta, int $post_id, bool $lazy_load = false, $i = 0 ) {
		if ( ( empty( $meta ) && ! $post_id ) || ! in_array( get_post_type( $post_id ), [ 'product_variation', 'product' ] ) ) {
			return [];
		}

		global $post, $product;

		if ( ! $product instanceof WC_Product && $post_id ) {
			$product = wc_get_product( $post_id );
		}

		$arg    = [];
		$p_type = $product->get_type();

		$arg['class']          = null;
		$arg['grid']           = null;
		$arg['anchor_class']   = null;
		$arg['hover_img_html'] = null;
		$arg['s_link']         = [];
		$arg['add_to_cart']    = '';
		$arg['p_id']           = $post_id;
		$arg['p_link']         = get_permalink();
		$arg['p_sale']         = '';
		$arg['rating_args']    = [];
		$arg['has_attributes'] = $product->is_type( 'variable' ) && $product->get_attributes();
		$arg['raw_settings']   = ! empty( $meta['raw_settings'] ) ? $meta['raw_settings'] : [];
		$cart_icon_html        = '';

		$layout = $meta['layout'];

		$arg['target']              = '_self';
		$arg['f_img']               = $meta['f_img'];
		$arg['items']               = $meta['visibility'];
		$arg['title_tag']           = $meta['title_tag'];
		$arg['title_class']         = 'product-title rtsb-text-limit limit-' . $meta['title_limit'] . ( ! $meta['title_link'] ? ' no-link' : '' );
		$arg['title']               = Fns::text_truncation( get_the_title(), $meta['title_limit_custom'] );
		$arg['excerpt_limit']       = $meta['excerpt_limit'];
		$arg['excerpt']             = wpautop( Fns::text_truncation( do_shortcode( $post->post_excerpt ), $meta['excerpt_limit_custom'] ) );
		$arg['title_link']          = $meta['title_link'];
		$arg['image_link']          = $meta['image_link'];
		$arg['out_of_stock']        = $meta['out_of_stock_badge_text'];
		$arg['action_btn_preset']   = $meta['btn_preset'];
		$arg['action_btn_position'] = $meta['btn_position'];
		$arg['swatch_position']     = $meta['swatch_position'];
		$arg['swatch_type']         = $meta['swatch_type'];
		$arg['tooltip_position']    = $meta['tooltip_position'];

		$is_list     = preg_match( '/list/', $layout );
		$is_carousel = preg_match( '/slider/', $layout );

		if ( ! $is_carousel ) {
			$arg['grid']  .= 'rtsb-col-grid ';
			$arg['class'] .= ' even-grid-item ';
		} else {
			$arg['grid'] .= 'rtsb-col-grid rtsb-col-full rtsb-slide-item swiper-slide ';
		}

		$d_cols = 0 === $meta['d_cols'] ? RenderHelpers::default_columns( $layout ) : $meta['d_cols'];
		$t_cols = 0 === $meta['t_cols'] ? 2 : $meta['t_cols'];
		$m_cols = 0 === $meta['m_cols'] ? 1 : $meta['m_cols'];

		$arg['grid'] .= 0 === $i % $d_cols ? ' row-last desktop-row-last' : '';
		$arg['grid'] .= 0 === $i % $t_cols ? ' row-last tablet-row-last' : '';
		$arg['grid'] .= 0 === $i % $m_cols ? ' row-last mobile-row-last' : '';

		$arg['class'] .= 'rtsb-product';

		if ( $is_list ) {
			$arg['class'] .= ' rtsb-product-list';
		}

		$arg['class'] .= ' animated rtFadeIn';

		if ( in_array( 'badges', $meta['visibility'], true ) ) {
			$arg['p_sale'] = Fns::get_sale_badge(
				$meta['sale_badge_type'],
				$meta['sale_badge_text'],
				$meta['out_of_stock_badge_text']
			);
		}

		$arg['badge_class'] = RenderHelpers::badge_class( $meta['badge_preset'] );

		if ( ! $meta['show_cart_text'] ) {
			$meta['add_to_cart_text']         = '';
			$meta['add_to_cart_success_text'] = '';
		}

		if ( in_array( 'add_to_cart', $meta['visibility'], true ) ) {
			if ( ! empty( $meta['add_to_cart_icon'] ) ) {
				$cart_icon_html .= Fns::icons_manager( $meta['add_to_cart_icon'], 'cart-icon' );
			}

			if ( ! empty( $meta['add_to_cart_success_icon'] ) ) {
				$cart_icon_html .= Fns::icons_manager( $meta['add_to_cart_success_icon'], 'cart-success-icon' );
			}

			$cart_icon = '<span class="icon">' . $cart_icon_html . '</span>';

			if ( $product->is_purchasable() || 'grouped' === $p_type || 'external' === $p_type ) {
				if ( $product->is_in_stock() ) {
					$arg['add_to_cart'] = $this->render_add_to_cart_button(
						get_permalink(),
						$post_id,
						$p_type,
						$meta['add_to_cart_text'],
						$meta['add_to_cart_success_text'],
						$cart_icon,
						$meta['add_to_cart_alignment']
					);
				}
			}
		}

		if ( in_array( 'quick_view', $meta['visibility'], true ) ) {
			add_filter( 'rtsb/module/quick_view/button_params', [ $this, 'button_classes' ] );
			add_filter( 'rtsb/module/quick_view/icon_html', [ $this, 'quick_view_icon' ] );
		}

		if ( in_array( 'compare', $meta['visibility'], true ) ) {
			add_filter( 'rtsb/module/compare/button_params', [ $this, 'button_classes' ] );
			add_filter( 'rtsb/module/compare/icon_html', [ $this, 'compare_icon' ] );
		}

		if ( in_array( 'wishlist', $meta['visibility'], true ) ) {
			add_filter( 'rtsb/module/wishlist/button_params', [ $this, 'button_classes' ] );
			add_filter( 'rtsb/module/wishlist/icon_html', [ $this, 'wishlist_icon' ] );
		}

		$arg['img_html'] = $meta['f_img'] ? Fns::get_product_image_html(
			'product',
			$post_id,
			$meta['f_img_size'],
			$meta['default_img_id'],
			$meta['custom_img_size'],
			$lazy_load
		) : null;

		if ( ! ( function_exists( 'rtwpvsp' ) && $product->is_type( 'variable' ) && $product->get_attributes() ) ) {
			$gallery_ids = $product->get_gallery_image_ids();

			if ( $meta['hover_img'] && ! empty( $gallery_ids ) ) {
				$arg['class'] .= ! $meta['gallery_img'] ? ' rtsb-double-img' : '';

				if ( ! rtsb()->has_pro() ) {
					$arg['class'] .= ' rtsb-double-img';
				}

				$arg['hover_img_html'] = Fns::get_product_image_html(
					'product',
					$gallery_ids[0],
					$meta['f_img_size'],
					null,
					$meta['custom_img_size'],
					$lazy_load,
					true
				);
			}
		}

		$arg['hover_btn_text'] = $meta['hover_btn_text'];

		if ( $meta['show_hover_btn_icon'] && ! empty( $meta['hover_btn_icon'] ) ) {
			$arg['hover_btn_icon'] = '<span class="icon">' . Fns::icons_manager( $meta['hover_btn_icon'], 'hover-btn-icon' ) . '</span>';
		}

		$arg['img_args'] = [
			'p_id'           => $arg['p_id'],
			'title'          => get_the_title(),
			'p_link'         => $arg['p_link'],
			'image_link'     => $arg['image_link'],
			'img_html'       => $arg['img_html'],
			'hover_img_html' => $arg['hover_img_html'],
			'meta'           => $meta,
		];

		return apply_filters( 'rtsb/elementor/render/arg_dataset', $arg, $post_id, $meta, $lazy_load );
	}

	/**
	 * Builds an array with meta values.
	 *
	 * @param array  $meta Meta values.
	 * @param Object $query Category object.
	 * @param bool   $fullwidth Fullwidth check.
	 * @param bool   $lazy_load Lazy Load.
	 *
	 * @return array
	 */
	public function cat_arg_dataset( $meta, $query = null, $fullwidth = false, $lazy_load = false, $category_loop = false ) {
		if ( empty( $meta ) ) {
			return [];
		}

		$arg = [];

		$products                = null;
		$arg['class']            = null;
		$arg['grid']             = null;
		$arg['anchor_class']     = null;
		$arg['p_sale']           = null;
		$arg['count']            = max( $query->count, 0 );
		$arg['count_position']   = $meta['count_position'];
		$arg['excerpt_position'] = $meta['cat_excerpt_position'];
		$arg['cat_link']         = get_term_link( $query );
		$arg['target']           = '_self';
		$arg['raw_settings']     = ! empty( $meta['raw_settings'] ) ? $meta['raw_settings'] : [];

		if ( ! empty( $meta['tag_term'] ) ) {
			$arg['tag_term'] = $meta['tag_term'];
		}

		if ( ! empty( $meta['custom_link']['url'] ) ) {
			$arg['cat_link'] = $meta['custom_link']['url'];
			$arg['target']   = $meta['custom_link']['is_external'] ? '_blank' : '_self';
		}

		$title   = $query->name;
		$excerpt = $query->description;

		if ( in_array( 'badges', $meta['visibility'], true ) ) {
			$arg['p_sale'] = $meta['custom_badge_text'];
		}

		$arg['badge_class'] = RenderHelpers::badge_class( $meta['badge_preset'] );

		if ( $arg['count'] >= 0 ) {
			$prefix = ! empty( $meta['before_count'] ) ? $meta['before_count'] : '';
			$suffix = ! empty( $meta['after_count'] ) ? $meta['after_count'] : '';

			$arg['count'] = $prefix . $arg['count'] . $suffix;
		}

		if ( $meta['show_custom_title'] && ! empty( $meta['cat_custom_title'] ) ) {
			$title = $meta['cat_custom_title'];
		}

		if ( $meta['show_custom_excerpt'] && ! empty( $meta['cat_custom_excerpt'] ) ) {
			$excerpt = $meta['cat_custom_excerpt'];
		}

		$layout = $meta['layout'];

		$arg['c_img']         = $meta['c_img'];
		$arg['items']         = $meta['visibility'];
		$arg['title_tag']     = $meta['title_tag'];
		$arg['title_class']   = 'category-title rtsb-text-limit limit-' . $meta['title_limit'] . ( ! $meta['title_link'] ? ' no-link' : '' );
		$arg['title']         = Fns::text_truncation( $title, $meta['title_limit_custom'] );
		$arg['excerpt_limit'] = $meta['excerpt_limit'];
		$arg['excerpt']       = wpautop( Fns::text_truncation( $excerpt, $meta['excerpt_limit_custom'] ) );
		$arg['title_link']    = $meta['title_link'];
		$arg['image_link']    = $meta['image_link'];

		if ( ! $fullwidth ) {
			$arg['grid']  .= 'rtsb-col-grid ';
			$arg['class'] .= ' even-grid-item ';
		} else {
			$arg['grid'] .= 'rtsb-col-grid ';
		}

		$arg['class'] .= 'rtsb-category-grid';

		$arg['img_html'] = $meta['c_img'] ? Fns::get_product_image_html(
			'category',
			$query->term_id,
			$meta['f_img_size'],
			$meta['default_img_id'],
			$meta['custom_img_size'],
			$lazy_load
		) : null;

		if ( $meta['show_custom_image'] && ! empty( $meta['custom_image'] ) ) {
			$arg['img_html'] = Fns::get_product_image_html(
				'custom',
				null,
				$meta['f_img_size'],
				$meta['custom_image'],
				$meta['custom_img_size'],
				$lazy_load
			);
		}

		$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' : '' );

		if ( $category_loop ) {
			$query_args = [
				'product_category_id' => $query->term_id,
				'limit'               => -1,
				'order'               => 'DESC',
				'orderby'             => 'date',
			];

			$products_query = new \WC_Product_Query( $query_args );
			$products       = $products_query->get_products();
		}

		return apply_filters( 'rtsb/elementor/render/cat_arg_dataset', $arg, $meta, $query, $fullwidth, $lazy_load, $products );
	}

	/**
	 * Renders add to cart button.
	 *
	 * @param string $link Product link.
	 * @param int    $id Product ID.
	 * @param string $type Product type.
	 * @param string $text Custom text.
	 * @param string $success Success text.
	 * @param string $icon_html Custom icon.
	 * @param string $alignment Icon alignment.
	 *
	 * @return string
	 */
	public function render_add_to_cart_button( $link, $id, $type, $text, $success, $icon_html, $alignment ) {
		$content      = null;
		$tooltip_attr = '';
		$ext_link     = get_post_meta( $id, '_product_url', true );
		$btn_txt      = get_post_meta( $id, '_button_text', true );

		if ( empty( $text ) ) {
			$tooltip_attr = ' title="' . esc_attr__( 'Add to Cart', 'shopbuilder' ) . '"';

			if ( 'variable' === $type ) {
				$tooltip_attr = ' title="' . esc_attr__( 'Select Options', 'shopbuilder' ) . '"';
			}

			if ( 'grouped' === $type ) {
				$tooltip_attr = ' title="' . esc_attr__( 'View Products', 'shopbuilder' ) . '"';
			}

			if ( 'external' === $type ) {
				$tooltip_txt  = ! empty( $btn_txt ) ? esc_html( $btn_txt ) : esc_html__( 'Buy Product', 'shopbuilder' );
				$tooltip_attr = ' title="' . esc_attr( $tooltip_txt ) . '"';
			}
		}

		ob_start();
		do_action( 'rtsb/before/cart/button' );
		$content .= ob_get_clean();

		if ( 'variable' === $type ) {
			$content .= sprintf(
				'<div class="rtsb-wc-add-to-cart-wrap">
					<a href="%1$s" data-quantity="1" class="rtsb-action-btn variable-product tipsy icon-%4$s %5$s" data-product_id="%3$s" rel="nofollow"%6$s>%7$s<span class="text">%2$s</span></a>
				</div>',
				esc_url( $link ),
				esc_html__( 'Select Options', 'shopbuilder' ),
				absint( $id ),
				esc_attr( $alignment ),
				empty( $text ) ? 'no-text' : 'has-text',
				$tooltip_attr,
				$icon_html,
			);
		} elseif ( 'grouped' === $type ) {
			$content .= sprintf(
				'<div class="rtsb-wc-add-to-cart-wrap">
					<a href="%1$s" data-quantity="1" class="rtsb-action-btn variable-product tipsy icon-%4$s %5$s" data-product_id="%3$s" rel="nofollow"%6$s>%7$s<span class="text">%2$s</span></a>
				</div>',
				esc_url( $link ),
				esc_html__( 'View Products', 'shopbuilder' ),
				absint( $id ),
				esc_attr( $alignment ),
				empty( $text ) ? 'no-text' : 'has-text',
				$tooltip_attr,
				$icon_html,
			);
		} elseif ( 'external' === $type ) {
			$content .= sprintf(
				'<div class="rtsb-wc-add-to-cart-wrap">
					<a href="%1$s" data-quantity="1" class="rtsb-action-btn variable-product tipsy icon-%4$s %5$s" data-product_id="%3$s" rel="nofollow"%6$s %8$s>%7$s<span class="text">%2$s</span></a>
				</div>',
				! empty( $ext_link ) ? esc_url( $ext_link ) : esc_url( $link ),
				! empty( $btn_txt ) ? esc_html( $btn_txt ) : esc_html__( 'Buy Product', 'shopbuilder' ),
				absint( $id ),
				esc_attr( $alignment ),
				empty( $text ) ? 'no-text' : 'has-text',
				$tooltip_attr,
				$icon_html,
				! empty( $ext_link ) ? ' target="_blank"' : ''
			);
		} else {
			$content .= sprintf(
				'<a href="%1$s?add-to-cart=%2$d" data-quantity="1" class="rtsb-action-btn rtsb-add-to-cart-btn tipsy icon-%6$s %7$s" data-id="%2$d" data-type="%3$s"%8$s>%4$s<span class="text %10$s" data-success="%9$s">%5$s</span><span></span></a>',
				esc_url( $link ),
				absint( $id ),
				esc_attr( $type ),
				$icon_html,
				esc_html( $text ),
				esc_attr( $alignment ),
				empty( $text ) ? 'no-text' : 'has-text',
				$tooltip_attr,
				esc_html( $success ),
				! empty( $success ) ? 'has-success-text' : 'no-success-text',
			);
		}

		ob_start();
			do_action( 'rtsb/after/cart/button' );
		$content .= ob_get_clean();

		return $content;
	}

	/**
	 * Button classes.
	 *
	 * @param array $params Button params.
	 *
	 * @return array
	 */
	public function button_classes( $params ) {
		$params['classes'] = array_merge( $params['classes'], [ 'rtsb-action-btn', 'tipsy' ] );

		return $params;
	}
}

```
