PHPwoocommerceadvanced

WooCommerce Custom Order Status

Create and manage custom order statuses in WooCommerce with email notifications

Faisal Yaqoob
#woocommerce#order-status#workflow#order-management#automation
Share this snippet:

Code

php
1// Register custom order statuses
2add_action('init', 'register_custom_order_statuses');
3function register_custom_order_statuses() {
4 // Awaiting Shipment status
5 register_post_status('wc-awaiting-shipment', array(
6 'label' => _x('Awaiting Shipment', 'Order status', 'woocommerce'),
7 'public' => true,
8 'exclude_from_search' => false,
9 'show_in_admin_all_list' => true,
10 'show_in_admin_status_list' => true,
11 'label_count' => _n_noop('Awaiting Shipment <span class="count">(%s)</span>',
12 'Awaiting Shipment <span class="count">(%s)</span>',
13 'woocommerce')
14 ));
15
16 // Quality Check status
17 register_post_status('wc-quality-check', array(
18 'label' => _x('Quality Check', 'Order status', 'woocommerce'),
19 'public' => true,
20 'exclude_from_search' => false,
21 'show_in_admin_all_list' => true,
22 'show_in_admin_status_list' => true,
23 'label_count' => _n_noop('Quality Check <span class="count">(%s)</span>',
24 'Quality Check <span class="count">(%s)</span>',
25 'woocommerce')
26 ));
27
28 // Ready for Pickup status
29 register_post_status('wc-ready-pickup', array(
30 'label' => _x('Ready for Pickup', 'Order status', 'woocommerce'),
31 'public' => true,
32 'exclude_from_search' => false,
33 'show_in_admin_all_list' => true,
34 'show_in_admin_status_list' => true,
35 'label_count' => _n_noop('Ready for Pickup <span class="count">(%s)</span>',
36 'Ready for Pickup <span class="count">(%s)</span>',
37 'woocommerce')
38 ));
39
40 // Partially Shipped status
41 register_post_status('wc-partially-shipped', array(
42 'label' => _x('Partially Shipped', 'Order status', 'woocommerce'),
43 'public' => true,
44 'exclude_from_search' => false,
45 'show_in_admin_all_list' => true,
46 'show_in_admin_status_list' => true,
47 'label_count' => _n_noop('Partially Shipped <span class="count">(%s)</span>',
48 'Partially Shipped <span class="count">(%s)</span>',
49 'woocommerce')
50 ));
51}

WooCommerce Custom Order Status

Create custom order statuses for WooCommerce to better manage your order workflow (e.g., Awaiting Shipment, Quality Check, Custom Processing).

// Register custom order statuses
add_action('init', 'register_custom_order_statuses');
function register_custom_order_statuses() {
    // Awaiting Shipment status
    register_post_status('wc-awaiting-shipment', array(
        'label'                     => _x('Awaiting Shipment', 'Order status', 'woocommerce'),
        '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>',
                                               'woocommerce')
    ));

    // Quality Check status
    register_post_status('wc-quality-check', array(
        'label'                     => _x('Quality Check', 'Order status', 'woocommerce'),
        'public'                    => true,
        'exclude_from_search'       => false,
        'show_in_admin_all_list'    => true,
        'show_in_admin_status_list' => true,
        'label_count'               => _n_noop('Quality Check <span class="count">(%s)</span>',
                                               'Quality Check <span class="count">(%s)</span>',
                                               'woocommerce')
    ));

    // Ready for Pickup status
    register_post_status('wc-ready-pickup', array(
        'label'                     => _x('Ready for Pickup', 'Order status', 'woocommerce'),
        'public'                    => true,
        'exclude_from_search'       => false,
        'show_in_admin_all_list'    => true,
        'show_in_admin_status_list' => true,
        'label_count'               => _n_noop('Ready for Pickup <span class="count">(%s)</span>',
                                               'Ready for Pickup <span class="count">(%s)</span>',
                                               'woocommerce')
    ));

    // Partially Shipped status
    register_post_status('wc-partially-shipped', array(
        'label'                     => _x('Partially Shipped', 'Order status', 'woocommerce'),
        'public'                    => true,
        'exclude_from_search'       => false,
        'show_in_admin_all_list'    => true,
        'show_in_admin_status_list' => true,
        'label_count'               => _n_noop('Partially Shipped <span class="count">(%s)</span>',
                                               'Partially Shipped <span class="count">(%s)</span>',
                                               'woocommerce')
    ));
}

Add Custom Statuses to WooCommerce

// Add custom statuses to order status list
add_filter('wc_order_statuses', 'add_custom_order_statuses');
function add_custom_order_statuses($order_statuses) {
    $new_order_statuses = array();

    // Add custom statuses in specific positions
    foreach ($order_statuses as $key => $status) {
        $new_order_statuses[$key] = $status;

        // Add custom statuses after processing
        if ('wc-processing' === $key) {
            $new_order_statuses['wc-quality-check'] = _x('Quality Check', 'Order status', 'woocommerce');
            $new_order_statuses['wc-awaiting-shipment'] = _x('Awaiting Shipment', 'Order status', 'woocommerce');
            $new_order_statuses['wc-partially-shipped'] = _x('Partially Shipped', 'Order status', 'woocommerce');
            $new_order_statuses['wc-ready-pickup'] = _x('Ready for Pickup', 'Order status', 'woocommerce');
        }
    }

    return $new_order_statuses;
}

