为何WooCommerce钩子在COD订单中返回数据库结果为Null?
我们在订单流程中收集客户的非商品相关信息并存储在数据库表中,随后将这些数据提取并添加到管理员新订单邮件中,正常情况下邮件会显示:
Location: Hospital County: Los Angeles Delivery: Pickup
使用的钩子代码如下:
add_action( 'woocommerce_email_order_meta', 'add_email_order_meta', 10, 3 ); function add_email_order_meta( $order_obj, $sent_to_admin, $plain_text ){ global $wpdb; $order_id = $order_obj->get_order_number(); $result = $wpdb->get_row( "SELECT * FROM cl_order_meta WHERE order_id = " . $order_id, OBJECT ); if ($sent_to_admin) { echo ' <ul> <li><strong>Location:</strong> ' . $result->location. '</li> <li><strong>County:</strong> ' . $result->county. '</li> <li><strong>Delivery:</strong> ' . $result->delivery. '</li> </ul>'; } }
该功能在信用卡订单中运行正常,但货到付款(COD)订单中无数据显示,邮件中仅显示:
Location: County: Delivery:
已确认数据已存在于数据库中,邮件可正常接收但无元数据。在邮件中输出的Order ID正确,输出json_encode($result)显示为Null,说明查询未返回结果。尝试在查询前添加sleep(5),推测可能是数据库写入延迟,但无效果。
已确认钩子已触发,因为邮件中有标签和正确的Order ID,但查询数据未显示。
Apache错误日志信息:
AH01071: Got error 'PHP message: The WC_Product::get_parent function is deprecated since version 3.0. Replace with WC_Product::get_parent_id.PHP message: The WC_Product::get_post_data function is deprecated since version 3.0. Replace with get_post. PHP message: The WC_Product::get_post_data function is deprecated since version 3.0. Replace with get_post. PHP message: The WC_Product::get_parent function is deprecated since version 3.0. Replace with WC_Product::get_parent_id. PHP message: The WC_Product::get_post_data function is deprecated since version 3.0. Replace with get_post. PHP message: The WC_Product::get_parent function is deprecated since version 3.0. Replace with WC_Product::get_parent_id. PHP message: The WC_Product::get_post_data function is deprecated since version 3.0. Replace with get_post. PHP message: woocommerce_add_order_item_meta is deprecated since version 3.0.0! Use woocommerce_new_order_item instead. PHP message: woocommerce_add_order_item_meta is deprecated since version 3.0.0! Use woocommerce_new_order_item instead. PHP message: woocommerce_add_order_item_meta is deprecated since version 3.0.0! Use woocommerce_new_order_item instead. PHP message: woocommerce_add_order_item_meta is deprecated since version 3.0.0! Use woocommerce_new_order_item instead. PHP message: woocommerce_add_order_item_meta is deprecated since version 3.0.0! Use woocommerce_new_order_item instead.', referer: https://example.com/checkout/
数据库插入代码:
add_action('wp_ajax_cl_add_session_vars_to_db', 'add_session_vars_to_db'); function add_session_vars_to_db() { global $wpdb; $order_id = $_POST['order_id']; $wpdb->insert('cl_order_meta', array( 'order_id' => $order_id, 'location' => isset($_SESSION['location']) ? $_SESSION['location'] : 'N/A', 'county' => isset($_SESSION['county']) ? $_SESSION['county'] : 'N/A', 'delivery' => isset($_SESSION['delivery']) ? $_SESSION['delivery'] : 'Pickup', 'create_date' => time() )); }
核心原因
订单ID类型不匹配:
信用卡订单中,$order_obj->get_order_number()返回的是订单的纯数字原始ID,和数据库中存储的order_id一致;但COD订单里,WooCommerce可能会生成带前缀的格式化订单号(比如WC-123),此时get_order_number()返回的是带前缀的字符串,而非数据库中存储的纯数字ID,导致查询无法匹配到数据。(次要排查点)插入时机问题:
虽然你确认数据已写入数据库,但需确认COD订单的邮件触发时机是否早于wp_ajax_cl_add_session_vars_to_db的执行时机,不过这条可能性较低。
验证方式
在邮件钩子中添加调试代码,对比两种订单类型的ID差异:
function add_email_order_meta( $order_obj, $sent_to_admin, $plain_text ){ global $wpdb; $order_number = $order_obj->get_order_number(); $order_raw_id = $order_obj->get_id(); // 获取原始数字ID // 调试输出,可在邮件中查看 echo "格式化订单号: {$order_number}<br>"; echo "原始数字ID: {$order_raw_id}<br>"; $result = $wpdb->get_row( "SELECT * FROM cl_order_meta WHERE order_id = " . $order_raw_id, OBJECT ); // ... 其余代码不变 }
解决办法
将查询时使用的订单ID替换为$order_obj->get_id()(WooCommerce订单的原始数字ID),同时优化代码安全性:
修改后的钩子代码:
add_action( 'woocommerce_email_order_meta', 'add_email_order_meta', 10, 3 ); function add_email_order_meta( $order_obj, $sent_to_admin, $plain_text ){ global $wpdb; $order_id = $order_obj->get_id(); // 使用原始数字ID // 使用prepare防止SQL注入 $result = $wpdb->get_row( $wpdb->prepare( "SELECT * FROM cl_order_meta WHERE order_id = %d", $order_id ), OBJECT ); // 增加非空判断,避免查询失败时邮件报错 if ($sent_to_admin && $result) { echo ' <ul> <li><strong>Location:</strong> ' . esc_html($result->location) . '</li> <li><strong>County:</strong> ' . esc_html($result->county) . '</li> <li><strong>Delivery:</strong> ' . esc_html($result->delivery) . '</li> </ul>'; } }
额外检查:确认数据库插入代码中$_POST['order_id']传入的是原始数字ID,确保插入和查询使用的ID类型完全一致。
内容的提问来源于stack exchange,提问作者cx3700

