WooCommerce订阅按购物车商品数加附加费触发致命错误排查
WooCommerce Subscriptions 附加费代码致命错误修复
核心报错原因
代码触发站点崩溃、逻辑失效共存在5个问题:
- 直接致命错误:
WC()->cart->get_cart()返回的购物车条目是数组格式,并非产品对象,直接对数组调用->is_type()方法会抛出PHP致命错误Call to a member function is_type() on array,这是站点无法访问的直接原因。每个购物车条目里的$item['data']才是对应的产品实例,只有产品实例才能调用类型判断方法。 - 计费逻辑错误:统计非订阅商品数量时,仅按商品条目数+1,没有乘以单商品的购买数量
$item['quantity'],用户同一款非订阅商品购买多件时会少算费用。 - 类型判断遗漏:仅判断了
subscription简单订阅类型,没有覆盖可变订阅subscription_variation类型,会把可变订阅商品误算为非订阅商品计费。 - 场景判断失效:
woocommerce_cart_calculate_fees钩子会在AJAX刷新购物车、结账计算等异步场景触发,直接调用is_page()无法在异步请求中获取正确的页面ID,导致周期性费用的分档规则完全失效。 - 不规范写法:钩子已经传入
$cart实例,仍全局调用WC()->cart获取购物车,容易在Subscriptions的周期性购物车计算场景下取错实例。
修复后可直接部署的代码
add_filter( 'woocommerce_cart_calculate_fees', 'add_administration_fees', 10, 1 ); function add_administration_fees( $cart ) { // 避免后台非AJAX场景误触发计算 if ( is_admin() && ! defined( 'DOING_AJAX' ) ) return; $item_count = 0; // 用钩子传入的$cart实例遍历购物车,避免上下文取值错误 foreach ( $cart->get_cart() as $item ) { $product = $item['data']; // 同时排除简单订阅、可变订阅商品,统计非订阅商品实际购买总数量 if ( ! $product->is_type( array( 'subscription', 'subscription_variation' ) ) ) { $item_count += $item['quantity']; } } // 初始订单附加费:每件非订阅商品收50 if ( empty( $cart->recurring_cart_key ) ) { $cart->add_fee( 'Additional Items', $item_count * 50 ); return; } // 兼容普通请求+AJAX请求获取当前页面ID $current_page_id = 0; if ( is_page() ) { $current_page_id = get_queried_object_id(); } elseif ( isset( $_REQUEST['_wp_http_referer'] ) ) { $referer_path = wp_parse_url( wp_get_raw_referer(), PHP_URL_PATH ); $referer_page = get_page_by_path( basename( untrailingslashit( $referer_path ) ) ); if ( $referer_page ) $current_page_id = $referer_page->ID; } // 周期性订阅费用分档计算 if ( 254 === $current_page_id ) { $cart->add_fee( 'Additional Items', $item_count * 7 ); } elseif ( 457 === $current_page_id ) { $cart->add_fee( 'Additional Items', $item_count * 5 ); } }
修复说明
- 彻底解决数组调用对象方法的致命错误,部署后站点可正常访问
- 补全可变订阅商品的类型判断,不会误将订阅商品计入非订阅商品统计
- 数量统计按用户实际购买件数计算,不会出现多买少算的问题
- 兼容AJAX场景下的页面ID判断,不同页面对应的分档周期性费用可正常触发
- 初始订单和周期性订单的费用计算逻辑完全隔离,不会出现重复计费问题
内容的提问来源于stack exchange,提问作者Dinoboy
相关产品推荐
相关产品推荐

