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

如何防止WooCommerce结账页创建重复自定义字段值的订单?

问题分析与代码修正

原代码的核心问题

  • 钩子绑定错误:woocommerce_after_checkout_validation钩子中,函数名custom__billing_code_validation前多了一个空格,导致验证函数无法被触发执行
  • SQL查询逻辑错误:
    • 重复关联同一张postmeta表,且条件pm.meta_value != $billing_code与pm2.meta_value LIKE '$billing_code'自相矛盾,永远查不到结果
    • 元键名称错误:保存字段时用的是billing_code,但SQL中写成了_billing_code,导致无法匹配已保存的字段值
  • SQL安全风险:直接将用户输入的变量拼接到SQL语句中,存在SQL注入隐患
  • 未过滤订单状态:会统计已取消、已退款等无效订单,导致判断不准确

修正后的完整代码

// 添加自定义结账字段
add_filter('woocommerce_checkout_fields','custom_woocommerce_billing_field');
function custom_woocommerce_billing_field( $fields ) {
    $fields['billing']['billing_code'] = array(
        'label'       => __('配送码', 'woocommerce'),
        'placeholder' => __('例如:s9855', 'woocommerce'),
        'required'    => true,
        'clear'       => false,
        'type'        => 'text',
        'class'       => array('billing_code'),
        'priority'    => 5,
    );

    return $fields;
}

// 保存自定义字段到订单元数据
add_action( 'woocommerce_checkout_update_order_meta', 'shipping_code_update_order_meta' );
function shipping_code_update_order_meta( $order_id ) {
    if ( ! empty( $_POST['billing_code'] ) ) {
        update_post_meta( $order_id, 'billing_code', sanitize_text_field( $_POST['billing_code'] ) );
    }
}

// 检查字段是否填写
add_action('woocommerce_checkout_process', 'my_custom_checkout_field_proces');
function my_custom_checkout_field_proces() {
    if ( empty( $_POST['billing_code'] ) ) {
        wc_add_notice( __( '请输入配送码。' ), 'error' );
    }
}

// 验证配送码是否已存在
add_action( 'woocommerce_after_checkout_validation', 'custom_billing_code_validation', 50, 2 );
function custom_billing_code_validation( $data, $errors ) {
    if ( isset( $data['billing_code'] ) ) {
        global $wpdb;

        $billing_code = sanitize_text_field( $data['billing_code'] );

        // 使用prepare方法防止SQL注入,同时只统计有效状态的订单
        $count = $wpdb->get_var( $wpdb->prepare( "
            SELECT COUNT(p.ID)
            FROM {$wpdb->prefix}posts as p
            INNER JOIN {$wpdb->prefix}postmeta as pm ON p.ID = pm.post_id
            WHERE p.post_type = 'shop_order'
            AND p.post_status IN ('wc-processing', 'wc-completed', 'wc-on-hold')
            AND pm.meta_key = 'billing_code'
            AND pm.meta_value = %s
        ", $billing_code ) );

        if ( $count > 0 ) {
            $errors->add( 'validation', __('该"配送码"已存在,请联系我们。') );
        }
    }
}

修正说明

  1. 移除了钩子注册时函数名前的多余空格,确保验证函数能被正确触发
  2. 简化了SQL查询,只关联一次postmeta表,修正了元键名称为billing_code
  3. 使用$wpdb->prepare()处理变量,彻底避免SQL注入风险
  4. 添加了订单状态过滤,只统计处理中、已完成、待付款的有效订单,避免无效订单干扰判断
  5. 优化了字段提示文字的中文表述,更符合国内用户习惯

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.16 08:17:32