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 are 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.

Empty order in WooCommerce
This is just an empty order in WooCommerce on its edit page.

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.

create order programmatically and add products to order
A simple product and a product variation both have been added as order items.

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 order items while creating order programmatically

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 billing and shipping addresses to an order
Of course billing and shipping addresses may differ.

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

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

Follow me on Twitter