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

通过WooCommerce REST API同步站点时的订单重复问题

WooCommerce跨站点订单同步重复创建问题解决

问题根源

核心问题是缺少源订单ID与目标订单ID的映射机制,每次cron任务运行都会拉取所有源订单并重复创建;之前尝试的两种方案都存在缺陷:

  • 直接复用源订单ID更新:导致订单项累加,因为PUT请求会追加订单项而非替换现有内容
  • 给订单项添加源ID:目标站点的订单项ID是本地生成的,无法识别源站点的ID,因此触发woocommerce_rest_invalid_item_id错误

解决方案步骤

1. 建立订单ID映射存储

利用WordPress的wp_options表存储源订单ID和目标订单ID的对应关系,快速判断订单是否已完成同步。

2. 优化订单拉取逻辑

通过WooCommerce API的modified_after参数,只拉取上次同步之后更新的订单,减少不必要的请求开销。

3. 区分创建/更新操作

对每个源订单,先检查映射关系:

  • 存在对应目标ID:调用PUT请求更新订单,更新前先清空原有订单项再重新添加
  • 不存在对应目标ID:调用POST请求创建新订单,成功后记录映射关系

4. 正确处理订单项更新

更新订单时必须先删除目标订单的所有现有订单项,再添加源订单的订单项,彻底解决累加问题。

修改后的完整代码

// Cron Schedule to Run the Code
add_filter('cron_schedules', 'add_every_minute_interval');

function add_every_minute_interval($schedules) {
    $schedules['every_minute'] = array(
        'interval' => 60, 
        'display' => __('Every Minute')
    );
    return $schedules;
}

add_action('wp_loaded', 'schedule_order_sync');

function schedule_order_sync() {
    if (!wp_next_scheduled('sync_orders_event')) {
        wp_schedule_event(time(), 'every_minute', 'sync_orders_event');
    }
}

add_action('sync_orders_event', 'sync_orders_from_source_to_destination');

// 获取订单ID映射
function get_order_id_mapping() {
    $mapping = get_option('wc_order_sync_mapping', array());
    return is_array($mapping) ? $mapping : array();
}

// 保存订单ID映射
function save_order_id_mapping($source_order_id, $dest_order_id) {
    $mapping = get_order_id_mapping();
    $mapping[$source_order_id] = $dest_order_id;
    update_option('wc_order_sync_mapping', $mapping);
}

// 删除目标订单的所有订单项
function delete_all_order_items($dest_order_id, $api_url, $consumer_key, $consumer_secret) {
    $url = $api_url . '/wp-json/wc/v3/orders/' . $dest_order_id . '/items';
    $response = wp_remote_get($url, array(
        'headers' => array(
            'Authorization' => 'Basic ' . base64_encode($consumer_key . ':' . $consumer_secret),
        ),
    ));

    if (is_wp_error($response)) return false;

    $items = json_decode(wp_remote_retrieve_body($response), true);
    if (!is_array($items)) return true;

    foreach ($items as $item) {
        $delete_url = $url . '/' . $item['id'];
        wp_remote_delete($delete_url, array(
            'headers' => array(
                'Authorization' => 'Basic ' . base64_encode($consumer_key . ':' . $consumer_secret),
            ),
        ));
    }
    return true;
}

// 创建或更新目标站点订单
function upsert_order_on_destination_site($source_order_id, $order_data, $api_url, $consumer_key, $consumer_secret) {
    $mapping = get_order_id_mapping();
    
    // 检查订单是否已同步
    if (isset($mapping[$source_order_id])) {
        $dest_order_id = $mapping[$source_order_id];
        $url = $api_url . '/wp-json/wc/v3/orders/' . $dest_order_id;

        // 更新前删除所有现有订单项
        delete_all_order_items($dest_order_id, $api_url, $consumer_key, $consumer_secret);

        // 执行更新请求
        $response = wp_remote_post($url, array(
            'method' => 'PUT',
            'headers' => array(
                'Authorization' => 'Basic ' . base64_encode($consumer_key . ':' . $consumer_secret),
                'Content-Type' => 'application/json',
            ),
            'body' => json_encode($order_data),
        ));
    } else {
        $url = $api_url . '/wp-json/wc/v3/orders';
        // 执行创建请求
        $response = wp_remote_post($url, array(
            'headers' => array(
                'Authorization' => 'Basic ' . base64_encode($consumer_key . ':' . $consumer_secret),
                'Content-Type' => 'application/json',
            ),
            'body' => json_encode($order_data),
        ));
    }

    if (is_wp_error($response)) {
        return false;
    }

    $body = wp_remote_retrieve_body($response);
    $processed_order = json_decode($body, true);

    // 新订单创建成功后保存映射
    if (!isset($mapping[$source_order_id]) && $processed_order && isset($processed_order['id'])) {
        save_order_id_mapping($source_order_id, $processed_order['id']);
    }

    return $processed_order;
}

