WooCommerce结账页Ajax添加多项费用 第二项触发400错误如何解决
问题根因
勾选高级礼盒选项时Ajax请求返回400的核心原因是第二个请求对应的WordPress Ajax action未注册回调:
- 前端JS中给礼盒复选框绑定的请求,传入的
action参数值为enable_fee_2 - 但代码末尾仅为第一个保险费的
enable_feeaction注册了登录、未登录用户两类Ajax回调钩子,完全没有为enable_fee_2绑定处理函数,WordPress在admin-ajax.php中找不到匹配的回调时会直接返回400错误。
除此之外现有代码还存在几个易触发异常的隐患: - 保险费计算函数
as_calculate_insurance_fee()中部分逻辑分支未给$insurance_fee变量赋值,触发对应条件时会抛出PHP未定义变量警告 - 礼盒费的显示名称存在拼写错误:
Siganture正确拼写为Signature - 两个复选框各自触发独立Ajax请求,存在不必要的性能开销,可合并逻辑简化代码
修复步骤
- 为
enable_fee_2action补全登录、未登录用户的Ajax回调钩子,直接复用已有的会话存储逻辑即可,无需新增处理函数 - 在保险费计算函数开头初始化
$insurance_fee默认值为0,避免未定义变量问题 - 修正费用名称的拼写错误
- 替换原生
die()为WordPress原生wp_die(),符合平台编码规范
修正后可直接使用的完整代码
// Calculate insurance fee function as_calculate_insurance_fee() { // 初始化默认值,避免未定义变量警告 $insurance_fee = 0; $shipping_country = WC()->customer->get_shipping_country(); $cart_subtotal = WC()->cart->subtotal; $cart_subtotal_rounded = ceil($cart_subtotal / 100) * 100; if($shipping_country == 'AU') { if($cart_subtotal <= 5000) $insurance_fee = $cart_subtotal_rounded/100 + 1; } else { $chosen_methods = WC()->session->get( 'chosen_shipping_methods' ); $chosen_shipping = $chosen_methods[0]; if ($chosen_shipping == 'free_shipping:12' || $chosen_shipping == 'starshipit_4') { if($cart_subtotal <= 5000) $insurance_fee = $cart_subtotal_rounded/100 * 3; } else if($chosen_shipping == 'starshipit_5') { $insurance_fee = ($cart_subtotal_rounded - 1000)/100 * 3 + 25; } } return $insurance_fee; } // Add a Shipping Insurance checkbox field function add_custom_checkout_checkbox() { $insurance_fee = as_calculate_insurance_fee(); $checked = WC()->session->get('enable_fee') ? true : false; woocommerce_form_field( 'insurance_fee', array( 'type' => 'checkbox', 'label' => __('<span class="woocommerce-Price-amount amount"><bdi><span class="woocommerce-Price-currencySymbol">'.get_woocommerce_currency().' </span>'.$insurance_fee.'</bdi></span>'), 'class' => array( 'form-row-wide' ), ), $checked ); } add_action( 'as_review_order_after_shipping', 'add_custom_checkout_checkbox', 20 ); // Add Signature Gift Box checkbox field function add_custom_checkout_checkbox_2() { $checked = WC()->session->get('enable_fee_2') ? true : false; woocommerce_form_field( 'premium_giftbox_fee', array( 'type' => 'checkbox', 'label' => __('<span class="woocommerce-Price-amount amount"><bdi><span class="woocommerce-Price-currencySymbol">'.get_woocommerce_currency().' </span>9</bdi></span>'), 'class' => array( 'form-row-wide' ), ), $checked ); } add_action( 'as_review_order_before_shipping', 'add_custom_checkout_checkbox_2', 20 ); // Add custom fees function custom_fee( $cart ) { // Only on checkout if ( ( is_admin() && ! defined( 'DOING_AJAX' ) ) || ! is_checkout() ) return; $insurance_fee = as_calculate_insurance_fee(); if( WC()->session->get('enable_fee') ) $cart->add_fee( __( 'Insurance fee', 'woocommerce'), $insurance_fee ); if( WC()->session->get('enable_fee_2') ) $cart->add_fee( __( 'Signature Gift Box fee', 'woocommerce'), 9 ); // 修正拼写错误 } add_action( 'woocommerce_cart_calculate_fees', 'custom_fee', 20, 1 ); // Remove "(optional)" label on checkbox field function remove_order_comments_optional_fields_label( $field, $key, $args, $value ) { if( ( 'insurance_fee' === $key || 'premium_giftbox_fee' === $key ) && is_checkout() ) { $optional = ' <span class="optional">(' . esc_html__( 'optional', 'woocommerce' ) . ')</span>'; $field = str_replace( $optional, '', $field ); } return $field; } add_filter( 'woocommerce_form_field' , 'remove_order_comments_optional_fields_label', 10, 4 ); // jQuery - Ajax script function checkout_fees_script() { // Only on Checkout if( is_checkout() && ! is_wc_endpoint_url() ) : if( WC()->session->__isset('enable_fee') ) WC()->session->__unset('enable_fee'); if( WC()->session->__isset('enable_fee_2') ) WC()->session->__unset('enable_fee_2'); ?> <script type="text/javascript"> jQuery( function($){ if (typeof wc_checkout_params === 'undefined') return false; // 统一监听两个复选框变化,减少重复请求 $('form.checkout').on('change', 'input[name=insurance_fee], input[name=premium_giftbox_fee]', function(e){ const feeChecked = $('input[name=insurance_fee]').prop('checked') ? '1' : ''; const fee2Checked = $('input[name=premium_giftbox_fee]').prop('checked') ? '1' : ''; $.ajax({ type: 'POST', url: wc_checkout_params.ajax_url, data: { 'action': 'enable_fee', 'enable_fee': feeChecked, 'enable_fee_2': fee2Checked, }, success: function () { $('body').trigger('update_checkout'); }, }); }); }); </script> <?php endif; } add_action( 'wp_footer', 'checkout_fees_script' ); // Get Ajax request and saving to WC session function get_enable_fee() { if ( isset($_POST['enable_fee']) ) { WC()->session->set('enable_fee', (bool)$_POST['enable_fee'] ); } if ( isset($_POST['enable_fee_2']) ) { WC()->session->set('enable_fee_2', (bool)$_POST['enable_fee_2'] ); } wp_die(); } add_action( 'wp_ajax_enable_fee', 'get_enable_fee' ); add_action( 'wp_ajax_nopriv_enable_fee', 'get_enable_fee' ); // 补全第二个action的钩子,解决400问题 add_action( 'wp_ajax_enable_fee_2', 'get_enable_fee' ); add_action( 'wp_ajax_nopriv_enable_fee_2', 'get_enable_fee' );
内容的提问来源于stack exchange,提问作者Isabel AG
相关产品推荐
相关产品推荐