Add Custom Status to Bulk Actions

// Add custom order status to bulk actions dropdown
add_filter('bulk_actions-edit-shop_order', 'add_custom_status_bulk_actions');
function add_custom_status_bulk_actions($bulk_actions) {
    $bulk_actions['mark_awaiting_shipment'] = __('Mark as Awaiting Shipment', 'woocommerce');
    $bulk_actions['mark_quality_check'] = __('Mark as Quality Check', 'woocommerce');
    $bulk_actions['mark_ready_pickup'] = __('Mark as Ready for Pickup', 'woocommerce');
    $bulk_actions['mark_partially_shipped'] = __('Mark as Partially Shipped', 'woocommerce');

    return $bulk_actions;
}

// Handle bulk action
add_filter('handle_bulk_actions-edit-shop_order', 'handle_custom_status_bulk_actions', 10, 3);
function handle_custom_status_bulk_actions($redirect_to, $action, $post_ids) {
    $status_actions = array(
        'mark_awaiting_shipment'  => 'wc-awaiting-shipment',
        'mark_quality_check'      => 'wc-quality-check',
        'mark_ready_pickup'       => 'wc-ready-pickup',
        'mark_partially_shipped'  => 'wc-partially-shipped',
    );

    if (array_key_exists($action, $status_actions)) {
        $changed = 0;

        foreach ($post_ids as $post_id) {
            $order = wc_get_order($post_id);

            if ($order) {
                $order->update_status($status_actions[$action]);
                $changed++;
            }
        }

        $redirect_to = add_query_arg('changed', $changed, $redirect_to);
    }

    return $redirect_to;
}

Add Custom Status to Order Actions

// Add custom status to order actions dropdown
add_filter('woocommerce_order_actions', 'add_custom_status_to_order_actions');
function add_custom_status_to_order_actions($actions) {
    global $theorder;

    // Add actions based on current order status
    if ($theorder->has_status('processing')) {
        $actions['move_to_quality_check'] = __('Move to Quality Check', 'woocommerce');
    }

    if ($theorder->has_status('quality-check')) {
        $actions['move_to_awaiting_shipment'] = __('Move to Awaiting Shipment', 'woocommerce');
    }

    if ($theorder->has_status('awaiting-shipment')) {
        $actions['move_to_partially_shipped'] = __('Mark as Partially Shipped', 'woocommerce');
    }

    return $actions;
}

// Handle custom order actions
add_action('woocommerce_order_action_move_to_quality_check', 'process_order_to_quality_check');
function process_order_to_quality_check($order) {
    $order->update_status('quality-check', __('Order moved to quality check.', 'woocommerce'));
}

add_action('woocommerce_order_action_move_to_awaiting_shipment', 'process_order_to_awaiting_shipment');
function process_order_to_awaiting_shipment($order) {
    $order->update_status('awaiting-shipment', __('Order awaiting shipment.', 'woocommerce'));
}

add_action('woocommerce_order_action_move_to_partially_shipped', 'process_order_to_partially_shipped');
function process_order_to_partially_shipped($order) {
    $order->update_status('partially-shipped', __('Order partially shipped.', 'woocommerce'));
}

Email Notifications for Custom Status

// Add custom status to emails
add_filter('woocommerce_email_actions', 'add_custom_status_email_actions');
function add_custom_status_email_actions($actions) {
    $actions[] = 'woocommerce_order_status_pending_to_awaiting-shipment';
    $actions[] = 'woocommerce_order_status_processing_to_awaiting-shipment';
    $actions[] = 'woocommerce_order_status_quality-check_to_awaiting-shipment';
    $actions[] = 'woocommerce_order_status_awaiting-shipment_to_ready-pickup';

    return $actions;
}

// Send email when order moves to "Awaiting Shipment"
add_action('woocommerce_order_status_awaiting-shipment', 'send_awaiting_shipment_email', 10, 2);
function send_awaiting_shipment_email($order_id, $order) {
    $mailer = WC()->mailer();

    $recipient = $order->get_billing_email();
    $subject = sprintf(__('Your order #%s is awaiting shipment', 'woocommerce'), $order->get_order_number());

    $message = sprintf(
        __('Hi %s,<br><br>Your order #%s has been prepared and is awaiting shipment. We will notify you once it ships.<br><br>Thank you!', 'woocommerce'),
        $order->get_billing_first_name(),
        $order->get_order_number()
    );

    $email = $mailer->emails['WC_Email_Customer_Processing_Order'];

    $email->send($recipient, $subject, $message, $email->get_headers(), $email->get_attachments());
}