// 从源站点拉取增量订单
function get_orders_from_source_site($api_url, $consumer_key, $consumer_secret) {
    $last_sync_time = get_option('wc_last_order_sync_time', '2000-01-01T00:00:00');
    $url = $api_url . '/wp-json/wc/v3/orders?modified_after=' . urlencode($last_sync_time);
    
    $response = wp_remote_get($url, array(
        'headers' => array(
            'Authorization' => 'Basic ' . base64_encode($consumer_key . ':' . $consumer_secret),
        ),
    ));

    if (is_wp_error($response)) {
        return array();
    }

    $body = wp_remote_retrieve_body($response);
    $orders = json_decode($body, true);

    // 更新上次同步时间为当前UTC时间
    update_option('wc_last_order_sync_time', gmdate('Y-m-d\TH:i:s'));

    return $orders;
}

// 主同步函数
function sync_orders_from_source_to_destination() {
    // 源站点API信息
    $sourceSiteApiUrl = 'https://source.com';
    $sourceConsumerKey = 'xxxxxxxxxxxxxxxxxxxx';
    $sourceConsumerSecret = 'xxxxxxxxxxxxxxxxxxxx';

    // 目标站点API信息
    $destinationSiteApiUrl = 'https://destination.com';
    $destinationConsumerKey = 'xxxxxxxxxxxxxxxxxxxx';
    $destinationConsumerSecret = 'xxxxxxxxxxxxxxxxxxxx';

    // 拉取增量订单
    $orders = get_orders_from_source_site($sourceSiteApiUrl, $sourceConsumerKey, $sourceConsumerSecret);

    if (!empty($orders) && is_array($orders)) {
        foreach ($orders as $order) {
            if (isset($order['id'], $order['status'], $order['customer_id'])) {
                $source_order_id = $order['id'];
                $first_name = $order['billing']['first_name'];
                $last_name = $order['billing']['last_name'];
                $phone = $order['billing']['phone'];

                $line_items_data = array();
                if (isset($order['line_items']) && is_array($order['line_items'])) {
                    foreach ($order['line_items'] as $item) {
                        $line_item_data = array(
                            'name' => $item['name'],
                            'quantity' => $item['quantity'],
                            'price' => $item['price'],
                            'subtotal' => $item['subtotal'],
                            'total' => $item['total'],
                            'product_id' => $item['product_id'],
                        );
                        $line_items_data[] = $line_item_data;
                    }
                }

                // 组装同步用的订单数据
                $order_data = array(
                    'status' => $order['status'],
                    'customer_id' => $order['customer_id'],
                    'billing' => array(
                        'first_name' => $first_name,
                        'last_name' => $last_name,
                        'phone' => $phone,
                    ),
                    'line_items' => $line_items_data,
                    // 可添加其他需要同步的字段(如配送信息、付款方式等)
                );

                // 执行创建/更新操作
                $processed_order = upsert_order_on_destination_site($source_order_id, $order_data, $destinationSiteApiUrl, $destinationConsumerKey, $destinationConsumerSecret);

                if ($processed_order) {
                    echo (isset($mapping[$source_order_id]) ? 'Updated' : 'Created') . ' Order ' . $processed_order['id'] . ' on destination site';
                } else {
                    echo 'Failed to process order ' . $source_order_id . ' on destination site';
                }
            } else {
                echo 'Order data is missing required fields';
            }
        }
    } else {
        echo 'No orders fetched from the source site';
    }
}

关键修改说明

  • 订单映射机制:新增get_order_id_mapping和save_order_id_mapping函数,用wc_order_sync_mapping选项持久化存储源与目标订单的ID对应关系
  • 增量拉取优化:get_orders_from_source_site函数通过modified_after参数实现增量同步,避免每次拉取全量订单
  • Upsert逻辑:upsert_order_on_destination_site函数自动判断订单状态,分别执行创建或更新操作
  • 订单项清理:更新订单前调用delete_all_order_items删除目标订单的所有订单项,彻底解决订单项累加问题

内容的提问来源于stack exchange,提问作者Vanda Nojan - وندا نوژن

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.29 02:29:53