In this tutorial I want to talk about WooCommerce order items. To understand what I mean, just look at the screenshot below:

You can see the Edit Order page with products purchased, shipping and fee. All of these are order items:

  • products – line_item type,
  • shipping – shipping type,
  • fee – fee type

Order items has their own tables in WordPress database – {prefix}woocommerce_order_items and {prefix}woocommerce_order_itemmeta.

What is the reason in creating a separate database table for products in an order than linking them by IDs? Actually the reason is really simple. Let’s say that someone purchased a snowboard from your store. A couple days ago the price of this snowboard has been changed… But we can not change it in that order! Did you get it?

How to do some magic with Order Items in code

Get

Let’s begin with WC_Order’s get_items() that returns all products in an order. But why? – order items are not only products, shipping and fee are also order items, aren’t they?

Sure, get_items() returns only products because it has the only parameter $types that is line_item by default. Anyway we can pass an array instead: get_items( array('line_item', 'fee', 'shipping').

$order_items = $order_object->get_items( array('line_item', 'fee', 'shipping') );
if ( !is_wp_error( $order_items ) ) {
	foreach( $order_items as $item_id => $order_item ) {
		echo $order_item->get_order_id();
		echo $order_item->get_name();
		echo $order_item->get_total(); // item price
		echo $order_item->get_type(); // line_item | fee | shipping

		// for products only:
		echo $order_item->get_quantity(); // or $order_item['quantity'];
		echo $order_item->get_product_id(); // or $order_item['product_id'];
		echo $order_item->get_variation_id(); // or $order_item['variation_id'];
		echo $order_item->get_product(); // get the associated product
	}
}

Add

Actually you can add the order items to an order when you create it with wc_create_order() function. But today we’re not talking about the orders themselves, so I suppose that an order with some $order_id is already exists and we want to add order items to it in the code:

// add an order item linked to a product
$order_item_id = wc_add_order_item( $order_id, array(
	'order_item_name' => 'Some product',
	'order_item_type' => 'line_item', // product
));
wc_add_order_item_meta( $order_item_id, '_qty', 2, true ); // quantity
wc_add_order_item_meta( $order_item_id, '_product_id', 13, true ); // ID of the product
// you can also add "_variation_id" meta
wc_add_order_item_meta( $order_item_id, '_line_subtotal', 10, true ); // price per item
wc_add_order_item_meta( $order_item_id, '_line_total', 20, true ); // total price

// add a fee order item
$order_item_id = wc_add_order_item( $order_id, array(
 	'order_item_name' => 'Some fee',
 	'order_item_type' => 'fee',
));
wc_add_order_item_meta( $order_item_id, '_fee_amount', 20, true );
wc_add_order_item_meta( $order_item_id, '_line_total', 20, true );

$order = new WC_Order( $order_id );
$order->calculate_totals();

If you would like to add a shipping order item, use shipping order_item_type and cost parameter to pass the shipping price and method_id as a shipping type.

Update

To update the existing order items you can use wc_update_order_item( $item_id, $args), where $args is the array with the same parameters wc_add_order_item() accepts and wc_update_order_item_meta( $item_id, $key, $value, $prev_value ).

If you want to reattach an order item to another order, this code will help:

wc_update_order_item( $order_item_id, array( 'order_id' => $new_order_id ) );

If you just would like to change the quantity of the product from the above example, you can use this code:

wc_update_order_item_meta( $order_item_id, '_qty', 3 );
wc_update_order_item_meta( $order_item_id, '_line_total', 30 );

Remove

The cool thing is that when you remove an order item with wc_delete_order_item( $order_item_id ) you shouldn’t care about deleting all its metadata, because it will be removed automatically.

But if you just want to delete some meta, wc_delete_order_item_meta( $item_id, $key, $value, $delete_all ). The required parameters are only $item_id and $key.

Add a custom product meta to an associated order item automatically

It is very easy to do, woocommerce_add_order_item_meta action hook will help you with it:

add_action( 'woocommerce_add_order_item_meta', 'misha_order_item_meta', 10, 2 );

// $item_id – order item ID
// $cart_item[ 'product_id' ] – associated product ID (obviously)
function misha_order_item_meta( $item_id, $cart_item ) {

	// get product meta
	$event_time = get_post_meta( $cart_item[ 'product_id' ], 'event_time', true );

	// if not empty, update order item meta
 	if( ! empty( $event_time ) ) {
		wc_update_order_item_meta( $item_id, 'event_time', $event_time );
	}
	
}

How to check if order item meta is added?

With the help of this tutorial you can create a column with purchased products and print your order item meta by key

foreach( $order_items as $order_item_id => $order_item ) {
	echo wc_get_order_item_meta( $order_item_id, 'event_time');
}

Another way – check your Edit Order page