如何为WooCommerce循环加入购物车链接添加自定义类及解决筛选差异
WooCommerce订阅商品按钮添加CSS类的问题排查与修复
问题背景
我们需要修改现有PHP代码,给特定WooCommerce加入购物车按钮添加CSS类ActiveSubscription。原代码可将不可购买商品的循环加入购物车按钮文本改为“Active”,但新增的添加类代码出现筛选不一致问题:原代码能选中3个订阅商品修改文本,新增代码仅选中2个,而“我的账户”页面显示有3个活跃订阅,需排查差异原因。
原功能代码(修改按钮文本)
/** * @snippet Read more > Out of stock @ WooCommerce Shop * @how-to businessbloomer.com/woocommerce-customization * @author Rodolfo Melogli, Business Bloomer * @testedwith WooCommerce 5 * @community https://businessbloomer.com/club/ * See: https://www.businessbloomer.com/woocommerce-rename-read-more-out-of-stock-shop/ */ add_filter( 'woocommerce_product_add_to_cart_text', 'bbloomer_archive_custom_cart_button_text' ); function bbloomer_archive_custom_cart_button_text( $text ) { global $product; if ( $product && ! $product->is_purchasable() ) { /* original example was: ! $product->is_in_stock() */ return 'Active'; } return $text; }
原代码生成的HTML结构
<p class="product woocommerce add_to_cart_inline " style=""> <span class="woocommerce-Price-amount amount"><bdi> <span class="woocommerce-Price-currencySymbol">£</span>0.00</bdi></span> <span class="subscription-details"> for 2 years</span><br> <a href=".../membership/arts-events-marketing-subscription-copy/" aria-describedby="woocommerce_loop_add_to_cart_link_describedby_2242" data-quantity="1" class="button product_type_subscription" data-product_id="2242" data-product_sku="" aria-label="Read more about “Arts Events Marketing Subscription”" rel="nofollow" data-success_message="" data-product_price="0.0" data-product_name="Arts Events Marketing Subscription" data-google_product_id="">Active</a> <span id="woocommerce_loop_add_to_cart_link_describedby_2242" class="screen-reader-text"></span> </p>
修改后的完整代码(尝试添加CSS类)
/** * @snippet Read more > Out of stock @ WooCommerce Shop * @how-to businessbloomer.com/woocommerce-customization * @author Rodolfo Melogli, Business Bloomer * @testedwith WooCommerce 5 * @community https://businessbloomer.com/club/ * See: https://www.businessbloomer.com/woocommerce-rename-read-more-out-of-stock-shop/ */ add_filter( 'woocommerce_product_add_to_cart_text', 'bbloomer_archive_custom_cart_button_text' ); function bbloomer_archive_custom_cart_button_text( $text ) { global $product; if ( $product && ! $product->is_purchasable() ) { /* original example was: ! $product->is_in_stock() */ return 'Active'; } return $text; } /* Also add a class so that custom css can grey-out the button */ add_filter( 'woocommerce_loop_add_to_cart_link', 'filter_loop_add_to_cart_link', 10, 2 ); function filter_loop_add_to_cart_link( $link, $product ) { // Check if the product is part of an active subscription for the current user // if ( wcs_user_has_subscription( get_current_user_id(), $product->get_id(), 'active' ) ) { replaced by line below for (attempted) commonality with function above if ( $product && ! $product->is_purchasable() ) { $link = str_replace('class="button', 'class="button ActiveSubscription', $link); } return $link; }
问题原因分析
- 钩子触发范围差异:
woocommerce_product_add_to_cart_text在所有生成按钮文本的场景下都会触发,全局$product变量稳定;而woocommerce_loop_add_to_cart_link仅在商品循环(商城列表、分类页)中生效,若某个订阅商品通过自定义模板/短码渲染,该钩子不会执行,导致类无法添加。 - 字符串替换的脆弱性:依赖固定的
class="button字符串进行替换,若商品按钮的HTML属性顺序、写法有差异(比如class="button"后紧跟其他类名无空格),替换会失效。 - 状态判断逻辑偏差:
is_purchasable()的判断规则和“我的账户”页面的活跃订阅判断逻辑可能不一致,部分订阅商品虽显示为活跃,但is_purchasable()返回true,导致新增代码未选中。
解决方案
方案1:统一订阅判断逻辑+安全添加类
使用WooCommerce Subscriptions官方函数判断活跃订阅,同时通过DOM解析安全添加类,避免字符串替换的局限性:
add_filter( 'woocommerce_loop_add_to_cart_link', 'filter_loop_add_to_cart_link', 10, 2 ); function filter_loop_add_to_cart_link( $link, $product ) { // 和“我的账户”页面一致的活跃订阅判断 if ( is_user_logged_in() && wcs_user_has_subscription( get_current_user_id(), $product->get_id(), 'active' ) ) { // 解析HTML并添加类 $dom = new DOMDocument(); @$dom->loadHTML(mb_convert_encoding($link, 'HTML-ENTITIES', 'UTF-8')); $aTags = $dom->getElementsByTagName('a'); foreach ($aTags as $tag) { $classes = $tag->hasAttribute('class') ? explode(' ', $tag->getAttribute('class')) : []; $classes[] = 'ActiveSubscription'; $tag->setAttribute('class', implode(' ', array_unique($classes))); } $link = $dom->saveHTML($dom->getElementsByTagName('p')->item(0)); } return $link; }
方案2:同步原文本修改的判断逻辑
如果要和原按钮文本修改逻辑完全对齐,保留is_purchasable()判断,同时改用DOM解析添加类:
add_filter( 'woocommerce_loop_add_to_cart_link', 'custom_add_to_cart_link_with_class', 10, 2 ); function custom_add_to_cart_link_with_class( $link, $product ) { if ( $product && ! $product->is_purchasable() ) { $dom = new DOMDocument(); @$dom->loadHTML(mb_convert_encoding($link, 'HTML-ENTITIES', 'UTF-8')); $aTags = $dom->getElementsByTagName('a'); foreach ($aTags as $tag) { $current_classes = $tag->getAttribute('class'); $tag->setAttribute('class', trim($current_classes . ' ActiveSubscription')); } $link = $dom->saveHTML($dom->getElementsByTagName('p')->item(0)); } return $link; }
方案3:排查未匹配商品的状态
对未被选中的那个商品做单独检查:
- 查看商品编辑页的库存、购买权限设置,确认是否真的
!is_purchasable(); - 检查该商品的按钮是否通过
woocommerce_loop_add_to_cart_link钩子生成,若为自定义模板输出,需单独添加类的逻辑。
内容的提问来源于stack exchange,提问作者user801347
相关产品推荐
相关产品推荐

