Create Orders Programmatically
In this tutorial we are going to dive deep into creating an order on your WooCommerce store completely via code. I already have a similar tutorial on my blog where we created a product programmatically.
First things first, you should know a very simple thing – yeah, orders is a WordPress custom post type and no, we can not use wp_insert_post()
to create them. We have to use a CRUD layer for that. If it says nothing to you, please be patient, we’re going to dive into it in just a little bit.
The long story short an order can be created with as far as one simple line of code.
$order = wc_create_order();
/* here we can add products, shipping, change status etc */
Do not believe me? Well, just try these lines by yourself and here we are.

Oh, and yes, do not use this code too early! Because if CPT is not registered yet, nothing will happen.
Add Order Items
In this chapter we are going to talk how to add any kind of order items to our newly created order.
Order items are products, fees, shipping and coupons in case you didn’t know. And also you can check my another tutorial specifically about order items.
Add Products to an Order
Well, the empty orders are ok, I’m sure you’re using them every day. But what about adding some products to it? add_product()
method should be super-helpful here for every kind of products, it works for product variations as well. But it is also possible to use add_item()
method, which is a little bit more complicated, you can find example here.
In the example below we are going to add a simple product with ID = 136 (and quantity 2) and a variable product with product variation ID = 70.
$order = wc_create_order();
$order->add_product( wc_get_product( 136 ), 2 );
$order->add_product( wc_get_product( 70 ) );
$order->calculate_totals();
We have to use calculate_totals()
method as well because without that order total is going to be zero.

Add Fee
For fees, shipping and coupons we can use add_item()
method of WC_Order
class. The only thing is that you need to create an order item object before adding it to an order using appropriate classes like WC_Order_Item_Fee
, WC_Order_Item_Shipping
and
.WC_Order_Item_Coupon
// create Fee object
$fee = new WC_Order_Item_Fee();
$fee->set_name( 'Some fee' );
$fee->set_amount( 20 );
$fee->set_total( 20 );
// add to order
$order = wc_create_order();
$order->add_item( $fee );
$order->calculate_totals();
More examples about adding fees to an order you can find here.
Add Shipping
In case you would like to add a shipping method to an order programmatically, please use WC_Order_Item_Shipping
class and you will also need an existing shipping method ID. How to find it I mentioned in this tutorial.
// create shipping object
$shipping = new WC_Order_Item_Shipping();
$shipping->set_method_title( 'Free shipping' );
$shipping->set_method_id( 'free_shipping:1' ); // set an existing Shipping method ID
$shipping->set_total( 0 ); // optional
// add to order
$order = wc_create_order();
$order->add_item( $shipping );
$order->calculate_totals();
Let’s check out this order in WordPress admin now.

Add Coupons
Super-easy!
$order = wc_create_order();
$order->apply_coupon( 'blackfriday13' )
There is also a difficult way how you can add coupons to an order using WC_Order_Item_Coupon
class and add_item()
method of WC_Order
class, I described it here.
Add Billing and Shipping Addresses to an Order
In order to add either a billing or shipping addresses we are going to use the same method set_address()
, the only difference is in its second parameter.
$order->set_address( $address, 'billing' )
– billing address,$order->set_address( $address, 'shipping' )
– shipping address.
By the way WC_Order
class has more specific methods, like set_billing_first_name()
, set_shipping_address_1()
etc, but I think there is no point of using them here.
Ok, so let’s do it right now.
$address = array(
'first_name' => 'Misha',
'last_name' => 'Rudrastyh',
'company' => 'rudrastyh.com',
'email' => 'no-reply@rudrastyh.com',
'phone' => '+995-123-4567',
'address_1' => '29 Kote Marjanishvili St',
'address_2' => '',
'city' => 'Tbilisi',
'state' => '',
'postcode' => '0108',
'country' => 'GE'
);
$order = wc_create_order();
$order->set_address( $address, 'billing' );
$order->set_address( $address, 'shipping' );
I hope everything should be crystal clear from the code snippet above. In case you’re not sure what is your country code in ISO-3166-1 alpha-2, you can check it here.

