You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在WooCommerce产品列表页AJAX加购时传递单选自定义字段值

实现WooCommerce归档页带自定义字段的AJAX加购

问题背景

已在产品页完成性别单选自定义字段的添加、验证、购物车数据存储及显示功能,开启归档页AJAX加购后,点击按钮会跳转到产品页要求填写字段。已通过add_action( 'woocommerce_shop_loop_item_title', 'my_add_radio_field' );将字段添加到产品列表,但需实现直接在归档页选字段并完成AJAX加购,无需跳转。

解决方案步骤

1. 调整归档页的自定义字段HTML结构

原字段的name属性全局重复,会导致多产品间字段冲突,需为每个产品的字段添加产品ID前缀确保唯一性:

function my_add_radio_field() {
    // 归档页场景:获取当前产品ID并生成唯一字段名
    if ( is_shop() || is_product_category() || is_product_tag() ) {
        global $product;
        $product_id = $product->get_id();
    ?>
    <div class="custom-field-wrap gender-field-wrap" style="margin: 10px;">
        <h4>Gender?</h4>
        <div class="form-check form-check-inline">
            <label for="g-gender-boy-<?php echo $product_id; ?>">Boy</label>
            <input type="radio" id="g-gender-boy-<?php echo $product_id; ?>" name="g_gender_<?php echo $product_id; ?>" value="boy" />
        </div>
        <div class="form-check form-check-inline">
            <label for="g-gender-girl-<?php echo $product_id; ?>">Girl</label>
            <input type="radio" id="g-gender-girl-<?php echo $product_id; ?>" name="g_gender_<?php echo $product_id; ?>" value="girl" />
        </div>
    </div>
    <?php
    } else {
        // 产品页保持原有结构
    ?>
    <div class="custom-field-wrap gender-field-wrap" style="margin: 10px;">
        <h4>Gender?</h4>
        <div class="form-check form-check-inline">
            <label for="g-gender-boy">Boy</label>
            <input type="radio" id="g-gender-boy" name="g_gender" value="boy" />
        </div>
        <div class="form-check form-check-inline">
            <label for="g-gender-girl">Girl</label>
            <input type="radio" id="g-gender-girl" name="g_gender" value="girl" />
        </div>
    </div>
    <?php
    }
}
add_action( 'woocommerce_before_add_to_cart_button', 'my_add_radio_field' );
add_action( 'woocommerce_shop_loop_item_title', 'my_add_radio_field' );

2. 修改AJAX加购的JS逻辑

拦截归档页的AJAX加购请求,将选中的性别值追加到请求参数中,同时处理未选择字段的错误提示:

jQuery(document).ready(function($) {
    // 监听归档页加购按钮点击事件
    $(document).on('click', '.woocommerce-loop-add-to-cart__button', function(e) {
        var $button = $(this);
        var productId = $button.data('product_id');
        var genderFieldName = 'g_gender_' + productId;
        var selectedGender = $('input[name="' + genderFieldName + '"]:checked').val();

        // 未选择性别时阻止请求并提示
        if (!selectedGender) {
            wc_add_notice('Gender is a required field.', 'error');
            e.preventDefault();
            e.stopPropagation();
            return;
        }

        // 拦截默认AJAX提交,追加性别数据
        $(document).off('submit.woocommerce-add-to-cart');
        $(document).on('submit.woocommerce-add-to-cart', 'form.cart', function(e) {
            var $form = $(this);
            var formData = $form.serializeArray();
            
            // 将选中的性别以统一键名加入请求
            formData.push({
                name: 'g_gender',
                value: selectedGender
            });

            // 发起自定义AJAX请求
            $.ajax({
                type: 'POST',
                url: wc_add_to_cart_params.wc_ajax_url.toString().replace('%%endpoint%%', 'add_to_cart'),
                data: formData,
                beforeSend: function() {
                    $button.removeClass('added').addClass('loading');
                },
                complete: function() {
                    $button.addClass('added').removeClass('loading');
                },
                success: function(response) {
                    if (!response) return;
                    // 更新购物车片段
                    if (response.fragments) {
                        $.each(response.fragments, function(key, value) {
                            $(key).replaceWith(value);
                        });
                    }
                    $(document.body).trigger('wc_fragments_refreshed');
                    wc_add_notice('Product added to cart.', 'success');
                },
                error: function() {
                    wc_add_notice('Failed to add product to cart.', 'error');
                }
            });
            e.preventDefault();
        });
    });
});

3. 兼容原有验证与数据存储逻辑

原有PHP逻辑无需大幅修改,只需确保AJAX请求中$_POST['g_gender']能被正确获取(上述JS已统一传递该键名),同时可添加唯一键确保不同性别视为独立购物车项:

// 验证逻辑(无需修改)
function my_add_to_cart_validation( $passed, $product_id, $quantity, $variation_id = null ) {
    if (empty( $_POST['g_gender'] )) {
        $passed = false;
        wc_add_notice( __( 'Gender is a required field.', 'my-theme' ), 'error' );
    }
    return $passed;
}
add_filter( 'woocommerce_add_to_cart_validation', 'my_add_to_cart_validation', 10, 4 );

// 自定义字段存入购物车(添加唯一键区分不同性别项)
function myr_add_cart_item_data( $cart_item_data, $product_id, $variation_id ) {
    if ( isset( $_POST['g_gender'] ) ) {
        $cart_item_data['custom_data']['guest_gender'] = sanitize_text_field( $_POST['g_gender'] );
        $cart_item_data['custom_data']['unique_key'] = md5( microtime() . rand() );
    }
    return $cart_item_data;
}
add_filter( 'woocommerce_add_cart_item_data', 'myr_add_cart_item_data', 10, 3 );

// 购物车显示自定义数据(修正原代码多余闭合括号)
function display_custom_data_in_cart($item_data, $cart_item)
{
    if (isset($cart_item['custom_data']['guest_gender']) && !empty($cart_item['custom_data']['guest_gender'])) {
        $item_data[] = array(
            'key' => 'Gender',
            'value' => $cart_item['custom_data']['guest_gender'],
        );
    }
    return $item_data;
}
add_filter('woocommerce_get_item_data', 'display_custom_data_in_cart', 10, 2);

4. 优化提示样式(可选)

添加CSS让归档页的提示信息更醒目:

.woocommerce-notices-wrapper {
    margin: 1em 0;
}
.woocommerce-error {
    border-left-color: #dc3232;
    background-color: #fef0f0;
    padding: 1em;
}
.woocommerce-message {
    border-left-color: #46b450;
    background-color: #f0fdf4;
    padding: 1em;
}

内容的提问来源于stack exchange,提问作者Dias

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.20 05:42:37