Driver FixRecommendedSound, Wi-Fi or graphics acting up? Check drivers firstFind missing or outdated drivers fast.Check DriversHalloween DealsAmazon USHalloween week deals: useful picks before month-endAmazon US: current deals, useful picks and tech finds.Check DealsPC HealthRecommendedCrashes, freezes, slowdowns? Check your PC nowSpot repairable issues before they interrupt work.Check PC×
VGSOURCES
Get listed

order managementPATCH 2026.10.15

How to Change a WooCommerce Order Status with update_status (PHP and REST API)

By VGSources Team 9 min read

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Inside WordPress, retrieve the order with wc_get_order(), verify that an order object was returned, and call update_status() with the destination slug:

$order = wc_get_order( $order_id );

if ( $order ) {
    $updated = $order->update_status( 'completed', 'Updated by automation.' );
}

WC_Order::update_status() saves the new status immediately. Pass a slug such as completed or on-hold without WooCommerce’s internal wc- prefix. For a system running outside WordPress, use an authenticated PUT request to the WooCommerce REST API v3 instead.

As an Amazon Associate I earn from qualifying purchases.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

What update_status() does

WC_Order::update_status() is the order-object method for changing a WooCommerce order’s status in PHP. It sets the destination status, saves the order, and can add an order note explaining the transition. The method is documented as updating the status immediately.

Its signature is:

update_status( string $new_status, string $note = '', bool $manual = false ): bool
  • $new_status is the destination status slug.
  • $note is optional text recorded with the transition; use an empty string when no note is needed.
  • $manual identifies whether the change should be treated as manual. Its default is false.
  • The return value is a Boolean. A successful update returns true; a failed update returns false.

The method calls the order status setter, persists the change, catches exceptions, logs an error, and reports failure through the return value. Your code should therefore check both the result of wc_get_order() and the Boolean returned by update_status().

Use the correct status slug

Use the REST schema’s slug form when calling the PHP method. Do not prepend wc-. The documented order-status values are:

Slug passed to update_status() Meaning Typical use
pending Payment is pending; this is documented as the default status in the REST order schema. Initial order awaiting payment.
processing Payment has been received and fulfillment can proceed. Paid orders being prepared.
on-hold The order is paused pending an action such as payment verification. Manual review or delayed payment.
completed Fulfillment is finished. Orders that require no further store work.
cancelled The order has been cancelled. Customer or administrator cancellation.
refunded The order has been refunded. After a refund has been processed.
failed Payment or another required operation failed. Unsuccessful payment attempts.
trash The order is moved to the trash state in the REST schema. Administrative removal workflows.

A custom status supplied by an extension may also be available in a particular store, but use the exact registered slug for that status. The values above are the statuses listed in the official REST order schema.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Change an order status in WordPress PHP

1. Retrieve the order

wc_get_order() accepts an order ID and returns a WC_Order object when the order exists. It can return a false-like value when the ID is missing, invalid, or the order cannot be loaded, so never call a method on the result without checking it.

$order_id = 727;
$order    = wc_get_order( $order_id );

if ( ! $order ) {
    // Handle an unknown or unavailable order here.
    return;
}

Run this code only after WooCommerce has loaded. In normal plugin code, that means placing the logic in a WooCommerce or WordPress action that runs after plugins are initialized, rather than executing it before WooCommerce is available.

2. Set the destination status

For a completed order, pass completed and optionally record why the automation made the change:

$order = wc_get_order( $order_id );

if ( $order ) {
    $updated = $order->update_status(
        'completed',
        'Updated by automation.'
    );
}

The save occurs as part of update_status(); you do not need a separate $order->save() call for this transition. The note is attached to the order history, giving administrators a reason that can be inspected later.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

3. Handle a failed transition

When a status change is business-critical, test the return value and choose a recovery path appropriate to your application. A false result means the transition did not complete successfully; the implementation also logs exceptions.

$order = wc_get_order( $order_id );

if ( ! $order ) {
    error_log( 'Order could not be loaded: ' . (int) $order_id );
    return;
}

$updated = $order->update_status(
    'processing',
    'Marked processing by fulfillment sync.'
);

