CommerceCategory

WooCommerce Wednesdays: WooCommerce order management guide

22 min read
Bradley Taylor

An accurate and efficient order management system is key to streamlined ecommerce operations. Accurate WooCommerce order management is less challenging when you only have a few sales, but once your business starts to pickup, errors are inevitable.

Sending packages to the wrong address, or shipping the wrong product can destroy your business reputation in a hurry.

Well-planned order management not only streamlines the entire fulfillment process, but it also help reduce the number of unneeded errors. The time spent fixing fulfillment issues is time that you could spend on the activities that help grow your business, whether it’s coming up with new product ideas or growing your brand.

In this post, we will outline how you can use WooCommerce and a few handy extensions to create a streamlined order management flow for your ecommerce business.

Ecommerce order fulfillment basics

When a retailer receives an order from a customer, there are a variety of steps needed to process the order. This includes everything from receiving, tracking, and fulfilling customer orders. Let’s examine the most integral steps in the typical WooCommerce order management process:

Picking

When a customer places an order, someone from the warehouse needs to pick all the items from the shelves. It is a simple task but can quickly become time-consuming if you run a larger warehouse.

Packing

The packing process is where the items are weighed and given the appropriate shipping materials and labels. The packing slip lists the content of the package, including the weight, dimensions, item details, quantities and SKU numbers.

Shipping

The final step of the fulfillment process is the shipping and delivery. Item are taken to or picked up by the carrier, entering their logistics network until the package reaches the customer.

WooCommerce orders management

The WooCommerce platform includes a native order management dashboard. Here are the key components of the WooCommerce order management interface:

Viewing all orders

The WooCommerce > Orders page provides a comprehensive of all your past and present orders.

When you visit the page, you’ll find all your WooCommerce orders listed in a table. Each order contains the order #, customer name, date, status, export status, and order total.

The final column of the dashboard is for Shipment tracking. This will display the tracking number, URL, and carrier for the delivery. You can apply this number to each order manually from the dashboard.

If you use third-party extensions, they may add details to the dashboard.

For instance, in our example you can see a column for Pickup Locations as well as Subscription relationship

If you want to edit your orders in bulk, you can do so from the dashboard. Click the Bulk actions window to reveal the options. For example, you could change the order status for a group of orders from processing to completed.

The dashboard features several filters you can use to refine the orders. The date filter lets you select a specific month. With the customer filter, you can enter a customer’s name into the search bar and the filter will populate all matching users.

Note, this filter will only work for customers that registered for an account. If a customer completed the purchase using a guest checkout you will not be able to search by their name.

You can also filter by order type. This is useful if you accept alternative forms of orders such as memberships or subscriptions.

Order statuses

Below are the different statuses for WooCommerce order management:

  • Pending installment — Order received but not paid
  • Failed — Payment failed or was declined
  • Processing — Payment received and stock levels have been updated.
  • On-Hold — Awaiting payment and stock levels have been updated.
  • Finished — Refunded by administrator
  • Canceled — Canceled by an admin or the customer

Searching for orders

You can find specific orders using the search box in the upper-right corner of the dashboard. The search supports order numbers, customer names, and other order details like the billing address. After you click Search, the platform will display the matching orders.

Viewing single orders

To review the details for a single order, click the link in the Order column. From the order page, you can see the various order details including the customer’s address, phone number, account status, and order status.

The interface allows you to edit most of these variables. You can change the date and time by using the dropdown date and quantity selectors. It also enables you to change the customer and order status using the same method.

The order actions window gives you several tools for managing the order. You can send an invoice to the customer or resend the order notification to the appropriate admin.

Additionally, you can perform actions for different WooCommerce extensions. For example, if you use WooCommerce Vendors to manage a multi-vendor marketplace you can use the order actions to generate a vendor commission.

With the Managed WooCommerce Stores plan from GoDaddy, you get a separate panel for shipment tracking. Here, you can add the tracking number and carrier information like you can from the orders dashboard.

Order notes

The order notes panel displays status changes and updates for the transaction. Different actions like payments and changes to stock levels will be automatically reflected in the order notes.

You can also use the panel to add your own custom notes.

