How to create a custom order status in woocommerce!

Woocommerce has 7 order statuses the moment you install it in your wordpress website(pending, failed, on-hold, cancelled, refunded and completed). These statuses are enough for an ecommerce website’s order processes but some might want to add more steps on it.

Just like what happened to me, one of my clients asked for a new order status. My client wanted to add a shipped order status because they want their customers be notified when the item(s) they’ve bought are being shipped.

Here are the steps of how I did it.

This code will check the order status shipped and if it doesn’t exists, it will going to add shipped on order status drop-down list.

add_action( 'init', function() {
    $term = get_term_by( 'name', 'shipped', 'shop_order_status' );
    if ( ! $term ) {
        wp_insert_term( 'shipped', 'shop_order_status' );
} );

You’ll be surprised seeing your custom order status added there.

Our next step is to make it look cool when the order status is shipped.

The code below will let you insert anything in the head tag of your wordpress backend and we’re going to use it to insert our css.

function insert_new_css() {
   echo '<style> { background: url("'.get_stylesheet_directory_uri().'/images/shipped.png") no-repeat scroll 50% center rgb(45, 178, 0) !important; }
add_action('admin_head', 'insert_new_css');

This is the image I used.

Now try to change the status of one of the order to shipped and look the result of it.

Great right?

Our next goal is to add shipped order status in the bulk actions, so you can change multiple order status at once.

The code below will add the Mark as Shipped in bulk actions below the Mark as completed.

add_action('admin_footer-edit.php', 'custom_bulk_admin_footer');
function custom_bulk_admin_footer() {
  global $post_type;
  if($post_type == 'shop_order') {
    <script type="text/javascript">
      jQuery(document).ready(function() {
        jQuery('<option>').val('shipped').text('<?php _e('Mark as Shipped')?>').appendTo("select[name='action']");
        jQuery('<option>').val('shipped').text('<?php _e('Mark as Shipped')?>').appendTo("select[name='action2']");

The last part is to add a function to it, like email the customer that his order is being shipped.

This is the content of the email that will be sent to the customer

function send_this($email) {

	$headers = 'From: My Store <[email protected]>' . "\r\n";
	$headers .= "MIME-Version: 1.0\r\n";
	$headers .= "Content-Type: text/html; charset=ISO-8859-1\r\n";
	$subject = 'Your Order has been shipped';

	$message = '<p><strong>Shipping Confirmation</strong><br />
	Your order has been shipped and is currently in transit.</p>
	<small>If you have not received your order in 7 business days, please send us an email at <a href="mailto:[email protected]">[email protected]</a></small>';	
	wp_mail( $email, $subject, $message, $headers ); 

This is the code that will update the order status.

function change_order_status($orderid) {
	$order = new WC_Order($orderid);
	$email = get_post_meta( $orderid, '_billing_email' )[0];
	if($order->status!='shipped') {
		$order->update_status('shipped', 'order_note');

The function for the bulk actions.

add_action('load-edit.php', 'custom_bulk_action');
function custom_bulk_action() {
	global $typenow;
	$post_type = $typenow;
	$sendback = admin_url( "edit.php?post_type=$post_type&success=1" );
	if($post_type == 'shop_order') {
		$wp_list_table = _get_list_table('WP_Posts_List_Table');
		$action = $wp_list_table->current_action();
		$allowed_actions = array("shipped");
		if(!in_array($action, $allowed_actions)) return;
		if(isset($_REQUEST['post'])) {
			$orderids = array_map('intval', $_REQUEST['post']);
		switch($action) {
			case "shipped":
				foreach( $orderids as $orderid ) {
			default: return;

The function for saving the order status individually.

add_action( 'woocommerce_order_status_shipped', 'order_status_shipped_custom');
function order_status_shipped_custom($orderid) {

The function to display a successful message.

add_action('admin_notices', 'custom_bulk_admin_notices');
function custom_bulk_admin_notices() {
  global $post_type, $pagenow;
  if( $post_type == 'shop_order' && isset($_GET['success']) ) {
    echo '<div class="updated"><p>The orders have been successfully shipped!</p></div>';

Okay that’s it! That’s how I did to create a custom order status.