
该教程详解为何 hide_payment_gateways_based_on_weight 在后台触发“Call to a member function get_cart_contents_weight() on null”错误,并提供安全、合规的修复方案,确保仅在前端购物车或结算页执行重量逻辑。
该教程详解为何 `hide_payment_gateways_based_on_weight` 在后台触发“call to a member function get_cart_contents_weight() on null”错误,并提供安全、合规的修复方案,确保仅在前端购物车或结算页执行重量逻辑。
在 WooCommerce 开发中,通过 woocommerce_available_payment_gateways 过滤器动态隐藏支付方式(如货到付款 COD)是常见需求。但若直接调用 WC()->cart->get_cart_contents_weight() 而未校验上下文环境,极易引发后台致命错误——因为 WordPress 后台(包括 WooCommerce Admin)不初始化购物车对象,WC()->cart 为 null,导致 get_cart_contents_weight() 调用失败。
原始代码使用 is_admin() 判断存在根本性误区:该函数仅检测是否处于 WordPress 管理后台(如 /wp-admin/),而 WooCommerce 的订单编辑、报表、商品管理等页面虽属后台,却仍可能触发支付网关钩子(例如通过 AJAX 或 REST API 加载结算逻辑)。更重要的是,is_admin() 无法区分前后端业务场景,且在部分 WC Admin 上下文中(如订单详情页的支付方式预览),WC()->cart 依然不可用。
✅ 正确做法是:仅在明确存在有效购物车的前端页面执行逻辑,即限定于 is_cart()(购物车页面)和 is_checkout()(结算页面)。这两个条件确保 WC()->cart 已初始化且数据可用。
以下是优化后的完整代码(符合 WPCS/PHPCS 规范,结构清晰、容错性强):
add_filter( 'woocommerce_available_payment_gateways', 'hide_payment_gateways_based_on_weight', 10, 1 );
function hide_payment_gateways_based_on_weight( $available_gateways ) {
// 仅在购物车页或结算页执行逻辑,避免后台及非购物上下文报错
if ( is_cart() || is_checkout() ) {
// 安全获取购物车总重量(单位:克)
$total_weight = WC()->cart->get_cart_contents_weight();
// 条件:总重 ≥ 2000 克(即 2kg)且 COD 网关启用时,将其移除
if ( $total_weight >= 2000 && isset( $available_gateways['cod'] ) ) {
unset( $available_gateways['cod'] );
}
}
return $available_gateways;
}
⚠️ 关键注意事项:
- 勿依赖 is_admin() 控制购物车逻辑:它与购物车生命周期无关,应改用语义化页面条件;
- 始终包裹多行逻辑块在大括号内:避免因缩进误判导致逻辑错误(如原代码中 unset() 实际恒执行);
- 重量单位需统一:get_cart_contents_weight() 返回克(g),请按实际业务调整阈值(如 2000 表示 2kg);
- 扩展建议:如需支持多网关按重量分级隐藏,可将条件抽象为配置数组,提升可维护性。
此方案彻底规避了 null 调用异常,同时保持轻量、可读与生产就绪。










