WooCommerce:按配送国家禁用特定商品购物车结账按钮及修复问题
问题分析与代码修改方案
你的核心问题出在将提示信息和移除结账按钮的逻辑放在了配置函数中,而这个函数被多个钩子反复调用,导致提示重复出现、全页面显示,且结账按钮的移除时机错误。以下是修正后的完整代码及说明:
修正后的代码
// 仅返回配送配置信息,不执行业务逻辑 function your_country_shipping_settings(){ $results = array(); // true=按商品ID限制,false=按商品分类限制 $results['type'] = false; // 允许配送的国家(仅支持两位字母国家代码) $results['countries'] = array( 'US', 'CA' ); if( $results['type'] ){ // 限制配送的商品ID列表 $results['matching'] = array( 37, 38 ); } else { // 限制配送的商品分类(支持ID、别名、名称) $results['matching'] = array('t-shirts', 'sweet-shirts' ); } // 默认提示文本 $results['message'] = __( "仅支持美国和加拿大地区配送", "woocommerce" ); return $results; } // 工具函数:检查购物车中是否存在受限商品,并返回商品名称列表 function get_items_names( $matching, $package, $type ){ $product_names = array(); foreach( $package['contents'] as $item ){ if( $type ){ if( in_array( $item['data']->get_id(), $matching ) ) $product_names[] = $item['data']->get_name(); } else { if( has_term( $matching, 'product_cat', $item['product_id'] ) ) $product_names[] = $item['data']->get_name(); } } return $product_names; } // 条件禁用配送方式(保留原有逻辑) add_filter('woocommerce_package_rates','custom_country_shipping_rules', 10, 2 ); function custom_country_shipping_rules( $rates, $package ){ if( isset($package['destination']['country']) && isset($package['contents']) ){ $data = your_country_shipping_settings(); // 如果是允许的国家,直接返回原有配送方式 if( in_array( $package['destination']['country'], $data['countries'] ) ) return $rates; $product_names = get_items_names( $data['matching'], $package, $data['type'] ); // 购物车存在受限商品时,移除所有配送方式 if( count($product_names) > 0 ){ foreach( $rates as $rate_id => $rate ) unset( $rates[$rate_id] ); } } return $rates; } // 自定义无配送方式时的提示(保留原有逻辑) add_filter('woocommerce_cart_no_shipping_available_html','custom_country_shipping_notice', 10, 1 ); add_filter('woocommerce_no_shipping_available_html','custom_country_shipping_notice', 10, 1 ); function custom_country_shipping_notice( $html ){ $package = WC()->shipping->get_packages()[0]; if( isset($package['destination']['country']) && isset($package['contents']) ){ $data = your_country_shipping_settings(); // 如果是允许的国家,直接返回原有提示 if( in_array( $package['destination']['country'], $data['countries'] ) ) return $html; $product_names = get_items_names( $data['matching'], $package, $data['type'] ); if( count($product_names) > 0 ){ $text = '"' . implode( '", "', $product_names ) . '" ' . $data['message']; $html = wpautop( $text ); } } return $html; } // 新增:检查购物车并控制结账按钮显示 add_action( 'woocommerce_check_cart_items', 'restrict_self_products_checkout' ); function restrict_self_products_checkout() { // 购物车为空时直接返回 if ( WC()->cart->is_empty() ) return; $data = your_country_shipping_settings(); $package = WC()->shipping->get_packages()[0]; // 如果是允许的国家,不限制结账 if ( isset($package['destination']['country']) && in_array( $package['destination']['country'], $data['countries'] ) ) { return; } $product_names = get_items_names( $data['matching'], $package, $data['type'] ); // 购物车存在受限商品时,显示提示并禁用结账按钮 if ( count($product_names) > 0 ) { wc_add_notice( __( "以下商品仅支持美国和加拿大地区配送:" . implode(', ', $product_names), "woocommerce" ), "error" ); remove_action( 'woocommerce_proceed_to_checkout', 'woocommerce_button_proceed_to_checkout', 20 ); } }
修改说明
分离配置与业务逻辑
把wc_add_notice和remove_action从your_country_shipping_settings()中移除,让这个函数仅返回配置信息,避免因函数被多次调用导致的重复提示和错误动作。新增专用检查钩子
使用woocommerce_check_cart_items钩子专门处理购物车检查逻辑:- 仅在购物车/结账页面触发,解决提示在所有页面显示的问题
- 只有满足「非美加地区+购物车含自营商品」条件时,才显示提示并禁用结账按钮
保留原有配送限制逻辑
原有的禁用配送方式、自定义无配送提示的逻辑不变,确保用户无法选择配送方式的同时,得到明确的错误指引。符合需求的商品可见性
所有商品正常展示,仅限制非目标地区用户的结账流程,符合你「不隐藏自营商品」的要求。
内容的提问来源于stack exchange,提问作者user22944362
相关产品推荐
相关产品推荐