The notes are displayed in one of three colors:

  • Purple — Indicates a status notice such as payment gateway details.
  • Grey — Notes are for general status updates including status changes and private notes.
  • Blue — Notes are notifications sent to customers via email.

If an order is delayed you can quickly add a note that will go to the customer. They will then be automatically notified.

Custom fields

The custom fields section lets you apply your variables to your orders. They do so by adding extra metadata.

Handling orders with the WooCommerce order management system

Creating orders

You can also add your orders manually. To create a new order, select Add order from the dashboard. This will take you to an order page that mirrors the typical record for an order. All the essential fields are editable and you will use these to create the new order.

Paying for pending orders

You can pay for pending orders using the payment link from the order overview.

The customer’s access to the payment link will depend on whether they signed in to complete the purchase.

If the customer is a guest, anyone with the link can view and use the payment page. If the customer is a registered user, they will need to log in to access the link. The customer can do so by going to My Account > Orders.

How to improve WooCommerce order management with  plugins

Sequential Order Numbers

By default, WooCommerce assigns random order numbers to each order. If you want your orders in chronological order, there are a few different approaches you can take.

With the GoDaddy Managed WooCommerce Stores, you get built-in functionality for sequential order numbers. You also have the ability to choose a starting order number and to add a prefix or suffix to the order numbers.

If you do not have our hosting plan, another option to implement sequential orders into your store is to use the Sequential Orders Pro extension. The plugin offers the same functionality as the native features in the Managed WooCommerce Stores.

Order Status Manager

For some businesses, the default WooCommerce order statuses may not suit their workflow. With the WooCommerce Order Status Manager plugin, you can create custom order statuses in workflows enabling your business to process orders efficiently.

You can also use the extension to create a “next status flow. With this tool, you can add an action button to your order pages and bulk actions to your orders dashboard.

Once the plugin is active, you can view your initial order statuses by going to WooCommerce > Settings > Order Statuses. To create additional statuses you have the option to add one from scratch or to import status.

The latter works if you have already created custom order statuses using another plugin or code snippet. To import your prior statuses, click Import custom statuses.

To change the order of the statuses, you can use the drag and drop functionality to arrange them in the sequence that works best for you. This will also change the order in which they appear on the Edit Order page. It also changes how they are displayed in the order bulk actions dropdown.

To add a new status click Add Order Status. From the creation page, begin adding the data for the new status. In addition to a name and URL slug, you will need to set a color, icon, action icon, and description.

If you want to apply a next status, click on the box and select the following step in your workflow.

Click Save Order Status after you enter the details and the plugin will create the new status.

Set up Emails

After you finish creating your custom order statuses, you will want to configure which emails customers will receive for each status change.

To update the messages go to WooCommerce > Settings > Order Statuses > Emails.

Click Add email and enter a name, description, and type. You can then proceed to populate the details for the message.

Order status control

A key to efficient order management is to reduce the number of manual steps needed to complete the fulfillment process. One way to do this is to automatically update order statuses and complete orders.

By default, WooCommerce only auto-completes paid orders for products that are both Downloadable and Virtual.

Depending on your store, you may have other types of orders that you want to automatically complete. With the Order Status Control extension (included in our Managed WooCommerce Stores hosting plan), you control which types of paid orders automatically receive a Completed status.

When an order set to auto-complete is paid, it skips the Processing status and goes right to the Completed Status. This helps streamline order administration for those that don’t require any action on your part between the different steps.

You can set the plugin to auto-complete for all paid orders, virtual orders that are not downloadable, or no orders.

To setup Order Status Control, go to WooCommerce > Settings > General. Scroll down until you find Orders to Auto-Complete. You can then select the types of orders to auto-complete.

When a customer places an order that meets these criteria, it will automatically update to the Completed status. This will then appear in the Order Notes.

The plugin only completes paid orders with a payment method that calls:

woocommerce_payment_complete() / $order->payment_complete()

Most popular payments do such and will work without issue.

Customizing order statuses manually

Let’s start with the first function in this code:

