I'm trying to make a plugin that merges two carts into one.

I am doing the following:

$old_order = wc_get_order($old_order_id);
duplicate_line_items($new_order, $old_order);
//re-fetch order to make sure changes aren't lost.
$new_order = $wc_get_order($new_order->get_id());

My duplicate_line_items() function looks like this:

function duplicate_line_items($source_order, $new_order){
    foreach ($source_order->get_items() as $item){

When I run this code, the items do not display in the admin view of the "new" order (the destination order), nor do they show up in the database.

I do see that per the WC_Order::add_item() docs, "The order item will not persist until save.", but I am saving the order, several times.

Am I missing a step here or something?


You have your duplicate_line_items() function written so that the items from the first parameter, $source_order are added to the second parameter, $new_order, but in your first block of code you're passing the old order as the 2nd parameter:

duplicate_line_items($new_order, $old_order);

So all the items from $new_order are being added to $old_order, not the other way round.

Make sure you're using the variables consistently:

duplicate_line_items( $old_order, $new_order );

Maybe name your variables in duplicate_line_items() a bit more clearly too:

function duplicate_line_items( $source_order, $target_order ) {
    foreach ( $source_order->get_items() as $item ) {
        $target_order->add_item( $item );


So with those two changes you're properly setting $old_order as the $source_order and $new_order as the $target_order.

  • I know it looks confusing, but what's actually being done here is on checkout i'm copying items from the "new" order (aka the "source" order) to the "old" order, aka the target order – zack6849 Dec 7 at 13:02
  • So when you say "the items do not display in the admin view of the "new" order", you mean they don't show up in the old order? Yes, that is confusing... – Jacob Peattie Dec 7 at 13:17
  • They don't no, but I fixed it and posted an answer, – zack6849 Dec 7 at 13:44
up vote 0 down vote accepted

I've solved my issue, I misunderstood the functionality of wc_add_order_item()'s item_array parameter, and assumed that was for the item data.

The working function:

     * Copy all line items from
     * @param $source_order \WC_Order
     * @param $destination_order \WC_Order
    private function duplicate_line_items($source_order, $destination_order){
        //get all item types.
        foreach ($source_order->get_items(['line_item', 'shipping', 'tax']) as $item_id => $item){
            $data = $item->get_data();
            $data['order_id'] = $destination_order->get_id();
            $new_item_id = wc_add_order_item($destination_order->get_id(), ['order_item_name' => $item->get_name(), 'order_item_type' => $item->get_type()]);
            $meta = wc_get_order_item_meta($item_id);
            foreach ($meta as $meta_key => $meta_value){
                //needed incase there are multiple values for the same key: eg, ingredients.
                foreach ($meta_value as $number => $raw_value){
                    wc_add_order_item_meta($new_item_id, $meta_key, $raw_value);

Hopefully this helps someone else later :)

Your Answer

By clicking "Post Your Answer", you acknowledge that you have read our updated terms of service, privacy policy and cookie policy, and that your continued use of the website is subject to these policies.

Not the answer you're looking for? Browse other questions tagged or ask your own question.