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