// Register new status
function register_awaiting_shipment_order_status() {
    register_post_status( 'wc-awaiting-shipment', array(
        'label'                     => 'Awaiting shipment',
        'public'                    => true,
        'exclude_from_search'       => false,
        'show_in_admin_all_list'    => true,
        'show_in_admin_status_list' => true,
        'label_count'               => _n_noop( 'Awaiting shipment <span class="count">(%s)</span>', 'Awaiting shipment <span class="count">(%s)</span>' )
    ) );
}
add_action( 'init', 'register_awaiting_shipment_order_status' );

This function is registering our custom status as a post status in WordPress. You can rename the function to suit your needs, but we’re going to build an “Awaiting shipment” order status, so we’ve called it register_awaiting_shipment_order_status() to reflect this.

We then build the post status using the WordPress register_post_status() function. Notice that the first thing in this function is the slug for our order status, prefixed by “wc-” for “WooCommerce”. If you want a different name for your order status, you’ll want to change this to a hyphenated, all lower-cased slug, such as wc-building or wc-packing-order.

Your custom status slug can only be a maximum of 20 characters, including dashes (as per the codex on register_post_status), so you need to be aware of this when creating your own slug.

We then create an array, which is a set of data that defines our custom post status. The label is what will be displayed, so you can change that to the exact name of your order status. You’ll then also want to insert this in the label_count instead of “Awaiting shipment”, but leave the rest of this array unchanged.

Finally, the action at the end runs this function and adds this order status to WordPress as our custom post status.

Now let’s talk about the second part:

// Add to list of WC Order statuses
function add_awaiting_shipment_to_order_statuses( $order_statuses ) {
 
    $new_order_statuses = array();
 
    // add new order status after processing
    foreach ( $order_statuses as $key => $status ) {
 
        $new_order_statuses[ $key ] = $status;
 
        if ( 'wc-processing' === $key ) {
            $new_order_statuses['wc-awaiting-shipment'] = 'Awaiting shipment';
        }
    }
 
    return $new_order_statuses;
}
add_filter( 'wc_order_statuses', 'add_awaiting_shipment_to_order_statuses' );

The add_awaiting_shipment_to_order_statuses() function is going to add this new custom post status into the list of available order statuses within the WooCommerce “Orders” and “Edit Orders” pages so that we can actually use it. We want to pass in the current order statuses so that we can go through them and insert our order status into the list where we’d like it.

We create an array for our new order statuses first, which will be our final product. We’ll then go through all order statuses and insert our own, so that by the time we spit out the new order statuses into the list, our new one is included.

The foreach loop here goes through the list of current order statuses until we find the one we want. In this case, I’m going to insert “Awaiting shipment” after the “Processing” order status. That’s what the if() part is doing here – we say, “If the order status is ‘processing’, add in ‘Awaiting shipment’ here, then continue going through order statuses.”

Notice that I use the slug and label I created in the first function to add this order status. I’ll now have “Awaiting shipment” displayed after “Processing” for my orders:

Order status - Awaiting shipment

You can insert your new status after any of the existing statuses; you can find a list of them here. For example, I could have looked for wc-pending instead and added my status after that.

That’s it! You can now add your own status and insert it anywhere into the order status list.

Tracking guest orders

Using a guest account makes it more difficult for customers to check back in on their orders. This becomes especially important if customers need to view a purchase note, or download files from an order. How can you help WooCommerce guest customers track their orders?

1. Delayed account creation

One of the best ways to help your guest customers track order information is to let them remain guests until they’ve completed their purchase, then encourage them to create an account. Delayed account creation asks for registration after checkout instead of during checkout. In fact, your thank you page is the best place to ask for registration, but 38 percent of sites don’t do this.

Create an account

Registering an account helps both you and your customer.

  • As a store owner, you can market to existing customers more easily, and existing customers have a 27 percent chance of purchasing again from your store. You can also learn more about browsing and purchasing behavior when it’s tied to a user account.
  • As a customer, registering for an account makes it easier to track your order information and to get details on shipping or delivery timelines. Once customers trust a store, they can also save payment methods for speedier checkout (and using saved payment methods makes mobile checkout simpler as well).
Order received

2. Offer order tracking forms

WooCommerce has guest tracking built in, but it’s not used anywhere by default. You can add a shortcode to your site to create an order tracking form: [woocommerce_order_tracking]

The tracking form allows guests to enter their order number and email information to revisit order details.

Track your order - Woo