// Send email when order is ready for pickup
add_action('woocommerce_order_status_ready-pickup', 'send_ready_pickup_email', 10, 2);
function send_ready_pickup_email($order_id, $order) {
    $to = $order->get_billing_email();
    $subject = sprintf(__('Your order #%s is ready for pickup!', 'woocommerce'), $order->get_order_number());

    $message = '
    <html>
    <body>
        <h2>Hi ' . $order->get_billing_first_name() . ',</h2>
        <p>Great news! Your order #' . $order->get_order_number() . ' is ready for pickup.</p>
        <p><strong>Pickup Location:</strong> 123 Main Street, City, State</p>
        <p><strong>Hours:</strong> Monday - Friday, 9am - 5pm</p>
        <p>Please bring your order confirmation email or ID.</p>
        <p>Thank you!</p>
    </body>
    </html>
    ';

    $headers = array('Content-Type: text/html; charset=UTF-8');

    wp_mail($to, $subject, $message, $headers);
}

Display Custom Status in My Account

// Show custom status messages in My Account
add_filter('woocommerce_my_account_my_orders_actions', 'add_custom_status_my_account_actions', 10, 2);
function add_custom_status_my_account_actions($actions, $order) {
    if ($order->has_status('awaiting-shipment')) {
        $actions['awaiting_info'] = array(
            'url'  => '#',
            'name' => __('Awaiting Shipment', 'woocommerce'),
        );
    }

    if ($order->has_status('ready-pickup')) {
        $actions['pickup_info'] = array(
            'url'  => get_permalink(get_option('woocommerce_myaccount_page_id')) . 'pickup-info/',
            'name' => __('Pickup Information', 'woocommerce'),
        );
    }

    return $actions;
}

Status Color Coding in Admin

// Add custom CSS for order status colors in admin
add_action('admin_head', 'custom_order_status_colors');
function custom_order_status_colors() {
    ?>
    <style>
        .order-status.status-awaiting-shipment {
            background: #ffba00;
            color: #000;
        }

        .order-status.status-quality-check {
            background: #a46497;
            color: #fff;
        }

        .order-status.status-ready-pickup {
            background: #33ccff;
            color: #000;
        }

        .order-status.status-partially-shipped {
            background: #ff9800;
            color: #fff;
        }

        mark.awaiting-shipment {
            background: #ffba00;
            color: #000;
            font-weight: 600;
        }

        mark.quality-check {
            background: #a46497;
            color: #fff;
            font-weight: 600;
        }

        mark.ready-pickup {
            background: #33ccff;
            color: #000;
            font-weight: 600;
        }

        mark.partially-shipped {
            background: #ff9800;
            color: #fff;
            font-weight: 600;
        }
    </style>
    <?php
}

Reports and Analytics for Custom Status

// Add custom status to reports
add_filter('woocommerce_reports_order_statuses', 'add_custom_status_to_reports');
function add_custom_status_to_reports($statuses) {
    $statuses[] = 'awaiting-shipment';
    $statuses[] = 'quality-check';
    $statuses[] = 'ready-pickup';
    $statuses[] = 'partially-shipped';

    return $statuses;
}

Mark Custom Status as Paid

// Mark custom statuses as paid (for payment complete)
add_filter('woocommerce_order_is_paid_statuses', 'add_custom_status_to_paid_statuses');
function add_custom_status_to_paid_statuses($statuses) {
    $statuses[] = 'awaiting-shipment';
    $statuses[] = 'quality-check';
    $statuses[] = 'ready-pickup';
    $statuses[] = 'partially-shipped';

    return $statuses;
}

Automatic Status Transition

// Automatically move orders to custom status after certain conditions
add_action('woocommerce_order_status_processing', 'auto_transition_to_quality_check', 10, 2);
function auto_transition_to_quality_check($order_id, $order) {
    // Check if order total is over $500
    if ($order->get_total() > 500) {
        $order->update_status('quality-check', __('High-value order sent to quality check.', 'woocommerce'));
    }
}

// Automatically move to ready for pickup if local pickup shipping
add_action('woocommerce_order_status_processing', 'auto_transition_to_ready_pickup', 10, 2);
function auto_transition_to_ready_pickup($order_id, $order) {
    $shipping_method = $order->get_shipping_method();

    if (stripos($shipping_method, 'local pickup') !== false) {
        $order->update_status('ready-pickup', __('Order ready for local pickup.', 'woocommerce'));
    }
}

Features

  • Multiple Custom Statuses: Awaiting Shipment, Quality Check, Ready for Pickup, Partially Shipped
  • Full Integration: Works seamlessly with WooCommerce order system
  • Bulk Actions: Change status for multiple orders at once
  • Email Notifications: Automatic emails when status changes
  • Color Coding: Visual distinction in admin panel
  • My Account Integration: Custom status displayed to customers
  • Order Actions: Quick status changes from order edit page
  • Reports Integration: Custom statuses included in WooCommerce reports
  • Payment Status: Mark custom statuses as paid
  • Automatic Transitions: Rule-based status changes
  • Extensible: Easy to add more custom statuses

Dependencies

  • WooCommerce

Related Snippets