如何在WooCommerce后台订单中查看自定义产品字段?
WooCommerce自定义字段后台订单不显示问题排查
问题描述
我在未使用插件的情况下,给WooCommerce产品页面添加了3个用户字段(日期字段、文本框、文本域),这些字段能正常显示在购物车和结账页面的商品名称下方,但在后台订单中完全找不到这些元字段的内容。我想知道最后一个用于后台显示的函数存在什么错误?
我的完整代码如下:
// Display custom fields on product page add_action('woocommerce_before_add_to_cart_button', 'add_custom_fields', 9); function add_custom_fields() { global $product; // Define the categories to exclude $excluded_categories = array(24, 26); // Check if the product belongs to the excluded categories if (has_term($excluded_categories, 'product_cat', $product->get_id())) { return; // Do not add the fields if the product belongs to the excluded categories } echo '<div class="customer-fields">'; echo '<div class="customer-field delivery_date">'; echo '<label for="delivery_date">Delivery Date<span class="req">*</span>:</label>'; echo '<input type="date" id="delivery_date" name="delivery_date">'; echo '</div>'; echo '<div class="customer-field occasion">'; echo '<label for="occasion">Occasion:</label>'; echo '<input type="text" id="occasion" name="occasion" placeholder="Occasion">'; echo '</div>'; echo '<div class="customer-field custom_note">'; echo '<label for="custom_note">Enter Your Message:</label>'; echo '<textarea id="custom_note" name="custom_note" rows="4" cols="50" placeholder="Enter your message here..."></textarea>'; echo '</div>'; echo '</div>'; } // Save custom fields data to order meta add_action('woocommerce_add_to_cart', 'save_custom_fields', 10, 2); function save_custom_fields($cart_item_key, $product_id) { if (isset($_POST['delivery_date'])) { WC()->session->set('delivery_date', sanitize_text_field($_POST['delivery_date'])); } if (isset($_POST['occasion'])) { WC()->session->set('occasion', sanitize_text_field($_POST['occasion'])); } if (isset($_POST['custom_note'])) { WC()->session->set('custom_note', sanitize_text_field($_POST['custom_note'])); } } add_action('woocommerce_checkout_create_order_line_item', 'add_custom_fields_to_order_items', 10, 4); function add_custom_fields_to_order_items($item, $cart_item_key, $values, $order) { if (WC()->session->__isset('delivery_date')) { $item->add_meta_data('Delivery Date', WC()->session->get('delivery_date')); WC()->session->__unset('delivery_date'); } if (WC()->session->__isset('occasion')) { $item->add_meta_data('Occasion', WC()->session->get('occasion')); WC()->session->__unset('occasion'); } if (WC()->session->__isset('custom_note')) { $item->add_meta_data('Custom Note', WC()->session->get('custom_note')); WC()->session->__unset('custom_note'); } } // Display custom fields in cart and checkout add_filter('woocommerce_get_item_data', 'display_custom_fields_in_cart', 10, 2); function display_custom_fields_in_cart($item_data, $cart_item) { if (isset($cart_item['delivery_date'])) { $item_data[] = array( 'key' => __('Delivery Date', 'woocommerce'), 'value' => wc_clean($cart_item['delivery_date']), 'display' => '', ); } if (isset($cart_item['occasion'])) { $item_data[] = array( 'key' => __('Occasion', 'woocommerce'), 'value' => wc_clean($cart_item['occasion']), 'display' => '', ); } if (isset($cart_item['custom_note'])) { $item_data[] = array( 'key' => __('Custom Note', 'woocommerce'), 'value' => wc_clean($cart_item['custom_note']), 'display' => '', ); } return $item_data; } // Display custom fields in admin order page add_action('woocommerce_admin_order_data_after_billing_address', 'display_custom_fields_in_admin_order', 10, 1); function display_custom_fields_in_admin_order($order) { $items = $order->get_items(); foreach ($items as $item_id => $item) { $delivery_date = wc_get_order_item_meta($item_id, 'Delivery Date', true); $occasion = wc_get_order_item_meta($item_id, 'Occasion', true); $custom_note = wc_get_order_item_meta($item_id, 'Custom Note', true); if (!empty($delivery_date)) { echo '<p><strong>' . __('Delivery Date', 'woocommerce') . ':</strong> ' . $delivery_date . '</p>'; } if (!empty($occasion)) { echo '<p><strong>' . __('Occasion', 'woocommerce') . ':</strong> ' . $occasion . '</p>'; } if (!empty($custom_note)) { echo '<p><strong>' . __('Custom Note', 'woocommerce') . ':</strong> ' . $custom_note . '</p>'; } } }
我还尝试过这段代码,但依然无效:
add_action( 'woocommerce_admin_order_data_after_billing_address', 'display_custom_fields_value_admin_order', 10, 1 ); function display_custom_fields_value_admin_order( $order ){ // Display the delivery date if( $delivery_date = $order->get_meta('delivery_date') ) echo '<p><strong>'.__('Delivery Date').':</strong> ' . $delivery_date . '</p>'; }
错误分析与修正方案
核心错误点
购物车项数据未同步:
你在save_custom_fields函数中只把字段值存在了Session,但没有同步到购物车项(cart_contents)里,这导致woocommerce_get_item_data能显示内容是偶然情况,实际购物车项并没有存储这些值,后续流程存在数据断层。后台读取元数据的键名错误:
当你用$item->add_meta_data('Delivery Date', $value)存储订单项元数据时,WooCommerce会自动将带空格的键名转换为下划线格式,并添加前缀_(比如Delivery Date会变成_delivery_date)。你后台读取时用原键名Delivery Date,自然找不到对应值。订单元数据读取逻辑错误:
你尝试的第二段代码用$order->get_meta('delivery_date')读取,但你的字段是存储在**订单项(order line item)**里,不是订单本身的元数据,所以从订单对象读取必然为空。
修正后的完整代码
1. 修正字段存储逻辑(同步到购物车项)
// 保存自定义字段到购物车项和Session add_action('woocommerce_add_to_cart', 'save_custom_fields', 10, 2); function save_custom_fields($cart_item_key, $product_id) { $cart_item_data = array(); if (isset($_POST['delivery_date'])) { $delivery_date = sanitize_text_field($_POST['delivery_date']); WC()->session->set('delivery_date', $delivery_date); $cart_item_data['delivery_date'] = $delivery_date; } if (isset($_POST['occasion'])) { $occasion = sanitize_text_field($_POST['occasion']); WC()->session->set('occasion', $occasion); $cart_item_data['occasion'] = $occasion; } if (isset($_POST['custom_note'])) { // 文本域用sanitize_textarea_field保留换行格式 $custom_note = sanitize_textarea_field($_POST['custom_note']); WC()->session->set('custom_note', $custom_note); $cart_item_data['custom_note'] = $custom_note; } // 更新购物车项数据 if (!empty($cart_item_data)) { WC()->cart->cart_contents[$cart_item_key] = array_merge(WC()->cart->cart_contents[$cart_item_key], $cart_item_data); } }
2. 修正订单项元数据存储(使用规范键名)
// 将自定义字段添加到订单项 add_action('woocommerce_checkout_create_order_line_item', 'add_custom_fields_to_order_items', 10, 4); function add_custom_fields_to_order_items($item, $cart_item_key, $values, $order) { // 直接从购物车项取数,避免Session依赖 if (isset($values['delivery_date'])) { // 使用下划线键名,第三个参数true表示隐藏元数据(不在前台订单显示) $item->add_meta_data('_delivery_date', $values['delivery_date'], true); } if (isset($values['occasion'])) { $item->add_meta_data('_occasion', $values['occasion'], true); } if (isset($values['custom_note'])) { $item->add_meta_data('_custom_note', $values['custom_note'], true); } }
3. 修正后台订单显示逻辑
// 后台订单页面显示自定义字段 add_action('woocommerce_admin_order_data_after_billing_address', 'display_custom_fields_in_admin_order', 10, 1); function display_custom_fields_in_admin_order($order) { foreach ($order->get_items() as $item) { // 使用订单项对象的get_meta方法读取规范键名 $delivery_date = $item->get_meta('_delivery_date'); $occasion = $item->get_meta('_occasion'); $custom_note = $item->get_meta('_custom_note'); if (!empty($delivery_date)) { echo '<p><strong>' . __('Delivery Date', 'woocommerce') . ':</strong> ' . esc_html($delivery_date) . '</p>'; } if (!empty($occasion)) { echo '<p><strong>' . __('Occasion', 'woocommerce') . ':</strong> ' . esc_html($occasion) . '</p>'; } if (!empty($custom_note)) { echo '<p><strong>' . __('Custom Note', 'woocommerce') . ':</strong> ' . esc_html($custom_note) . '</p>'; } } }
额外优化建议
- 添加必填字段验证:在
woocommerce_add_to_cart_validation钩子中检查delivery_date是否填写,避免空值提交。 - 前端字段样式优化:给自定义字段添加必要的CSS样式,提升用户体验。
内容的提问来源于stack exchange,提问作者libertarian
相关产品推荐
相关产品推荐