Bonus tip: be sure to include this page somewhere in your site or footer navigation so it’s easy for guests to find. It’s a good idea to include it in a post-purchase or thank you email, as well.

Once a valid order number and email are submitted, guest customers will see the same information as the order confirmation or thank you page.

Track your order - Woo

This will even work if you’ve migrated orders from a different site or platform—you can use a plugin like Sequential Order Numbers Pro to carry over your previous order numbers, and these can also be used in the tracking form.

Track your order

Adding columns to your WooCommerce orders list

When viewing the “Orders” list in WooCommerce, you’ll see a set of columns that will show you details about orders in your store. While you can remove columns easily using the “Screen options” tab, adding columns requires some custom code to determine what the column data should be.

Let’s take a look at adding some custom WooCommerce Orders list columns today. In this case, we’ll add a “Profit” column to show the order’s profit when used with WooCommerce Cost of Goods.

WooCommerce Orders List Column, Step 1: Add a Header

Adding a new column is straight-forward using the manage_edit-{$post_type}_columns filter from WordPress core. This will let us change the columns shown in the list table for orders so we can inject our own.

While this code could be as simple as:

function wc_new_order_column( $columns ) {
    $columns['my_column'] = 'My column';
    return $columns;
add_filter( 'manage_edit-shop_order_columns', 'wc_new_order_column' );

I’m going to take this a bit further to add my column in the position I want it in. I’ll add my new “Profit” column after the “total” column for the order.

/**
 * Adds 'Profit' column header to 'Orders' page immediately after 'Total' column.
 *
 * @param string[] $columns
 * @return string[] $new_columns
 */
function sv_wc_cogs_add_order_profit_column_header( $columns ) {

    $new_columns = array();

    foreach ( $columns as $column_name => $column_info ) {

        $new_columns[ $column_name ] = $column_info;

        if ( 'order_total' === $column_name ) {
            $new_columns['order_profit'] = __( 'Profit', 'my-textdomain' );
        }
    }

    return $new_columns;
}
add_filter( 'manage_edit-shop_order_columns', 'sv_wc_cogs_add_order_profit_column_header', 20 );

Now I’ve got a new column!

WooCommerce orders

However, we haven’t told WordPress / WooCommerce what should go in the column yet, so we need to populate the column for each row in the list next.

Step 2: Populate the Column

To put data into our custom column, we’ll use another core hook: the manage_{$post_type}_posts_custom_column action, which will be fired each time our custom column is reached for a row.

We’ll need to do a couple things for our column: (1) get the profit from the order, and (2) output it in the column. That sounds easy, but there are a couple caveats:

  1. Cost of Goods stores cost, not profit. We’ll need to get the order total and cost, then determine profit.
  2. Cost of Goods stores cost as order meta. While we could use get_post_meta() to retrieve this, for the sake of completeness and compatibility with WooCommerce 3.0+ (and future versions), I’ll use core WooCommerce functions to get this meta.

As such, let’s first write ourselves a little helper to get order meta in multiple WooCommerce versions.

if ( ! function_exists( 'sv_helper_get_order_meta' ) ) :

    /**
     * Helper function to get meta for an order.
     *
     * @param \WC_Order $order the order object
     * @param string $key the meta key
     * @param bool $single whether to get the meta as a single item. Defaults to `true`
     * @param string $context if 'view' then the value will be filtered
     * @return mixed the order property
     */
    function sv_helper_get_order_meta( $order, $key = '', $single = true, $context = 'edit' ) {

        // WooCommerce > 3.0
        if ( defined( 'WC_VERSION' ) && WC_VERSION && version_compare( WC_VERSION, '3.0', '>=' ) ) {

            $value = $order->get_meta( $key, $single, $context );

        } else {

            // have the $order->get_id() check here just in case the WC_VERSION isn't defined correctly
            $order_id = is_callable( array( $order, 'get_id' ) ) ? $order->get_id() : $order->id;
            $value    = get_post_meta( $order_id, $key, $single );
        }

        return $value;
    }

endif;

Alright! Now we can use that to get the profit for the order and add it to the column. Notice I’ll also do a couple things here:

  1. The method to return order currency changed in WC 3.0, so I have an is_callable() check to determine how I should get it.
  2. I’ve cast the order cost and total as (float) since I’ll be doing some math with them in case they’re stored as strings, as PHP 7.1+ issues warnings when using strings in math functions.
/**
 * Adds 'Profit' column content to 'Orders' page immediately after 'Total' column.
 *
 * @param string[] $column name of column being displayed
 */
function sv_wc_cogs_add_order_profit_column_content( $column ) {
    global $post;

    if ( 'order_profit' === $column ) {

        $order    = wc_get_order( $post->ID );
        $currency = is_callable( array( $order, 'get_currency' ) ) ? $order->get_currency() : $order->order_currency;
        $profit   = '';
        $cost     = sv_helper_get_order_meta( $order, '_wc_cog_order_total_cost' );
        $total    = (float) $order->get_total();

        // don't check for empty() since cost can be '0'
        if ( '' !== $cost || false !== $cost ) {

            // now we can cast cost since we've ensured it was calculated for the order
            $cost   = (float) $cost;
            $profit = $total - $cost;
        }

        echo wc_price( $profit, array( 'currency' => $currency ) );
    }
}
add_action( 'manage_shop_order_posts_custom_column', 'sv_wc_cogs_add_order_profit_column_content' );

Alright, we have some data in our profit column!

WooCommerce Orders List

We could stop here if desired, but I’m going to take one final step. That column is pretty wide, so I’m going to add some CSS to the WooCommerce admin styles to make it more consistent.

Step 3: (Optional) Fix Column Styles

This is totally optional, but I’d like to make the “Profit” column the same width as the “Total” column. This is where the wp_add_inline_style function is handy, as it lets you add some additional CSS into an existing stylesheet. I’ll add this to the woocommerce_admin_styles:

/**
 * Adjusts the styles for the new 'Profit' column.
 */
function sv_wc_cogs_add_order_profit_column_style() {

    $css = '.widefat .column-order_date, .widefat .column-order_profit { width: 9%; }';
    wp_add_inline_style( 'woocommerce_admin_styles', $css );
}
add_action( 'admin_print_styles', 'sv_wc_cogs_add_order_profit_column_style' );

Sorting order items alphabetically

To sort WooCommerce order items alphabetically, you can drop this code into your current theme’s functions.php:

/*
 * Filters the $order->get_items() method results to order all line items by
 * product name
 */
add_filter( 'woocommerce_order_get_items', function( $items, $order ) {

  uasort( $items, 
          function( $a, $b ) { 
            return strnatcmp( $a['name'], $b['name'] ); 
          }
        );

  return $items;

}, 10, 2 );

Which will give you something like the following, regardless of the original order the items were added to the cart:

Alphabetically Sorted Order Items

Alphabetically Sorted Order Items

How does it work?

This code takes advantage of the 'woocommerce_order_get_items' filter provided by the WooCommerce WC_Order::get_items() method to modify the returned set of order items from a given order. Note that we don’t actually alter anything about the order items, besides their, well, order.

Because the order items data structure is complex (it’s an array of associative arrays), to sort the items alphabetically while maintaining the original item keys, we use PHP’s uasort() function to order the items using a custom function we supply (lines 8-10 in the code above). This custom function simply delegates to another PHP core function: strnatcmp() which compares two strings using a “natural string comparison” algorithm (which if you’re interested you read all the really technical information about here). Bottom line is that it helps to sort strings in a very sensible way.

Taking it Further

Note that using this sample code as a starting point, items can be sorted any way you desire. Just return the correct value from that custom sorting function (lines 8-10): -1 if $a should appear before $b, 0 if $a and $b are the same, or 1 if $a should appear after $b.

As an example, to sort in reverse alphabetical order, replace line 9 with: return strnatcmp( $b['name'], $a['name'] );

Using this technique you could sort the order items by any criteria you prefer: by item quantity, by line total, anything!

Conclusion

The popularity of ecommerce means that customers expect to order whatever they like, whenever they like, and without issue.

Fortunately, WooCommerce provides a straightforward and easy-to-use platform for managing your ecommerce orders. It allows you to automate repetitive work and gives you clear details about current inventory levels and orders that need attention. Easily extendable, you can use the OMS to sync your data across your various platforms to provide a more holistic customer experience.

Products Used