PluginProbe
ShopBuilder – WooCommerce Builder For Elementor / 3.2.5
ShopBuilder – WooCommerce Builder For Elementor v3.2.5
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 +29 -114 3.4.23.2.5 View file →
@@ -125,14 +125,8 @@
125 125 if ( ! empty( $pagination_attributes ) ) {
126 126 $container_attributes['data-rtsb-ajax'] = $pagination_attributes;
127 127 }
128 128
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 129 // Adding render attributes.
136 130 $this->add_attribute( 'rtsb_container_attr_' . $rand, $container_attributes );
137 131
138 132 // Start rendering.
@@ -468,15 +462,11 @@
468 462 $settings['rtsb_order'] = in_array( $order, [ 'ASC','DESC' ], true ) ? $order : 'ASC';
469 463
470 464 $pagination = $metas['pagination'];
471 465
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;
466 + $page_type = BuilderFns::builder_type( get_the_ID() );
467 + $is_preview = BuilderFns::is_builder_preview() && array_key_exists( $page_type, BuilderFns::builder_page_types() );
468 + $posts_per_page = apply_filters( 'loop_shop_per_page', wc_get_default_products_per_row() * wc_get_default_product_rows_per_page() ); // phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedHooknameFound -- woocommerce default hooks used.
479 469 if ( $is_preview ) {
480 470 $main_query = clone $wp_query;
481 471 $main_post = clone $post;
482 472
@@ -497,30 +487,12 @@
497 487 $wp_query = new WP_Query( $wp_query_args ); // phpcs:ignore WordPress.WP.GlobalVariablesOverride.Prohibited
498 488
499 489 wc_set_loop_prop( 'total', $wp_query->found_posts );
500 490 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 491 }
516 492
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>';
493 + if ( Fns::product_has_applied_filters( 'shop' ) || Fns::product_has_applied_filters( 'archive' ) || 'rtsb_builder' === get_post_type( get_the_ID() ) ) {
494 + echo '<div class="rtsb-active-filters-wrapper"></div>';
523 495 }
524 496
525 497 // column_per_row.
526 498 if ( woocommerce_product_loop() ) {
@@ -530,44 +502,28 @@
530 502 $this->row( $this->wc_product_loop( $wp_query, $metas, $template ), $metas, '', $settings );
531 503 }
532 504
533 505 // Pagination.
534 - $this->html .= '<div class="rtsb-archive-pagination-wrap" data-per-page="' . absint( $posts_per_page ) . '">';
506 + $this->html .= '<div class="rtsb-archive-pagination-wrap">';
535 507
536 508 if ( $pagination ) {
537 509 if ( Fns::product_filters_has_ajax( apply_filters( 'rtsb/builder/set/current/page/type', '' ) ) ) {
538 510 if ( $wp_query->max_num_pages > 1 ) {
539 - $posts_loading_type = ! empty( $metas['posts_loading_type'] ) ? $metas['posts_loading_type'] : 'pagination';
511 + $this->add_attribute(
512 + 'rtsb_load_more_btn_attr_' . $rand,
513 + [
514 + 'data-paged' => '2',
515 + 'data-max-page' => $wp_query->max_num_pages,
516 + ]
517 + );
540 518
541 - if ( 'pagination_ajax' === $posts_loading_type ) {
542 - $this->html .= Fns::custom_pagination( $wp_query->max_num_pages, $posts_per_page, true, $metas['visible_range'] ?? null );
543 - } elseif ( 'pagination' === $posts_loading_type ) {
544 - $this->html .= Fns::custom_pagination( $wp_query->max_num_pages, $posts_per_page, false, $metas['visible_range'] ?? null );
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 - }
519 + $this->html .=
520 + "<div class='rtsb-load-more rtsb-pos-r'>
521 + <button {$this->get_attribute_string( 'rtsb_load_more_btn_attr_' . $rand )}>
522 + <span>" . esc_html__( 'Load More', 'shopbuilder' ) . "</span>
523 + </button>
524 + <div class='rtsb-loadmore-loading rtsb-ball-clip-rotate'><div></div></div>
525 + </div>";
570 526 }
571 527 } else {
572 528 $pagination_args = [
573 529 'query' => $wp_query,
@@ -584,9 +540,9 @@
584 540 } else {
585 541 $this->no_products_msg( $metas );
586 542 }
587 543
588 - if ( $is_preview || ! empty( $restore_query ) ) {
544 + if ( $is_preview ) {
589 545 // phpcs:disable
590 546 $wp_query = $main_query;
591 547 $post = $main_post;
592 548
@@ -594,11 +550,8 @@
594 550 wp_reset_postdata();
595 551 // phpcs:enable
596 552 }
597 553
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 554 // Container.
602 555 $this->container( $this->html, $settings, 'rtsb-products-container', $template );
603 556
604 557 return $this->html;
@@ -652,13 +605,8 @@
652 605 *
653 606 * @return string
654 607 */
655 608 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 609 $this->get_settings = $settings;
662 610
663 611 $metas = RenderHelpers::meta_dataset( $settings, $template, $this->get_settings_for_display() );
664 612 $taxonomy = $metas['category_source'];
@@ -688,9 +636,9 @@
688 636 if ( ! is_wp_error( $taxonomy_query ) && ! empty( $taxonomy_query ) ) {
689 637 // Row.
690 638 $this->row( $this->category_loop( $taxonomy_query, $metas, $template, $is_single ), $metas );
691 639 } else {
692 - $this->html = '<p>' . esc_html__( 'No categories found', 'shopbuilder' ) . '</p>';
640 + $this->html .= '<p>' . esc_html__( 'No categories found', 'shopbuilder' ) . '</p>';
693 641 }
694 642
695 643 // Container.
696 644 $this->container( $this->html, $settings, 'rtsb-categories-container', $is_single );
@@ -1090,26 +1038,8 @@
1090 1038 add_filter( 'rtsb/module/wishlist/button_params', [ $this, 'button_classes' ] );
1091 1039 add_filter( 'rtsb/module/wishlist/icon_html', [ $this, 'wishlist_icon' ] );
1092 1040 }
1093 1041
1094 - // Eager-load the above-the-fold product images so the LCP candidate is
1095 - // fetched immediately instead of being lazy-loaded after render-blocking
1096 - // CSS and layout. Defaults to the mobile viewport row count (Lighthouse
1097 - // scores mobile); eagering below-the-fold images would only steal
1098 - // bandwidth from the visible ones. Filterable per layout.
1099 - $eager_count = (int) apply_filters( 'rtsb/loop/eager_image_count', 6, $meta );
1100 -
1101 - // The mobile LCP is often NOT the first card but the top-right one in a
1102 - // 2-column grid, so the first *row* of images gets fetchpriority=high to
1103 - // promote the real LCP candidate ahead of render-blocking CSS. Kept small
1104 - // (default 2 = one mobile row) to avoid competing high-priority requests.
1105 - $high_count = (int) apply_filters( 'rtsb/loop/fetchpriority_high_count', 2, $meta );
1106 - $img_priority = false;
1107 -
1108 - if ( $i <= $eager_count ) {
1109 - $img_priority = $i <= $high_count ? 'high' : 'eager';
1110 - }
1111 -
1112 1042 $arg['img_html'] = $meta['f_img'] ? Fns::get_product_image_html(
1113 1043 'product',
1114 1044 $post_id,
1115 1045 $meta['f_img_size'],
@@ -1114,13 +1044,9 @@
1114 1044 $post_id,
1115 1045 $meta['f_img_size'],
1116 1046 $meta['default_img_id'],
1117 1047 $meta['custom_img_size'],
1118 - $lazy_load,
1119 - false,
1120 - false,
1121 - 0,
1122 - $img_priority
1048 + $lazy_load
1123 1049 ) : null;
1124 1050
1125 1051 if ( ! ( function_exists( 'rtwpvsp' ) && $product->is_type( 'variable' ) && $product->get_attributes() ) ) {
1126 1052 $gallery_ids = $product->get_gallery_image_ids();
@@ -1227,9 +1153,10 @@
1227 1153 );
1228 1154
1229 1155 $content .= '<a ' . $this->get_attribute_string( 'rtsb_add_to_cart_button_' . $id . $rand ) . '>';
1230 1156 $content .= $icon_html;
1231 - $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>';
1157 + $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>';
1158 + $content .= '<span></span>';
1232 1159 } elseif ( 'external' === $type ) {
1233 1160 if ( ! empty( $ext_link ) ) {
1234 1161 $cart_attr['target'] = '_blank';
1235 1162 }
@@ -1239,9 +1166,9 @@
1239 1166 $this->add_attribute( 'rtsb_add_to_cart_button_' . $id . $rand, $cart_attr );
1240 1167
1241 1168 $content .= '<a ' . $this->get_attribute_string( 'rtsb_add_to_cart_button_' . $id . $rand ) . '>';
1242 1169 $content .= $icon_html;
1243 - $content .= '<span class="button-text text">' . ( ! empty( $btn_txt ) ? esc_html( $btn_txt ) : esc_html__( 'Buy Product', 'shopbuilder' ) ) . '</span>';
1170 + $content .= '<span class="text">' . ( ! empty( $btn_txt ) ? esc_html( $btn_txt ) : esc_html__( 'Buy Product', 'shopbuilder' ) ) . '</span>';
1244 1171 } else {
1245 1172 $cart_attr['href'] = $cart_attr['href'] . '?add-to-cart=' . absint( $id );
1246 1173 $cart_attr['class'] .= ' rtsb-add-to-cart-btn';
1247 1174 $cart_attr['data-type'] = $type;
@@ -1250,9 +1177,10 @@
1250 1177 $this->add_attribute( 'rtsb_add_to_cart_button_' . $id . $rand, $cart_attr );
1251 1178
1252 1179 $content .= '<a ' . $this->get_attribute_string( 'rtsb_add_to_cart_button_' . $id . $rand ) . '>';
1253 1180 $content .= $icon_html;
1254 - $content .= '<span class="button-text text ' . ( ! empty( $success ) ? 'has-success-text' : 'no-success-text' ) . '" data-success="' . esc_html( $success ) . '">' . esc_html( $text ) . '</span>';
1181 + $content .= '<span class="text ' . ( ! empty( $success ) ? 'has-success-text' : 'no-success-text' ) . '" data-success="' . esc_html( $success ) . '">' . esc_html( $text ) . '</span>';
1182 + $content .= '<span></span>';
1255 1183 }
1256 1184
1257 1185 $content .= '</a>';
1258 1186 $content .= '</div>';
@@ -1353,22 +1281,9 @@
1353 1281 if ( 'pagination' === $meta['posts_loading_type'] ) {
1354 1282 if ( $is_grid ) {
1355 1283 $html_utility .= Fns::custom_pagination(
1356 1284 $total_page,
1357 - 'wc' === $query_type ? $per_page : $posts_per_page,
1358 - false,
1359 - $meta['visible_range'] ?? null
1360 - );
1361 - }
1362 - } elseif ( 'pagination_ajax' === $meta['posts_loading_type'] && ! rtsb()->has_pro() ) {
1363 - // Free version fallback: render non-AJAX number pagination so filter
1364 - // params in the URL are preserved via get_pagenum_link().
1365 - if ( $is_grid ) {
1366 - $html_utility .= Fns::custom_pagination(
1367 - $total_page,
1368 - 'wc' === $query_type ? $per_page : $posts_per_page,
1369 - false,
1370 - $meta['visible_range'] ?? null
1285 + 'wc' === $query_type ? $per_page : $posts_per_page
1371 1286 );
1372 1287 }
1373 1288 } else {
1374 1289 ob_start();