在本教程中,我将为大家展示如何在 WooCommerce 产品列表页面上创建自己的变体下拉菜单。当我说 “创建自己的 “时,我是认真的,所以我们不只是复制和粘贴单个产品页面上的几个钩子。
我们的另一个目标是确保AJAX 添加到购物车按钮也能很好地应用于我们的自定义变体下拉菜单。
下面的截图中展示了本指南中要创建的内容:
首先,我们需要修改按钮的 HTML 输出
现在是代码时间,我们需要使用woocommerce_loop_add_too_cart_link
Hook,因为它可以删除和修改 「选择选项」 按钮为我们需要的效果,同时,当产品为简单商品时,直接原样返回 「添加到购物车」按钮 。
add_filter( 'woocommerce_loop_add_to_cart_link', 'wprs_select_variations_shop_page', 99, 2 );
function wprs_select_variations_shop_page( $add_to_cart, $product ) {
// 如果不是可变产品则不做任何事
if( ! $product->is_type( 'variable' ) ) {
return $add_to_cart;
}
// 如果没有可供购买的变体,也不执行任何操作
if( ! $variations = $product->get_available_variations() ) {
return $add_to_cart;
}
ob_start();
?>
<div class="wprs_variations" data-product_variations="<?php echo wc_esc_json( wp_json_encode( $variations ) ) ?>">
<?php
foreach( $product->get_attributes() as $attribute_name => $attribute ) :
?>
<div class="wprs-variation-select value">
<?php
wc_dropdown_variation_attribute_options(
array(
'show_option_none' => 'Select ' . strtolower( wc_attribute_label( $attribute_name ) ),
'options' => $attribute->get_slugs(),
'attribute' => $attribute_name,
'product' => $product
)
);
?>
</div>
<?php
endforeach;
?>
<a href="" data-product_id="" class="disabled button add_to_cart_button">Add to cart</a>
</div>
<?php
return ob_get_clean();
}
- 第一步,我们将
$product->get_available_variations()
的整个值存储在一个 HTML 属性中,就像 WooCommerce 在单个产品页面上所做的那样,如果需要,我们可以简化它,因为我们只需要attributes
,variation_id
,price_html
respond in singingimage
对象属性。 - 之所以需要
ob_start()
respond in singingob_end
_clean
()
,是因为我们必须向woocommerce_loop_add_too_cart_link
过滤器钩子返回(而不是打印)值,但里面使用的函数wc_dropdown_variation_attribute_options()
总是会打印下拉菜单。 - 最后,您可以看到一个不带
data-product_id
属性和ajax_add_too_cart
类的 AJAX 添加到购物车按钮。
第二部,我们需要用 JS 实现 Ajax 添加到购物车功能
第一部中,我们只是通过 PHP 输出了我们需要的二 HTML 结构,我们还需要一些 JavaScript,才能实现完整的交互功能。
jQuery( function( $ ) {
$( '.rudr-variation-select' ).find( 'select[data-attribute_name]' ).change( function() {
const el = $(this);
const variationsWrapper = el.closest( '.wprs_variations' );
const availableVariations = JSON.parse( variationsWrapper.attr( 'data-product_variations' ) );
const productWrapper = variationsWrapper.closest( 'li.product' );
const button = productWrapper.find( 'a.add_to_cart_button' );
// 我们的匹配变体将存储在这个对象中
let matchingVariation = {};
// 现在我们可以循环遍历所有变体,并根据所选属性进行检查
for( let i = 0; i < availableVariations.length; i++ ) {
// assign it as a matching variation in any case
matchingVariation = availableVariations[i];
// 让我们检查一下这个变体的所有属性
for( const [ attr_name, attr_value ] of Object.entries( availableVariations[i].attributes ) ) {
// 如果任何属性不匹配
if( attr_value !== variationsWrapper.find( '[name="' + attr_name + '"]' ).val() ) {
matchingVariation = {};
}
}
// 如果有匹配的变体,则退出循环
if( Object.keys( matchingVariation ).length !== 0 ) {
break;
}
}
// 将变体 ID 添加到“添加到购物车”按钮
if( matchingVariation.variation_id ) {
button.removeClass( 'disabled' ).addClass( 'ajax_add_to_cart' );
button.attr( 'data-product_id', matchingVariation.variation_id );
}
// 更新产品价格
if( matchingVariation.price_html ) {
productWrapper.find( 'span.price').replaceWith( matchingVariation.price_html );
}
// 更新产品图片
if( matchingVariation.image ) {
productWrapper.find( 'img' ).attr( {
src: matchingVariation.image.src,
srcset: matchingVariation.image.srcset,
width: matchingVariation.image.src_w,
height: matchingVariation.image.src_h
} );
}
} );
} );
如果你很需要在产品列表中显示分类下拉菜单功能,但是你的主题不支持,又不方便更换主题,那么你可以参考本文中的代码在你的现有主题中实现这一功能。所需的代码量不多,相信大家都可以实现。如有疑问,欢迎在评论中提出,我将和大家一起探讨。