if ( ! $updated ) {
    error_log( 'Order status update failed: ' . (int) $order_id );
    // Queue a retry, alert an administrator, or record the failure.
}

Do not treat a non-existent order as a successful no-op. Keep the order ID and failure reason in your application’s logs so a retry can distinguish a temporary exception from an invalid identifier.

Choosing the note and manual flag

Order notes

The second argument is an order note, not a replacement for the status. Use concise text that identifies the operation or system responsible:

$order->update_status(
    'on-hold',
    'Payment verification required by risk workflow.'
);

Pass an empty string when a note would add no useful audit information:

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
$order->update_status( 'processing', '' );

The manual argument

The third argument is a Boolean that indicates whether the status change is manual. It defaults to false. Supply true only when your workflow should classify the transition as manual:

$order->update_status(
    'completed',
    'Approved by a staff review.',
    true
);

For unattended synchronization, leave the argument at its default or pass false explicitly. The status slug and note remain the same regardless of this flag.

Examples for common transitions

Mark an order as processing

$order = wc_get_order( $order_id );

if ( $order && ! $order->update_status( 'processing', 'Payment confirmed.' ) ) {
    // Record or retry the failed update.
}

Put an order on hold

$order = wc_get_order( $order_id );

if ( $order ) {
    $order->update_status( 'on-hold', 'Awaiting address verification.' );
}

The hyphen in on-hold is part of the slug. Using on_hold or wc-on-hold does not represent the documented value.

Cancel or refund an order

$order = wc_get_order( $order_id );

if ( $order ) {
    $cancelled = $order->update_status( 'cancelled', 'Cancelled by fulfillment system.' );
}

Changing a status is not the same operation as issuing a payment refund. If money must be returned, perform the store’s refund workflow separately, then set the status when that process is complete.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Prevent accidental or repeated transitions

Before changing an order, decide whether your integration should update it every time it runs or only when it is in an expected source state. A guarded transition avoids overwriting a later status with an old message from a delayed job.

$order = wc_get_order( $order_id );

if ( ! $order ) {
    return;
}

if ( 'processing' !== $order->get_status() ) {
    return;
}

if ( ! $order->update_status( 'completed', 'Fulfillment confirmed.' ) ) {
    error_log( 'Could not complete order ' . (int) $order_id );
}

Use the guard only when the business rule requires a particular starting status. If the transition is intentionally repeatable, omit it and rely on the method’s result. Either way, include a stable note or external event identifier in your own logs so retries can be traced.

Change a status through the WooCommerce REST API

The REST option is intended for an external service, mobile application, or separate fulfillment system that cannot execute PHP inside the store. WooCommerce identifies REST API v3 as the current recommended version for new integrations.

Request format

Send an authenticated PUT request to the order resource. This example changes order 727 to completed:

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
PUT /wp-json/wc/v3/orders/727
Content-Type: application/json

{"status":"completed"}

The same endpoint accepts other documented status slugs, for example:

PUT /wp-json/wc/v3/orders/727
Content-Type: application/json

{"status":"on-hold"}

The order ID belongs in the URL, while the new status is sent in the JSON body as status. A successful response should be treated as confirmation only after your client checks the HTTP status and parses the returned order data.

Authentication and transport

REST requests require credentials with permission to edit orders. Use the authentication mechanism configured for the store, keep credentials out of source control, and send the request over HTTPS. Restrict the integration’s permissions to what it needs, protect logs from leaking secrets, and handle unauthorized or forbidden responses separately from a validation error.

Remote error handling

  • A connection timeout or server error can leave the remote result unknown. Retry with backoff only when your workflow can safely repeat the request.
  • A client or validation error usually requires correcting the order ID, status slug, or permissions before retrying.
  • After a successful response, persist the returned order ID, status, and your external event identifier to prevent duplicate processing.
Independent reader supportYour contribution helps us test, update, and keep practical guides available for everyone.Support on Ko-Fi

PHP versus REST: which approach fits?

