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

求助:解决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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.29 12:52:46