如何实现适配多场景的WooCommerce支付关联费/折扣功能?
通用WooCommerce支付类型手续费/折扣实现方案
问题分析
原代码存在以下几个导致场景覆盖不全的问题:
- 重复注册了
woocommerce_cart_calculate_fees钩子,可能引发执行冲突 - 获取选中支付方式时,session键名错误(多了美元符号
$) - JS仅监听常规结账表单的支付方式切换,未覆盖押金插件等自定义结账场景
- 钩子优先级默认10,可能被其他插件的同钩子代码覆盖
改进后的通用代码
PHP部分
// 注册费用计算钩子,提高优先级确保优先执行 add_action( 'woocommerce_cart_calculate_fees', 'ts_add_payment_based_discount', 20, 1 ); function ts_add_payment_based_discount( $cart ) { // 后台非AJAX请求直接返回 if ( is_admin() && ! defined( 'DOING_AJAX' ) ) return; // 目标支付方式(替换为你的支付方式slug) $target_payment_method = 'redsys'; // 折扣百分比(正数为折扣,负数为手续费) $percent = 5.435; // 正确获取选中的支付方式 $chosen_payment_method = WC()->session->get( 'chosen_payment_method' ); // 仅当选中目标支付方式时执行计算 if ( $target_payment_method === $chosen_payment_method ) { // 使用cart->get_subtotal()确保兼容更多场景(包括押金插件的金额计算) $cart_total = $cart->get_subtotal(); $discount = round( ( $cart_total / 100 ) * $percent, 2 ); // 添加折扣(负数为折扣,正数为手续费) $cart->add_fee( __( "Discount International Charge" ), -$discount, false ); } } // 触发结账更新的钩子,使用更通用的位置 add_action( 'woocommerce_before_checkout_form', 'ts_refresh_checkout_on_payment_change' ); function ts_refresh_checkout_on_payment_change() { ?> <script type="text/javascript"> (function($){ // 监听所有支付方式单选框的变化,不限于常规结账表单 $( document.body ).on( 'change', 'input[name^="payment_method"]', function() { // 触发结账更新事件,兼容WooCommerce核心及多数插件 $( document.body ).trigger( 'update_checkout' ); }); })(jQuery); </script> <?php }
关键优化点
- 钩子优先级:将
woocommerce_cart_calculate_fees的优先级设为20,确保在多数插件之后执行,避免被覆盖 - 支付方式获取:修正session键名错误,使用正确的
chosen_payment_method - 金额计算:使用
$cart->get_subtotal()替代subtotal_ex_tax,兼容更多自定义结账场景(如押金插件的部分金额计算) - JS监听范围:将监听对象从
form.checkout改为document.body,覆盖所有页面中的支付方式切换事件 - 移除重复钩子:删除重复的
add_action注册,避免函数重复执行
额外适配建议
如果押金插件使用了独立的结账流程或自定义session存储,可尝试以下补充操作:
- 检查押金插件是否支持
woocommerce_cart_calculate_fees钩子,若不支持,可查看插件文档寻找对应的费用计算钩子 - 若支付方式在押金场景下存储在其他位置,可通过
$_POST['payment_method']或插件提供的API获取当前选中的支付方式
内容的提问来源于stack exchange,提问作者Marcel
相关产品推荐
相关产品推荐

