PluginProbe
ShopBuilder – WooCommerce Builder For Elementor / 3.1.3
ShopBuilder – WooCommerce Builder For Elementor v3.1.3
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 +170 -30 2.1.93.1.3 View file →
@@ -85,9 +85,10 @@
85 85 public function container( $content, $settings, $class = '', $template = '', $fullwidth = false, $ajax = true ) {
86 86 $rand = wp_rand();
87 87 $layout_id = 'rtsb-container-' . $rand;
88 88 $metas = RenderHelpers::meta_dataset( $settings, $template );
89 - $layout = $metas['layout'];
89 + $raw_layout = esc_html( $metas['layout'] );
90 + $layout = RenderHelpers::filter_layout( $raw_layout, $template );
90 91 $style_attr = '--rtsb-default-columns: ' . esc_attr( RenderHelpers::default_columns( $layout ) );
91 92 $view_mode = $settings['view_mode'] ?? 'grid';
92 93 $view_mode = isset( $_GET['displayview'] ) ? sanitize_text_field( wp_unslash( $_GET['displayview'] ) ) : $view_mode; // phpcs:ignore WordPress.Security.NonceVerification.Recommended
93 94 $tooltip_attr = 'list' == $view_mode && ! empty( $metas['tooltip_position_list'] ) ? esc_attr( $metas['tooltip_position_list'] ) : $metas['tooltip_position'];
@@ -92,8 +93,9 @@
92 93 $view_mode = isset( $_GET['displayview'] ) ? sanitize_text_field( wp_unslash( $_GET['displayview'] ) ) : $view_mode; // phpcs:ignore WordPress.Security.NonceVerification.Recommended
93 94 $tooltip_attr = 'list' == $view_mode && ! empty( $metas['tooltip_position_list'] ) ? esc_attr( $metas['tooltip_position_list'] ) : $metas['tooltip_position'];
94 95 $has_pro = rtsb()->has_pro();
95 96 $has_filters = $has_pro && ! empty( $settings['tax_filter'] );
97 + $grid_style = $settings['grid_style'] ?? 'even';
96 98
97 99 // Set default layout.
98 100 if ( ! $has_pro && ! in_array( $layout, array_keys( Fns::free_layouts() ), true ) ) {
99 101 $layout = RenderHelpers::set_default_layout( $layout );
@@ -98,8 +100,13 @@
98 100 if ( ! $has_pro && ! in_array( $layout, array_keys( Fns::free_layouts() ), true ) ) {
99 101 $layout = RenderHelpers::set_default_layout( $layout );
100 102 }
101 103
104 + if ( $has_pro && 'masonry' === $grid_style ) {
105 + $style_attr .= '; --rtsb-masonry-columns: ' . esc_attr( RenderHelpers::default_columns( $layout ) );
106 + $style_attr .= '; --rtsb-masonry-list-columns: ' . esc_attr( RenderHelpers::default_columns( $layout ) );
107 + }
108 +
102 109 // Container classes.
103 110 $container_classes = RenderHelpers::prepare_container_classes( $metas, $settings, $class );
104 111
105 112 // Pagination attributes.
@@ -108,9 +115,9 @@
108 115 // Attributes for the container.
109 116 $container_attributes = [
110 117 'id' => $layout_id,
111 118 'class' => $container_classes,
112 - 'style' => $style_attr,
119 + 'style' => apply_filters( 'rtsb/product/container/attr', $style_attr, $settings ),
113 120 'data-layout' => $layout,
114 121 'data-tooltip-position' => $tooltip_attr,
115 122 ];
116 123
@@ -140,8 +147,9 @@
140 147 $script_generator = [];
141 148 $script_generator['layout'] = $layout_id;
142 149 $script_generator['rand'] = absint( $rand );
143 150 $script_generator['isCarousel'] = preg_match( '/slider/', $layout );
151 + $script_generator['isMasonry'] = $has_pro && 'masonry' === $grid_style;
144 152
145 153 // Register scripts in the wp_footer action.
146 154 add_action(
147 155 'wp_footer',
@@ -163,13 +171,15 @@
163 171 *
164 172 * @return string
165 173 */
166 174 public function row( $content, $settings, $hook_html = '', $raw_settings = [] ) {
167 - $layout = $settings['layout'];
175 + $raw_layout = esc_html( $settings['layout'] );
176 + $layout = RenderHelpers::filter_layout( $raw_layout );
177 +
168 178 $rand = wp_rand();
169 - $is_carousel = preg_match( '/slider/', $layout );
179 + $is_carousel = preg_match( '/slider/', $raw_layout );
170 180
171 - if ( preg_match( '/category/', $layout ) && ( ! empty( $settings['active_cat_slider'] ) ) ) {
181 + if ( preg_match( '/category/', $raw_layout ) && ( ! empty( $settings['active_cat_slider'] ) ) ) {
172 182 $is_carousel = true;
173 183 }
174 184
175 185 // Row classes.
@@ -185,9 +195,8 @@
185 195 $this->html = ! empty( $settings['show_filter'] ) ? $hook_html . $start_wrapper : $start_wrapper;
186 196
187 197 if ( $is_carousel ) {
188 198 $slider_data = RenderHelpers::slider_data( $settings, $raw_settings );
189 -
190 199 // Adding slider render attributes.
191 200 $this->add_attribute(
192 201 'rtsb_slider_attr_' . $rand,
193 202 [
@@ -237,11 +246,21 @@
237 246 }
238 247
239 248 $i = 0;
240 249
241 - foreach ( $products as $product ) {
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 ) {
242 261 $i++;
243 - $GLOBALS['product'] = $product;
262 + $GLOBALS['product'] = $_product;
244 263
245 264 /**
246 265 * Before product template render hook.
247 266 */
@@ -247,12 +266,12 @@
247 266 */
248 267 do_action( 'rtsb_before_product_template_render' );
249 268
250 269 // Loop arg.
251 - $arg = $this->arg_dataset( $settings, $product, $settings['lazy_load'], $i );
270 + $arg = $this->arg_dataset( $settings, $_product, $settings['lazy_load'], $i );
252 271
253 272 // Get template.
254 - $html .= Fns::load_template( $template . $settings['layout'], $arg, true );
273 + $html .= Fns::load_template( $template . $layout, $arg, true );
255 274
256 275 /**
257 276 * After product template render hook.
258 277 */
@@ -259,9 +278,11 @@
259 278 do_action( 'rtsb_after_product_template_render' );
260 279
261 280 unset( $GLOBALS['product'] );
262 281 }
263 -
282 + if ( $isGlobalProduct ) {
283 + $GLOBALS['product'] = $isGlobalProduct;
284 + }
264 285 return $html;
265 286 }
266 287
267 288 /**
@@ -279,19 +300,20 @@
279 300 if ( empty( $query ) ) {
280 301 return null;
281 302 }
282 303
283 - $i = 0;
304 + $i = 0;
305 + $layout = RenderHelpers::filter_layout( esc_html( $settings['layout'] ), $template );
284 306
285 307 while ( $query->have_posts() ) {
286 308 $query->the_post();
287 309 $i++;
288 -
310 + global $product;
289 311 // Loop arg.
290 - $arg = $this->arg_dataset( $settings, wc_get_product( get_the_ID() ), $settings['lazy_load'], $i );
312 + $arg = $this->arg_dataset( $settings, $product, $settings['lazy_load'], $i );
291 313
292 314 // Get template.
293 - $html .= Fns::load_template( $template . $settings['layout'], $arg, true );
315 + $html .= Fns::load_template( $template . $layout, $arg, true );
294 316 }
295 317
296 318 return $html;
297 319 }
@@ -368,10 +390,16 @@
368 390 do_action( 'rtsb/elements/render/before_query', $settings, $args );
369 391
370 392 // Query.
371 393 $product_query = new WC_Product_Query( $args );
372 - $products = $pagination ? $product_query->get_products()->products : $product_query->get_products();
373 394
395 + /**
396 + * Product query hook.
397 + */
398 + do_action( 'rtsb/elements/render/product_query', $product_query, $this );
399 +
400 + $products = $pagination ? $product_query->get_products()->products : $product_query->get_products();
401 +
374 402 if ( ! empty( $products ) ) {
375 403 // Start rendering.
376 404 $hook_html .= $this->render_start( $metas, $settings, $temp_args );
377 405
@@ -435,10 +463,9 @@
435 463 $pagination = $metas['pagination'];
436 464
437 465 $page_type = BuilderFns::builder_type( get_the_ID() );
438 466 $is_preview = BuilderFns::is_builder_preview() && array_key_exists( $page_type, BuilderFns::builder_page_types() );
439 - $posts_per_page = wc_get_default_products_per_row() * wc_get_default_product_rows_per_page();
440 -
467 + $posts_per_page = apply_filters( 'loop_shop_per_page', wc_get_default_products_per_row() * wc_get_default_product_rows_per_page() );
441 468 if ( $is_preview ) {
442 469 $main_query = clone $wp_query;
443 470 $main_post = clone $post;
444 471
@@ -586,8 +613,11 @@
586 613
587 614 if ( rtsb()->has_pro() && ( ! empty( $metas['tag_term'] ) ) ) {
588 615 $term = $metas['tag_term'];
589 616 }
617 + if ( rtsb()->has_pro() && ( ! empty( $metas['brand_term'] ) ) ) {
618 + $term = $metas['brand_term'];
619 + }
590 620
591 621 // Query.
592 622 if ( $is_single ) {
593 623 if ( empty( $term ) ) {
@@ -688,8 +718,9 @@
688 718 *
689 719 * @return array
690 720 */
691 721 public function wp_arg_dataset( array $meta, int $post_id, bool $lazy_load = false, $i = 0 ) {
722 + // phpcs:ignore WordPress.PHP.StrictInArray.MissingTrueStrict
692 723 if ( ( empty( $meta ) && ! $post_id ) || ! in_array( get_post_type( $post_id ), [ 'product_variation', 'product' ] ) ) {
693 724 return [];
694 725 }
695 726
@@ -788,9 +819,13 @@
788 819 $arg['image_link'] = $meta['image_link'];
789 820 $arg['grid'] .= 'rtsb-col-grid ';
790 821
791 822 if ( ! $fullwidth ) {
792 - $arg['class'] .= ' even-grid-item ';
823 + if ( 'masonry' === $meta['grid_type'] ) {
824 + $arg['class'] .= 'masonry-grid-item ';
825 + } else {
826 + $arg['class'] .= 'even-grid-item ';
827 + }
793 828 }
794 829
795 830 if ( ! empty( $meta['active_cat_slider'] ) ) {
796 831 $arg['class'] .= ' rtsb-slide-item swiper-slide animated rtFadeIn ';
@@ -864,8 +899,9 @@
864 899 $arg['anchor_class'] = null;
865 900 $arg['hover_img_html'] = null;
866 901 $arg['s_link'] = [];
867 902 $arg['add_to_cart'] = '';
903 + $arg['p_counter'] = absint( $i );
868 904 $arg['p_id'] = $post_id;
869 905 $arg['product'] = $product;
870 906 $arg['p_link'] = $product->get_permalink();
871 907 $arg['p_sale'] = '';
@@ -896,10 +932,15 @@
896 932 $is_list = preg_match( '/list/', $layout );
897 933 $is_carousel = preg_match( '/slider/', $layout );
898 934
899 935 if ( ! $is_carousel ) {
900 - $arg['grid'] .= 'rtsb-col-grid ';
901 - $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 + }
902 943 } else {
903 944 $arg['grid'] .= 'rtsb-col-grid rtsb-col-full rtsb-slide-item swiper-slide ';
904 945 }
905 946
@@ -930,8 +971,10 @@
930 971 }
931 972
932 973 $arg['badge_class'] = RenderHelpers::badge_class( $meta['badge_preset'] );
933 974
975 + $meta['add_to_cart_text'] = apply_filters( 'rtsb/elementor/render/add_to_cart_text', $meta['add_to_cart_text'], $product );
976 +
934 977 if ( ! $meta['show_cart_text'] ) {
935 978 $meta['add_to_cart_text'] = '';
936 979 $meta['add_to_cart_success_text'] = '';
937 980 }
@@ -957,8 +1000,9 @@
957 1000 'text' => $meta['add_to_cart_text'],
958 1001 'success' => $meta['add_to_cart_success_text'],
959 1002 'icon_html' => $cart_icon,
960 1003 'alignment' => $meta['add_to_cart_alignment'],
1004 + 'product' => $product,
961 1005 ]
962 1006 );
963 1007 }
964 1008 }
@@ -1043,9 +1087,10 @@
1043 1087 'type' => $type,
1044 1088 'text' => $text,
1045 1089 'success' => $success,
1046 1090 'icon_html' => $icon_html,
1047 - 'alignment' => $alignment
1091 + 'alignment' => $alignment,
1092 + 'product' => $product
1048 1093 ) = $args;
1049 1094
1050 1095 $content = null;
1051 1096 $rand = wp_rand();
@@ -1058,9 +1103,8 @@
1058 1103
1059 1104 $cart_attr = [
1060 1105 'class' => 'rtsb-action-btn ' . $type . '-product tipsy icon-' . $alignment . ' ' . ( empty( $text ) ? 'no-text' : 'has-text' ),
1061 1106 'href' => esc_url( $link ),
1062 - 'rel' => 'nofollow',
1063 1107 'data-quantity' => '1',
1064 1108 'data-product_id' => absint( $id ),
1065 1109 'data-id' => absint( $id ),
1066 1110 ];
@@ -1066,12 +1110,13 @@
1066 1110 ];
1067 1111
1068 1112 if ( empty( $text ) ) {
1069 1113 $tooltip_mapping = [
1070 - 'simple' => esc_attr__( 'Add to Cart', 'shopbuilder' ),
1071 - 'variable' => esc_attr__( 'Select Options', 'shopbuilder' ),
1072 - 'grouped' => esc_attr__( 'View Products', 'shopbuilder' ),
1073 - 'external' => ! empty( $btn_txt ) ? esc_html( $btn_txt ) : esc_html__( 'Buy Product', 'shopbuilder' ),
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' ),
1074 1119 ];
1075 1120
1076 1121 $cart_attr['title'] = $tooltip_mapping[ $type ];
1077 1122 }
@@ -1076,13 +1121,22 @@
1076 1121 $cart_attr['title'] = $tooltip_mapping[ $type ];
1077 1122 }
1078 1123
1079 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 ';
1127 + }
1128 + if ( 'variable' === $type || 'grouped' === $type ) {
1129 + $cart_attr = apply_filters( 'rtsb/elementor/render/cart_attributes', $cart_attr, $product );
1080 1130
1081 - if ( 'variable' === $type || 'grouped' === $type ) {
1082 1131 $this->add_attribute( 'rtsb_add_to_cart_button_' . $id . $rand, $cart_attr );
1083 1132
1084 - $text_btn = 'grouped' === $type ? __( 'View Products', 'shopbuilder' ) : __( 'Select Options', 'shopbuilder' );
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 + );
1085 1139
1086 1140 $content .= '<a ' . $this->get_attribute_string( 'rtsb_add_to_cart_button_' . $id . $rand ) . '>';
1087 1141 $content .= $icon_html;
1088 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>';
@@ -1102,8 +1156,9 @@
1102 1156 } else {
1103 1157 $cart_attr['href'] = $cart_attr['href'] . '?add-to-cart=' . absint( $id );
1104 1158 $cart_attr['class'] .= ' rtsb-add-to-cart-btn';
1105 1159 $cart_attr['data-type'] = $type;
1160 + $cart_attr = apply_filters( 'rtsb/elementor/render/cart_attributes', $cart_attr, $product );
1106 1161
1107 1162 $this->add_attribute( 'rtsb_add_to_cart_button_' . $id . $rand, $cart_attr );
1108 1163
1109 1164 $content .= '<a ' . $this->get_attribute_string( 'rtsb_add_to_cart_button_' . $id . $rand ) . '>';
@@ -1371,8 +1426,46 @@
1371 1426 return $this;
1372 1427 }
1373 1428
1374 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;
1465 + }
1466 +
1467 + /**
1375 1468 * Get render attribute string.
1376 1469 *
1377 1470 * @param string $element The element.
1378 1471 *
@@ -1382,7 +1475,54 @@
1382 1475 if ( empty( $this->attributes[ $element ] ) ) {
1383 1476 return '';
1384 1477 }
1385 1478
1386 - return Utils::render_html_attributes( $this->attributes[ $element ] );
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 );
1387 1527 }
1388 1528 }