求助:解决WooCommerce后台订单页面自定义库存字段值随产品更新同步变更的问题
解决方案:保存订单项的自定义字段快照
这个问题的核心原因很明确:你当前的代码是实时从产品/变体的自定义字段中拉取内容,每次打开订单页面都会去读取最新的产品数据——这就导致旧订单的内容会跟着产品字段更新而同步改变。要实现「旧订单保留下单时的原始内容,新订单用最新内容」,关键是在用户下单时,把当时的自定义字段值快照式保存到订单项的元数据中,后续后台展示时直接读取这个快照,而非产品本身的字段。
下面分两步实现:
1. 下单时保存自定义字段快照到订单项
使用woocommerce_checkout_create_order_line_item钩子,在结账流程创建订单项的瞬间,将当时产品/变体的自定义字段值保存到订单项的元数据里:
add_action('woocommerce_checkout_create_order_line_item', 'save_custom_field_to_order_item', 10, 4); function save_custom_field_to_order_item($item, $cart_item_key, $values, $order) { $product = $values['data']; // 处理可变产品的变体 if ($product->is_type('variation')) { $custom_text = get_post_meta($product->get_id(), 'custom_field', true); // 保存到订单项元数据(第三个参数true表示不在前端显示) if (!empty($custom_text)) { $item->add_meta_data('_custom_stock_snapshot', $custom_text, true); } } // 处理简单产品 elseif ($product->is_type('simple')) { $custom_text = get_post_meta($product->get_id(), 'custom_stock_message', true); if (!empty($custom_text)) { $item->add_meta_data('_custom_stock_snapshot', $custom_text, true); } } // 同时把当时的库存状态逻辑结果也存为快照(后台直接读这个更省事) $quantity = $values['quantity']; $availability_text = ''; if ($product->is_type('variation')) { if (!empty($custom_text) && $quantity <= -1) { $availability_text = $custom_text; } elseif (empty($custom_text) && $quantity <= -1) { $availability_text = __('Right now is not available', 'woocommerce'); } else { $availability_text = __('Finns i lager', 'woocommerce'); } } elseif ($product->is_type('simple')) { if (!empty($custom_text) && $quantity <= 0) { $availability_text = $custom_text; } elseif (empty($custom_text) && $quantity <= 0) { $availability_text = __('Right now is not available', 'woocommerce'); } else { $availability_text = __('Finns i lager', 'woocommerce'); } } $item->add_meta_data('_availability_snapshot', $availability_text, true); }
2. 修改后台订单页面的显示代码
现在不再从产品读取数据,而是直接读取订单项里保存的快照值,同时兼容没有快照的旧订单:
add_action('woocommerce_admin_order_data_after_shipping_address', 'display_order_data_in_admin'); function display_order_data_in_admin($order) { ?> <h4><?php _e('Speciellnotering', 'woocommerce'); ?></h4> <?php foreach ($order->get_items() as $item_id => $item) { $product = $item->get_product(); $quantity = $item->get_quantity(); $sku = ''; // 获取SKU if ($product->is_type('variable')) { $sku = get_post_meta($item->get_variation_id(), '_sku', true); } else { $sku = $product->get_sku(); } // 优先读取订单项的快照 $availability_text = $item->get_meta('_availability_snapshot'); // 旧订单无快照时,兼容生成内容(可选逻辑) if (empty($availability_text)) { if ($product->is_type('variable')) { $custom_text_message = get_post_meta($item->get_variation_id(), 'custom_field', true); if ($custom_text_message && $quantity <= -1) { $availability_text = $custom_text_message; } elseif (!$custom_text_message && $quantity <= -1) { $availability_text = __('Right now is not available', 'woocommerce'); } else { $availability_text = __('Finns i lager', 'woocommerce'); } } else { $custom_stock_message = get_post_meta($item->get_product_id(), 'custom_stock_message', true); if ($custom_stock_message && $quantity <= 0) { $availability_text = $custom_stock_message; } elseif (!$custom_stock_message && $quantity <= 0) { $availability_text = __('Right now is not available', 'woocommerce'); } else { $availability_text = __('Finns i lager', 'woocommerce'); } } } echo __('Artnr') . ' (' . $sku . ')' . ': ' . $availability_text . '<br>'; } ?> <?php } ?>
额外:处理已存在的旧订单
上面的代码只对新订单生效,如果你需要让旧订单也显示下单时的原始内容,可以运行下面的一次性脚本(建议先备份数据库):
// 批量补存旧订单的订单项快照(运行一次后删除) add_action('admin_init', 'retroactively_save_old_order_snapshots'); function retroactively_save_old_order_snapshots() { // 仅管理员可运行 if (!current_user_can('manage_options')) return; // 可设置订单日期范围,避免一次性处理过多订单 $orders = wc_get_orders(array( 'date_created' => '<2023-01-01', 'limit' => -1, // 全部订单,数据量大建议分批处理 )); foreach ($orders as $order) { foreach ($order->get_items() as $item) { $product = $item->get_product(); if (!$product) continue; $custom_text = ''; $quantity = $item->get_quantity(); $availability_text = ''; if ($product->is_type('variation')) { $custom_text = get_post_meta($product->get_id(), 'custom_field', true); if (!empty($custom_text) && $quantity <= -1) { $availability_text = $custom_text; } elseif (empty($custom_text) && $quantity <= -1) { $availability_text = __('Right now is not available', 'woocommerce'); } else { $availability_text = __('Finns i lager', 'woocommerce'); } } elseif ($product->is_type('simple')) { $custom_text = get_post_meta($product->get_id(), 'custom_stock_message', true); if (!empty($custom_text) && $quantity <= 0) { $availability_text = $custom_text; } elseif (empty($custom_text) && $quantity <= 0) { $availability_text = __('Right now is not available', 'woocommerce'); } else { $availability_text = __('Finns i lager', 'woocommerce'); } } // 保存快照到订单项 if (!empty($custom_text)) { $item->update_meta_data('_custom_stock_snapshot', $custom_text); } $item->update_meta_data('_availability_snapshot', $availability_text); $item->save(); } $order->save(); } // 运行完成后移除钩子,避免重复执行 remove_action('admin_init', 'retroactively_save_old_order_snapshots'); echo '旧订单快照补存完成!'; exit; }
将这段代码临时加到主题的functions.php中,登录后台访问任意页面即可触发运行,完成后记得删除这段代码。
内容的提问来源于stack exchange,提问作者Eyahya Khan
相关产品推荐
相关产品推荐

