如何防止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', __('该"配送码"已存在,请联系我们。') ); } } }
修正说明
- 移除了钩子注册时函数名前的多余空格,确保验证函数能被正确触发
- 简化了SQL查询,只关联一次
postmeta表,修正了元键名称为billing_code - 使用
$wpdb->prepare()处理变量,彻底避免SQL注入风险 - 添加了订单状态过滤,只统计
处理中、已完成、待付款的有效订单,避免无效订单干扰判断 - 优化了字段提示文字的中文表述,更符合国内用户习惯
内容的提问来源于stack exchange,提问作者Andrey Miller
相关产品推荐
相关产品推荐

