Woo Dev Patch – Add a Product to a WooCommerce Order

Adding a product to an existing WooCommerce order programmatically is useful when an order needs to be updated after it has been created. This can be required for custom workflows, order adjustments, automated processes, or integrations that need to add an additional product to an existing order.

WooCommerce provides methods for adding products directly to an order, but simply adding the item is not enough. The order totals and other calculated values also need to be updated before the changes are saved.

In this Woo Dev Patch, we’ll look at how to add a product to an existing WooCommerce order programmatically, including how to set the quantity, update the order totals, and save the changes correctly.

Get the Order

$order = wc_get_order( $order_id );

If you are creating a new order programmatically:

$order = wc_create_order();

Get the Product

Retrieve the product using its product ID:

$product = wc_get_product( $product_id );

Add the Product to the Order

Before adding the product, it is advisable to check that a valid product object was returned.

if ( $product ) {
    $quantity = 2;
    $item_id  = $order->add_product( $product, $quantity );
}

add_product() creates the product line item and populates the relevant product, quantity, price, tax class, and other order item data.

Update the Order Totals

Once the product is added, the order totals need to be recalculated. Adding a product does not by itself recalculate the order totals.

$order->calculate_totals();

calculate_totals() recalculates the order totals and, by default, also calculates taxes.

If you need to explicitly control the tax class or tax calculation when adding a product, see this code snippet.

Save the Order

Finally, save the order:

$order->save();

Complete Example

The following example creates a new order, adds a product with a quantity of 2, recalculates the totals, and saves the order:

$order = wc_create_order();
// Add product with ID 145.
$product = wc_get_product( 145 );
if ( $product ) {
    $quantity = 2;
    $item_id  = $order->add_product( $product, $quantity );
    if ( $item_id && $item_id > 0 ) {
        $item = $order->get_item( $item_id );
        // Set the item class already present in product.
        $item->set_tax_class( $product->get_tax_class() );
    }
    $order->calculate_taxes();
    $order->calculate_totals();
    $order->save();

If you are adding a product to an existing order, replace wc_create_order() with wc_get_order( $order_id ).

Add a variation

If you want to add a variation to the order, retrieve the variation using its variation ID:

$product = wc_get_product( $variation_id );

The returned object represents the variation, so it can be passed to add_product() in the same way as a regular product.

Adding a Product at a Custom Price

Sometimes, you may need to add a product at a discounted or quoted price instead of the original product price.

You can pass the subtotal and total values to add_product():

if ( $product ) {
    $custom_price = 110;
    $quantity     = 2;
    $item_id      = $order->add_product(
        $product,
        $quantity,
        array(
            'subtotal' => $custom_price * $quantity,
            'total'    => $custom_price * $quantity,
        )
    );
    if ( $item_id ) {
        $order->calculate_totals();
        $order->save();
    }
}

Common Mistake

Make sure you check whether wc_get_product() returned a valid WC_Product or variation object before attempting to add it to the order.

Also, use add_product() when adding a product to an order. The add_item() method is intended for adding a WC_Order_Item object that has already been created, rather than a WC_Product object.

HPOS Compatibility

This code is compatible with both HPOS and the legacy WooCommerce order storage system. The WooCommerce CRUD APIs used here handle the underlying order storage, so the code does not need to change depending on which order storage system the store uses.

Using the WooCommerce order APIs also avoids directly modifying the underlying order database tables.

Tested with:

  • WordPress 7.1.0
  • WooCommerce 11.1.0

Leave a Comment

Your email address will not be published. Required fields are marked *

Scroll to Top