Decision point PHP with update_status() REST API v3
Where it runs Inside the WordPress/WooCommerce installation. In an external service communicating with the store.
How it identifies the order Loads a WC_Order with wc_get_order(). Uses the order ID in /wp-json/wc/v3/orders/<id>.
Authentication Uses the current WordPress execution context and its permissions. Requires REST credentials and permission to edit orders.
Error signal Checks the object and the method’s Boolean return; exceptions are logged by the implementation. Checks HTTP status, response body, and transport errors.
Local follow-up Runs in the same WooCommerce environment, where local actions and filters are available. Crosses an integration boundary; local hooks still run in the store, but the caller must handle the remote response.
Best fit Store plugins, theme-side integrations, scheduled WordPress jobs, and code that needs direct access to WooCommerce objects. Fulfillment platforms, back-office systems, and services hosted outside WordPress.

React to status changes with actions and webhooks

Changing the status is one operation; performing downstream work is another. Use WooCommerce actions and filters when code must react to a transition. The documented status-related hooks include woocommerce_order_status_changed and woocommerce_order_edit_status.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
add_action( 'woocommerce_order_status_changed', function ( $order_id, $old_status, $new_status, $order ) {
    if ( 'completed' !== $new_status ) {
        return;
    }

    // Trigger fulfillment, notification, or synchronization here.
}, 10, 4 );

Keep the callback focused and make it safe to run more than once if retries are possible. If the receiving system is external, store an event key or delivery record before retrying so a repeated hook does not create duplicate fulfillment.

For integrations that should receive events outside WordPress, configure a WooCommerce webhook for the relevant order event. Webhooks provide the delivery boundary; your receiver remains responsible for authentication, idempotency, response codes, and retry handling.

Testing a status update safely

  1. Use a staging store or a test order rather than a live customer order.
  2. Confirm that the ID supplied to wc_get_order() belongs to the intended order.
  3. Test a valid transition such as processing to completed.
  4. Test an invalid or missing ID and verify that your code stops before calling a method on a false result.
  5. Force or simulate an exception and confirm that a false return is logged and surfaced to your retry or alerting system.
  6. Check the order’s status and order notes in the administration screen after a successful call.
  7. If hooks or webhooks are enabled, verify that one transition produces the intended downstream event and that a retry does not duplicate it.
  8. For REST, test unauthorized credentials, an unknown order ID, malformed JSON, and a valid authenticated request separately.

Troubleshooting common failures

The status does not change

Verify the order object was loaded, the slug is spelled exactly as documented, and the returned Boolean is checked. In particular, use on-hold, not an underscore or a prefixed value. Review the WooCommerce and WordPress logs for an exception reported during the save.

The code reports an unknown function

wc_get_order() and WC_Order are WooCommerce APIs. Ensure the WooCommerce plugin is active and that the code executes after WooCommerce initialization. A plugin file loaded too early can run before these APIs are available.

What’s actually slowing this PC down?

Pick the symptom - the matching free tool is one click away.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

The REST request is rejected

Check the API version and path, use PUT rather than a read-only method, verify that the credential can edit orders, and confirm that the request body is valid JSON with a supported status value. Treat a permission response differently from a malformed-status response; they require different fixes.

An integration keeps undoing a newer status

Add a source-status guard or compare the event’s timestamp and identifier with the last event applied. Delayed jobs and webhook retries should not overwrite a later business decision simply because they eventually arrived.

Practical checklist

  • Load the order with wc_get_order( $order_id ).
  • Stop if no order object is returned.
  • Pass a documented status slug without wc-.
  • Add an informative note when automation changes a customer-visible state.
  • Use the third argument only when the transition should be marked manual.
  • Check the Boolean return and log or retry failures.
  • Use REST API v3 and an authenticated PUT request for external callers.
  • Attach follow-up work to status hooks or webhooks, with duplicate delivery protection.

Product prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on Amazon at the time of purchase will apply.

order managementPHPREST APIWooCommerceWordPress Development

Leave a reply

Your email address will not be published. Required fields are marked *

Free tools Windows power users keep installed

One-click scans. No signup required.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Recommended PC Tool
Recommended PC Tool
Outdated Drivers Are Slowing You DownFree scan - exact matches
PC Slower Than It Used to Be?Free scan - under a minute

Two free Windows tools

One Free Minute Could Fix That PC

Before you go - each of these free tools takes about a minute and tackles what quietly slows a Windows PC down.

Special offer. View Outbyte info, uninstall instructions, EULA, and Privacy Policy.