
本文详解为何 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 后台(尤其是订单管理、商品编辑等页面)抛出致命错误:
CRITICAL Uncaught Error: Call to a member function get_cart_contents_weight() on null
根本原因在于:后台页面(包括 WooCommerce Admin)默认无购物车上下文,WC()->cart 为 null,此时调用其方法必然失败。而 is_admin() 并不能准确区分「是否处于前端购物流程」——它仅判断是否进入 /wp-admin/,却无法排除后台 AJAX 请求、REST API 或自定义管理页中对支付网关钩子的意外触发。
✅ 正确做法是:仅在真正存在购物车的上下文中执行逻辑,即限定于前端的 cart 和 checkout 页面:
add_filter( 'woocommerce_available_payment_gateways', 'hide_payment_gateways_based_on_weight', 10, 1 );
function hide_payment_gateways_based_on_weight( $available_gateways ) {
// ✅ 仅在购物车页或结账页执行逻辑(确保 WC()->cart 可用)
if ( is_cart() || is_checkout() ) {
// 安全获取购物车总重量(单位:克)
$total_weight = WC()->cart->get_cart_contents_weight();
// ✅ 注意条件顺序:先检查重量阈值,再验证网关是否存在
// 此处逻辑为「重量 ≥ 2000g 时隐藏 COD」;若需「≥2000g 才启用 COD」,请调整比较符
if ( $total_weight >= 2000 && isset( $available_gateways['cod'] ) ) {
unset( $available_gateways['cod'] );
}
}
return $available_gateways;
}
⚠️ 关键注意事项:
- 勿依赖 is_admin() 过滤:它无法解决后台钩子被间接调用的问题(如某些插件或 REST 端点会触发该过滤器);
- 必须使用 is_cart() || is_checkout():这是 WooCommerce 官方推荐的、语义明确的上下文判断方式;
- 始终包裹 if 语句体:避免因缺少大括号导致逻辑错误(例如原代码中 unset 实际不受 if 控制);
- 重量单位统一为克:get_cart_contents_weight() 返回值以克为单位,请按实际业务校准阈值(如 2000g = 2kg);
- COD 网关 ID 需确认:部分主题或插件可能重命名 COD 网关(如 'cash_on_delivery'),建议在调试时 var_dump(array_keys($available_gateways)) 验证。
该方案既消除了后台致命错误,又保持了前端功能完整性,同时符合 WooCommerce 编码最佳实践与 PHPCS/WPCS 规范要求。