Add Customer Information to an Order
By a customer in WooCommerce I mean an existing WordPress user on the website. By default orders are created for a Guest user (you can check it on a screenshot above by the way). So, if you would like to assign an existing WordPress user, you have to use set_customer_id()
method. There is also set_customer_ip_address()
method that could be helpful.
As simple as that:
$order = wc_create_order();
$order->set_customer_id( 1 );
$order->set_customer_ip_address( '10.1.1.1' );
Add Payment Method
Here we are going to use two methods and they are set_payment_method()
and set_payment_method_title()
. In the first one you need to pass a payment method ID (the best way how to find it is described here), in the second one please pass any title you are going to use for this payment method for this particular order.
$order = wc_create_order();
$order->set_payment_method( 'stripe' );
$order->set_payment_method_title( 'Credit/Debit card' );
In WooCommerce < 3.0 you were supposed to pass WC_Payment_Gateway
object inside set_payment_method()
method like this:
// WooCommerce < 3.0
$payment_gateways = WC()->payment_gateways->payment_gateways();
$order->set_payment_method( $payment_gateways[ 'stripe' ] );
So you may find this obsolete implementation over the internet as well.
Assign an Order Status
There are two WC_Order
methods available that allow to assign an order status – set_status()
and update_status()
. The difference is that the first one is just make changes in an order object, but doesn’t update the information in database, and the second one do make changes and update the status in database as well. So if you are going to use set_status()
, you are also supposed to use save()
method.
$order = wc_create_order();
$order->set_status( 'wc-completed' );
// $order->set_status( 'wc-completed', 'You can pass some order notes here...' );
$order->save();
The list of order statuses:
wc-pending
– Pending payment (Default),wc-processing
– Processing,wc-on-hold
– On hold,wc-misha-shipping
– Awaiting shipping,wc-completed
– Completed,wc-cancelled
– Cancelled,wc-refunded
– Refunded,wc-failed
– Failed,- or any custom order status.
And yes, you can use an order status name without wc-
prefix.
Complete code
Just for your convenience.
$order = wc_create_order();
// add products
$order->add_product( wc_get_product( 136 ), 2 );
$order->add_product( wc_get_product( 70 ) );
// add shipping
$shipping = new WC_Order_Item_Shipping();
$shipping->set_method_title( 'Free shipping' );
$shipping->set_method_id( 'free_shipping:1' ); // set an existing Shipping method ID
$shipping->set_total( 0 ); // optional
$order->add_item( $shipping );
// add billing and shipping addresses
$address = array(
'first_name' => 'Misha',
'last_name' => 'Rudrastyh',
'company' => 'rudrastyh.com',
'email' => 'no-reply@rudrastyh.com',
'phone' => '+995-123-4567',
'address_1' => '29 Kote Marjanishvili St',
'address_2' => '',
'city' => 'Tbilisi',
'state' => '',
'postcode' => '0108',
'country' => 'GE'
);
$order->set_address( $address, 'billing' );
$order->set_address( $address, 'shipping' );
// add payment method
$order->set_payment_method( 'stripe' );
$order->set_payment_method_title( 'Credit/Debit card' );
// order status
$order->set_status( 'wc-completed', 'Order is created programmatically' );
// calculate and save
$order->calculate_totals();
$order->save();

Misha Rudrastyh
Hey guys and welcome to my website. For more than 10 years I've been doing my best to share with you some superb WordPress guides and tips for free.
Need some developer help? Contact me
Thanks a lot for this one, Misha! Needed to programmatically create new orders while testing WooCommerce webhooks for a project, and this is a complete tutorial on how to create orders programmatically.
Thank you from the whole heart. You are my best fiend man.
I really like your tutorials. You helped me a lot setting up a custom payment gateway! :D Do you know a hook I can use when creating orders with php?
woocommerce_new_order
is nice but I can’t get the shipping data via get_items().If I use
woocommerce_checkout_order_processed
it works, but only gets triggered if an order if created on the frontend.@Jay
some actions aren’t taken if the order isn’t saved `$order->save()` perhaps your action needs to run after?