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?


closed as off-topic by Jacob Peattie, rudtek, fuxia Jan 4 at 22:40

This question appears to be off-topic. The users who voted to close gave this specific reason:

If this question can be reworded to fit the rules in the help center, please edit the question.


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 '18 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 '18 at 13:17
  • They don't no, but I fixed it and posted an answer, – zack6849 Dec 7 '18 at 13:44

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 :)

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