You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

WordPress中WooCommerce全局变量传递与条件隐藏配送方法问题

解决WooCommerce中全局变量无法跨钩子传递的问题

你遇到的核心问题是全局变量在WooCommerce的钩子执行流程里不可靠——woocommerce_before_cart只在购物车页面首次加载时触发,而结账页、AJAX更新购物车场景下这个钩子不会运行,导致$shipping变量没被正确初始化;另外全局变量在独立请求(比如AJAX)里无法保留值,这也是拿不到正确值的关键原因。

修复方案:移除全局变量,直接在配送方法钩子中实时检测购物车

最稳妥的做法是把商品类别的检测逻辑封装成可复用函数,然后在hide_shipping_method_based_on_shipping_method里直接调用它,这样不管在购物车页、结账页还是AJAX更新时,都能实时获取当前购物车的状态。

修改后的完整代码如下:

// 封装购物车商品类别检测的复用函数
function check_cart_target_categories() {
    $hasOfficePack = false;
    $hasSundayCombo = false;
    $officePack = array('office pack', '77'); // 类别slug或ID
    $sundayCombo = array('sunday combo', '85');

    // 遍历购物车所有商品
    foreach ( WC()->cart->get_cart() as $cart_item ) {
        if ( has_term( $officePack, 'product_cat', $cart_item['product_id'] ) ) {
            $hasOfficePack = true;
        }
        if ( has_term( $sundayCombo, 'product_cat', $cart_item['product_id'] ) ) {
            $hasSundayCombo = true;
        }
    }

    // 返回对应的标识(如果同时存在两类商品,这里可按需调整优先级)
    if ( $hasSundayCombo ) {
        return 1;
    } elseif ( $hasOfficePack ) {
        return 0;
    }
    // 无匹配类别时返回null
    return null;
}

add_filter( 'woocommerce_package_rates', 'hide_shipping_method_based_on_cart', 20, 2 );
function hide_shipping_method_based_on_cart( $rates, $package ) {
    // 后台非AJAX请求直接返回原配送方法
    if ( is_admin() && ! defined( 'DOING_AJAX' ) ) return $rates;

    // 获取当前购物车的类别检测结果
    $shipping_flag = check_cart_target_categories();

    // 根据检测结果设置要隐藏的配送方法
    $method_key_ids = array();
    if ( $shipping_flag == 0 ) {
        $method_key_ids = array('flat_rate:2', 'free_shipping:8', 'flat_rate:9');
    } elseif( $shipping_flag == 1 ) {
        $method_key_ids = array('flat_rate:2', 'flat_rate:9');
    }

    // 移除指定配送方法(先检查是否存在,避免PHP警告)
    foreach( $method_key_ids as $method_key_id ){
        if ( isset( $rates[$method_key_id] ) ) {
            unset($rates[$method_key_id]);
        }
    }

    return $rates;
}

关键改进点:

  • 移除全局变量依赖:不再靠woocommerce_before_cart钩子设置全局变量,而是在需要使用的地方实时检测购物车,彻底避免钩子执行顺序和跨请求的问题。
  • 复用检测逻辑:把类别检测抽成单独函数,后续如果需要在其他场景(比如购物车提示、结账页通知)使用,直接调用即可。
  • 调整钩子优先级:把woocommerce_package_rates的优先级从1改为20,确保在其他可能修改购物车的钩子执行完成后,再处理配送方法隐藏,保证检测结果准确。
  • 增加存在性检查:移除配送方法前先确认该方法存在,避免因方法不存在抛出PHP警告。

补充:用WooCommerce会话存储状态(可选)

如果你需要保留woocommerce_before_cart的逻辑用于其他操作,也可以把检测结果存入WooCommerce会话(比全局变量可靠),示例如下:

add_action('woocommerce_before_cart', 'update_shipping_flag_to_session');
function update_shipping_flag_to_session() {
    $hasOfficePack = false;
    $hasSundayCombo = false;
    $officePack = array('office pack', '77');
    $sundayCombo = array('sunday combo', '85');

    foreach ( WC()->cart->get_cart() as $cart_item ) {
        if ( has_term( $officePack, 'product_cat', $cart_item['product_id'] ) ) {
            $hasOfficePack = true;
        }
        if ( has_term( $sundayCombo, 'product_cat', $cart_item['product_id'] ) ) {
            $hasSundayCombo = true;
        }
    }

    // 将结果存入WooCommerce会话
    if ( $hasSundayCombo ) {
        WC()->session->set('shipping_flag', 1);
    } elseif ( $hasOfficePack ) {
        WC()->session->set('shipping_flag', 0);
    } else {
        WC()->session->set('shipping_flag', null);
    }
}

// 在配送方法钩子中获取会话值
add_filter( 'woocommerce_package_rates', 'hide_shipping_method_via_session', 20, 2 );
function hide_shipping_method_via_session( $rates, $package ) {
    if ( is_admin() && ! defined( 'DOING_AJAX' ) ) return $rates;

    $shipping_flag = WC()->session->get('shipping_flag');

    // 后续逻辑和之前一致...
}

不过这种方式需要注意:购物车商品变化时(比如添加/删除商品),要触发会话更新,否则会话值会过时。所以第一种实时检测的方式通常更稳定可靠。

内容的提问来源于stack exchange,提问作者AFS18

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.14 08:42:30