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 +35 -109 3.4.13.2.1 View file →
@@ -8,9 +8,8 @@
8 8 */
9 9
10 10 namespace RadiusTheme\SB\Elementor\Render;
11 11
12 -use RadiusTheme\SBPRO\Modules\CatalogMode\CatalogModeFns;
13 12 use WC_Query;
14 13 use WP_Query;
15 14 use WC_Product;
16 15 use Elementor\Utils;
@@ -125,14 +124,8 @@
125 124 if ( ! empty( $pagination_attributes ) ) {
126 125 $container_attributes['data-rtsb-ajax'] = $pagination_attributes;
127 126 }
128 127
129 - // Opt-out of the scroll-to-top behaviour on Ajax filter/pagination when
130 - // the "Enable Scroll To Top?" switch is turned off.
131 - if ( isset( $settings['enable_ajax_scroll'] ) && empty( $settings['enable_ajax_scroll'] ) ) {
132 - $container_attributes['data-rtsb-disable-scroll'] = '1';
133 - }
134 -
135 128 // Adding render attributes.
136 129 $this->add_attribute( 'rtsb_container_attr_' . $rand, $container_attributes );
137 130
138 131 // Start rendering.
@@ -265,9 +258,10 @@
265 258 $layout = RenderHelpers::filter_layout( esc_html( $settings['layout'] ), $template );
266 259
267 260 foreach ( $products as $_product ) {
268 261 $i++;
269 - $GLOBALS['product'] = $_product; // phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedVariableFound -- Global variable is intentionally used to share the current product context with hooks and templates during rendering.
262 + $GLOBALS['product'] = $_product;
263 +
270 264 /**
271 265 * Before product template render hook.
272 266 */
273 267 do_action( 'rtsb_before_product_template_render' );
@@ -285,9 +279,9 @@
285 279
286 280 unset( $GLOBALS['product'] );
287 281 }
288 282 if ( $isGlobalProduct ) {
289 - $GLOBALS['product'] = $isGlobalProduct; // phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedVariableFound -- Global variable is intentionally used to share the current product context with hooks and templates during rendering.
283 + $GLOBALS['product'] = $isGlobalProduct;
290 284 }
291 285 return $html;
292 286 }
293 287
@@ -392,10 +386,10 @@
392 386 * Before Product query hook.
393 387 *
394 388 * @hooked RadiusTheme\SB\Controllers\Hooks\ActionHooks::modify_wc_query_args 10
395 389 */
390 + do_action( 'rtsb/elements/render/before_query', $settings, $args );
396 391
397 - do_action( 'rtsb/elements/render/before_query', $settings, $args );
398 392 // Query.
399 393 $product_query = new WC_Product_Query( $args );
400 394
401 395 /**
@@ -462,21 +456,16 @@
462 456 $this->get_settings = $settings;
463 457 $rand = wp_rand();
464 458 $metas = RenderHelpers::meta_dataset( $settings, $template, $widget->get_settings_for_display() );
465 459
466 - $order = strtoupper( $wp_query->query_vars['order'] ?? 'ASC' );
467 - $settings['rtsb_orderby'] = RenderHelpers::escaping_product_orderby( $wp_query->query_vars['orderby'] ?? 'menu_order' );
468 - $settings['rtsb_order'] = in_array( $order, [ 'ASC','DESC' ], true ) ? $order : 'ASC';
460 + $settings['rtsb_order'] = ! empty( $wp_query->query_vars['order'] ) ? $wp_query->query_vars['order'] : 'ASC';
461 + $settings['rtsb_orderby'] = ! empty( $wp_query->query_vars['orderby'] ) ? $wp_query->query_vars['orderby'] : 'menu_order';
469 462
470 463 $pagination = $metas['pagination'];
471 464
472 - $page_type = BuilderFns::builder_type( get_the_ID() );
473 - $is_preview = BuilderFns::is_builder_preview() && array_key_exists( $page_type, BuilderFns::builder_page_types() );
474 - $raw_settings = $widget->get_settings_for_display();
475 - $widget_per_page = ! empty( $raw_settings['posts_per_page'] ) ? absint( $raw_settings['posts_per_page'] ) : 0;
476 - $wc_per_page = wc_get_default_products_per_row() * wc_get_default_product_rows_per_page();
477 - $posts_per_page = $widget_per_page ? $widget_per_page : apply_filters( 'loop_shop_per_page', $wc_per_page ); // phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedHooknameFound -- woocommerce default hooks used.
478 - $restore_query = false;
465 + $page_type = BuilderFns::builder_type( get_the_ID() );
466 + $is_preview = BuilderFns::is_builder_preview() && array_key_exists( $page_type, BuilderFns::builder_page_types() );
467 + $posts_per_page = apply_filters( 'loop_shop_per_page', wc_get_default_products_per_row() * wc_get_default_product_rows_per_page() );
479 468 if ( $is_preview ) {
480 469 $main_query = clone $wp_query;
481 470 $main_post = clone $post;
482 471
@@ -497,30 +486,12 @@
497 486 $wp_query = new WP_Query( $wp_query_args ); // phpcs:ignore WordPress.WP.GlobalVariablesOverride.Prohibited
498 487
499 488 wc_set_loop_prop( 'total', $wp_query->found_posts );
500 489 wc_set_loop_prop( 'total_pages', $wp_query->max_num_pages );
501 - } elseif ( ! is_admin() && ( is_shop() || is_product_taxonomy() ) && absint( $wp_query->get( 'posts_per_page' ) ) !== $posts_per_page ) {
502 - // Apply widget's posts_per_page to the main query on the live frontend.
503 - $main_query = clone $wp_query;
504 - $main_post = clone $post;
505 -
506 - $query_vars = $wp_query->query_vars;
507 - $query_vars['posts_per_page'] = $posts_per_page;
508 -
509 - $wp_query = new WP_Query( $query_vars ); // phpcs:ignore WordPress.WP.GlobalVariablesOverride.Prohibited
510 -
511 - wc_set_loop_prop( 'total', $wp_query->found_posts );
512 - wc_set_loop_prop( 'total_pages', $wp_query->max_num_pages );
513 -
514 - $restore_query = true;
515 490 }
516 491
517 - if ( rtsb()->has_pro() && ( Fns::product_has_applied_filters( 'shop' ) || Fns::product_has_applied_filters( 'archive' ) || 'rtsb_builder' === get_post_type( get_the_ID() ) ) ) {
518 - $rtsb_active_filters_html = Fns::get_active_filters_html();
519 - $rtsb_wrapper_style = '' !== $rtsb_active_filters_html ? ' style="' . esc_attr( 'display:block;' ) . '"' : '';
520 - echo '<div class="rtsb-active-filters-wrapper"' . $rtsb_wrapper_style . '>'; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- Style value is escaped above.
521 - Fns::print_html( $rtsb_active_filters_html, true );
522 - echo '</div>';
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>';
523 494 }
524 495
525 496 // column_per_row.
526 497 if ( woocommerce_product_loop() ) {
@@ -530,44 +501,28 @@
530 501 $this->row( $this->wc_product_loop( $wp_query, $metas, $template ), $metas, '', $settings );
531 502 }
532 503
533 504 // Pagination.
534 - $this->html .= '<div class="rtsb-archive-pagination-wrap" data-per-page="' . absint( $posts_per_page ) . '">';
505 + $this->html .= '<div class="rtsb-archive-pagination-wrap">';
535 506
536 507 if ( $pagination ) {
537 508 if ( Fns::product_filters_has_ajax( apply_filters( 'rtsb/builder/set/current/page/type', '' ) ) ) {
538 509 if ( $wp_query->max_num_pages > 1 ) {
539 - $posts_loading_type = ! empty( $metas['posts_loading_type'] ) ? $metas['posts_loading_type'] : 'pagination';
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 + );
540 517
541 - if ( 'pagination_ajax' === $posts_loading_type ) {
542 - $this->html .= Fns::custom_pagination( $wp_query->max_num_pages, $posts_per_page, true );
543 - } elseif ( 'pagination' === $posts_loading_type ) {
544 - $this->html .= Fns::custom_pagination( $wp_query->max_num_pages, $posts_per_page, false );
545 - } elseif ( 'load_on_scroll' === $posts_loading_type ) {
546 - $this->html .= "<div class='rtsb-infinite-scroll' data-trigger='1' data-paged='2' data-max-page='{$wp_query->max_num_pages}'>
547 - <div class='rtsb-infinite-action'>
548 - <div class='rtsb-loadmore-loading rtsb-ball-clip-rotate'><div></div></div>
549 - </div>
550 - </div>";
551 - } else {
552 - $load_more_text = ! empty( $metas['load_more_text'] ) ? $metas['load_more_text'] : esc_html__( 'Load More', 'shopbuilder' );
553 -
554 - $this->add_attribute(
555 - 'rtsb_load_more_btn_attr_' . $rand,
556 - [
557 - 'data-paged' => '2',
558 - 'data-max-page' => $wp_query->max_num_pages,
559 - ]
560 - );
561 -
562 - $this->html .=
563 - "<div class='rtsb-load-more rtsb-pos-r'>
564 - <button {$this->get_attribute_string( 'rtsb_load_more_btn_attr_' . $rand )}>
565 - <span>" . esc_html( $load_more_text ) . "</span>
566 - </button>
567 - <div class='rtsb-loadmore-loading rtsb-ball-clip-rotate'><div></div></div>
568 - </div>";
569 - }
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>";
570 525 }
571 526 } else {
572 527 $pagination_args = [
573 528 'query' => $wp_query,
@@ -584,9 +539,9 @@
584 539 } else {
585 540 $this->no_products_msg( $metas );
586 541 }
587 542
588 - if ( $is_preview || ! empty( $restore_query ) ) {
543 + if ( $is_preview ) {
589 544 // phpcs:disable
590 545 $wp_query = $main_query;
591 546 $post = $main_post;
592 547
@@ -594,11 +549,8 @@
594 549 wp_reset_postdata();
595 550 // phpcs:enable
596 551 }
597 552
598 - // Ensure the container's data-rtsb-ajax uses the same posts_per_page as the initial render.
599 - $settings['pagination_per_page'] = $posts_per_page;
600 -
601 553 // Container.
602 554 $this->container( $this->html, $settings, 'rtsb-products-container', $template );
603 555
604 556 return $this->html;
@@ -652,13 +604,8 @@
652 604 *
653 605 * @return string
654 606 */
655 607 public function category_view( $template, $settings, $is_single = false ) {
656 - // Reset the shared singleton's html buffer so leftover markup from a
657 - // previously rendered widget (e.g. a products grid that ran earlier
658 - // in the same request) doesn't get folded into the categories
659 - // container by container() below.
660 - $this->html = '';
661 608 $this->get_settings = $settings;
662 609
663 610 $metas = RenderHelpers::meta_dataset( $settings, $template, $this->get_settings_for_display() );
664 611 $taxonomy = $metas['category_source'];
@@ -688,9 +635,9 @@
688 635 if ( ! is_wp_error( $taxonomy_query ) && ! empty( $taxonomy_query ) ) {
689 636 // Row.
690 637 $this->row( $this->category_loop( $taxonomy_query, $metas, $template, $is_single ), $metas );
691 638 } else {
692 - $this->html = '<p>' . esc_html__( 'No categories found', 'shopbuilder' ) . '</p>';
639 + $this->html .= '<p>' . esc_html__( 'No categories found', 'shopbuilder' ) . '</p>';
693 640 }
694 641
695 642 // Container.
696 643 $this->container( $this->html, $settings, 'rtsb-categories-container', $is_single );
@@ -779,9 +726,9 @@
779 726
780 727 global $product;
781 728
782 729 if ( ! $product instanceof WC_Product && $post_id ) {
783 - $product = wc_get_product( $post_id ); // phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedVariableFound -- Global variable is intentionally used to share the current product context with hooks and templates during rendering.
730 + $product = wc_get_product( $post_id );
784 731 }
785 732
786 733 $post_id = $product->get_id();
787 734 $arg = $this->build_product_arg(
@@ -1058,23 +1005,8 @@
1058 1005 ]
1059 1006 );
1060 1007 }
1061 1008 }
1062 - if ( Fns::is_catalog_mode() && empty( $arg['add_to_cart'] ) ) {
1063 - if ( ! empty( $meta['add_to_cart_icon'] ) ) {
1064 - $cart_icon_html = Fns::icons_manager( $meta['add_to_cart_icon'], 'cart-icon' );
1065 - }
1066 - $cart_icon = ! empty( $cart_icon_html ) ? '<span class="icon">' . $cart_icon_html . '</span>' : '';
1067 - $arg['add_to_cart'] = CatalogModeFns::render_elementor_widget_catalog_mode_button(
1068 - [
1069 - 'id' => $post_id,
1070 - 'type' => $p_type,
1071 - 'text' => $meta['add_to_cart_text'],
1072 - 'icon_html' => $cart_icon,
1073 - 'alignment' => $meta['add_to_cart_alignment'],
1074 - ]
1075 - );
1076 - }
1077 1009 }
1078 1010
1079 1011 if ( in_array( 'quick_view', $meta['visibility'], true ) ) {
1080 1012 add_filter( 'rtsb/module/quick_view/button_params', [ $this, 'button_classes' ] );
@@ -1139,8 +1071,9 @@
1139 1071 ];
1140 1072
1141 1073 return $arg;
1142 1074 }
1075 +
1143 1076 /**
1144 1077 * Renders add to cart button.
1145 1078 *
1146 1079 * @param array $args Cart args.
@@ -1205,9 +1138,10 @@
1205 1138 );
1206 1139
1207 1140 $content .= '<a ' . $this->get_attribute_string( 'rtsb_add_to_cart_button_' . $id . $rand ) . '>';
1208 1141 $content .= $icon_html;
1209 - $content .= '<span class="button-text 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>';
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>';
1210 1144 } elseif ( 'external' === $type ) {
1211 1145 if ( ! empty( $ext_link ) ) {
1212 1146 $cart_attr['target'] = '_blank';
1213 1147 }
@@ -1217,9 +1151,9 @@
1217 1151 $this->add_attribute( 'rtsb_add_to_cart_button_' . $id . $rand, $cart_attr );
1218 1152
1219 1153 $content .= '<a ' . $this->get_attribute_string( 'rtsb_add_to_cart_button_' . $id . $rand ) . '>';
1220 1154 $content .= $icon_html;
1221 - $content .= '<span class="button-text text">' . ( ! empty( $btn_txt ) ? esc_html( $btn_txt ) : esc_html__( 'Buy Product', 'shopbuilder' ) ) . '</span>';
1155 + $content .= '<span class="text">' . ( ! empty( $btn_txt ) ? esc_html( $btn_txt ) : esc_html__( 'Buy Product', 'shopbuilder' ) ) . '</span>';
1222 1156 } else {
1223 1157 $cart_attr['href'] = $cart_attr['href'] . '?add-to-cart=' . absint( $id );
1224 1158 $cart_attr['class'] .= ' rtsb-add-to-cart-btn';
1225 1159 $cart_attr['data-type'] = $type;
@@ -1228,9 +1162,10 @@
1228 1162 $this->add_attribute( 'rtsb_add_to_cart_button_' . $id . $rand, $cart_attr );
1229 1163
1230 1164 $content .= '<a ' . $this->get_attribute_string( 'rtsb_add_to_cart_button_' . $id . $rand ) . '>';
1231 1165 $content .= $icon_html;
1232 - $content .= '<span class="button-text text ' . ( ! empty( $success ) ? 'has-success-text' : 'no-success-text' ) . '" data-success="' . esc_html( $success ) . '">' . esc_html( $text ) . '</span>';
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>';
1233 1168 }
1234 1169
1235 1170 $content .= '</a>';
1236 1171 $content .= '</div>';
@@ -1328,17 +1263,8 @@
1328 1263 'ajax' => $ajax,
1329 1264 ];
1330 1265
1331 1266 if ( 'pagination' === $meta['posts_loading_type'] ) {
1332 - if ( $is_grid ) {
1333 - $html_utility .= Fns::custom_pagination(
1334 - $total_page,
1335 - 'wc' === $query_type ? $per_page : $posts_per_page
1336 - );
1337 - }
1338 - } elseif ( 'pagination_ajax' === $meta['posts_loading_type'] && ! rtsb()->has_pro() ) {
1339 - // Free version fallback: render non-AJAX number pagination so filter
1340 - // params in the URL are preserved via get_pagenum_link().
1341 1267 if ( $is_grid ) {
1342 1268 $html_utility .= Fns::custom_pagination(
1343 1269 $total_page,
1344 1270 'wc' === $query_type ? $per_page : $posts_per_page