To change an order status in PHP running inside WordPress, load the order with wc_get_order() and call update_status() on the returned WC_Order object:
Antihost offers managed WordPress hosting with free migration, one-click staging and a 14-day free trial.
$order = wc_get_order( $order_id );
if ( $order ) {
$order->update_status( 'completed', 'Updated by automation.' );
}
The method saves the transition immediately. Use a status slug such as completed or on-hold without WooCommerce’s internal wc- prefix, record a useful note when appropriate, and check the Boolean return value when a failed transition matters.
As an Amazon Associate I earn from qualifying purchases.
What’s actually slowing this PC down?
Pick the symptom - the matching free tool is one click away.
What update_status() does
WC_Order::update_status() changes an existing WooCommerce order to a new status and persists that change immediately. It operates on a WC_Order object, not on an order ID by itself. The normal sequence is therefore: obtain the order, verify that an object was returned, call the method, and handle its result.
The documented method signature is:
update_status( string $new_status, string $note = '', bool $manual = false ): bool
$new_statusis the destination status slug.$noteis optional text stored with the status transition. An empty string means that you do not want to add a note.$manualis a Boolean that identifies whether the change should be treated as manual. It defaults tofalse.- The return value is
truewhen the update succeeds andfalsewhen it does not.
The implementation sets the new status, saves the order, catches exceptions, logs an error, and returns false if the operation cannot be completed. That makes the return value the application-level signal to inspect after the call.
#1 Best Overall
Change an order status in PHP
Minimal status update
Place this code in a context where WooCommerce is loaded, such as a plugin, a theme integration, or a callback that runs after WordPress has initialized its plugins:
$order_id = 727;
$order = wc_get_order( $order_id );
if ( $order ) {
$order->update_status( 'processing' );
}
The example requests the processing status and supplies no note. WooCommerce performs the save during the method call; there is no separate status-save step in this sequence.
Outdated Drivers Are Slowing You Down
One free scan finds every outdated or missing driver and matches the right update for your exact hardware.Free scan · exact hardware matchPC Slower Than It Used to Be?
A free scan shows the junk files, broken settings and background clutter dragging Windows down - then fixes them in one click.Free scan · Windows 10 & 11Add an audit note
An explanatory note is useful when an automated job, synchronization process, or support tool changes an order. Pass it as the second argument:
$order = wc_get_order( $order_id );
if ( $order ) {
$updated = $order->update_status(
'completed',
'Updated by the fulfillment automation.'
);
if ( ! $updated ) {
error_log( 'The order status update failed.' );
}
}
Keep the note factual and specific. It should explain why the transition occurred without putting credentials, payment data, or other sensitive values into the order history.
Pass the manual flag explicitly when your workflow needs it
The third argument is optional:
$updated = $order->update_status(
'on-hold',
'Placed on hold pending verification.',
true
);
Use true only when your application is intentionally identifying the transition as manual. Otherwise, omit the argument and use the documented default of false.
Retrieve and validate the order first
wc_get_order() can fail to return an order object. The ID may be wrong, the order may not exist in the current store, or the value supplied by an external system may not identify a valid WooCommerce order. Calling a method on a failed lookup is an avoidable fatal error, so guard the call:
$order = wc_get_order( $order_id );
if ( ! $order ) {
error_log( 'No WooCommerce order was found for the supplied ID.' );
return;
}
$updated = $order->update_status( 'completed', 'Marked complete by automation.' );
if ( ! $updated ) {
error_log( 'WooCommerce could not change the order status.' );
}
In a function that cannot use return directly, replace that branch with the error-handling convention used by the surrounding application. The important points are to stop before calling update_status() when the lookup failed and to treat a false result as a real failure rather than assuming the transition happened.
Use the correct status slug
The official WooCommerce REST order schema lists these status values:
| Status slug | Use in code | Schema note |
|---|---|---|
pending |
$order->update_status( 'pending' ); |
Documented as the default status in the schema |
processing |
$order->update_status( 'processing' ); |
Use the slug exactly as shown |
on-hold |
$order->update_status( 'on-hold' ); |
Includes a hyphen |
completed |
$order->update_status( 'completed' ); |
Use the slug without a prefix |
cancelled |
$order->update_status( 'cancelled' ); |
Spelling follows the documented slug |
refunded |
$order->update_status( 'refunded' ); |
Use the exact lowercase value |
failed |
$order->update_status( 'failed' ); |
Use the exact lowercase value |
trash |
$order->update_status( 'trash' ); |
Listed by the REST order schema |
Pass completed, not wc-completed; pass on-hold, not wc-on-hold. The internal wc- prefix is not part of the value expected by update_status().
Choose the destination deliberately
A status change is a business decision, not merely a text edit. Before setting it, identify the event that authorizes the transition: payment confirmation, fulfillment confirmation, a fraud review, a customer-service correction, or an external system’s confirmed result. A job that runs repeatedly should also determine whether it should attempt the call only when the current status differs from the desired status.
Quick wins for a faster PC:
Repair Windows errors before they cause bigger problemsFix Now →Scan for outdated or missing drivers - takes under a minuteDriver Scan →$order = wc_get_order( $order_id );
if ( ! $order ) {
return;
}
if ( 'completed' !== $order->get_status() ) {
$order->update_status(
'completed',
'Completed after confirmed fulfillment.'
);
}
This conditional avoids issuing the same transition when the order is already complete. Whether to skip an already-correct status or still write a note is a workflow choice; make it explicit in the calling code.
Handle failures instead of assuming success
There are two separate failure points. First, the order lookup may not produce a WC_Order object. Second, update_status() may return false. The method’s implementation catches exceptions and logs an error, so callers should still inspect the Boolean result and decide how to recover.
Rank #3
For a critical workflow
If the status controls fulfillment, entitlement, invoicing, or another irreversible action, record the failure and keep the source event available for retry. A practical pattern is:
$order = wc_get_order( $order_id );
if ( ! $order ) {
error_log( 'Order lookup failed; queue the source event for review.' );
return;
}
$updated = $order->update_status(
'completed',
'Completed by the fulfillment integration.'
);
if ( ! $updated ) {
error_log( 'Status transition failed; do not acknowledge the source event.' );
return;
}
// Acknowledge the source event only after the update succeeds.
The final action in this example represents your integration’s acknowledgement mechanism; it is intentionally performed only after a successful return value.
Recommended Free Tools
For a non-critical administrative script
A one-off maintenance task can log the order ID and continue to the next item when one update fails. Do not hide failures by discarding the return value, especially in a batch where a successful exit code could otherwise suggest that every order changed.
Changing status through the REST API
Use the REST API when the code that initiates the change runs outside the WordPress installation, such as a separate fulfillment service or an integration server. WooCommerce identifies REST API v3 under /wp-json/wc/v3/ as the current recommended version for new integrations.
To change order 727 remotely, send an authenticated PUT request to the order resource:
PUT /wp-json/wc/v3/orders/727
Content-Type: application/json
{"status":"completed"}
The request body contains the status field and the same slug rules apply: use completed, processing, or on-hold, not a value with the wc- prefix. The request must be authenticated with credentials that have permission to edit orders, and it must be transported securely. How credentials are stored and supplied depends on the integration; never place them in client-side code or log them with request details.
The Tool Desk
Outbyte PC Repair FREERepair Windows errors before they cause bigger problemsFix Now →Outbyte Driver Updater FREEFix the driver behind crashes, sound loss and screen glitchesFind Drivers →Rank #4
Validate the remote result
A remote caller should treat the HTTP response as part of the operation’s result. Check that the request was accepted, inspect an error response when it was not, and retain enough context to retry safely. At minimum, log the order ID, requested status, time, and a correlation identifier while omitting secrets. If the integration can receive the same event twice, make its retry behavior idempotent so that a repeated request does not trigger duplicate downstream work.
PHP or REST: which path fits?
| Decision point | PHP with update_status() |
REST API v3 |
|---|---|---|
| Where it runs | Inside the WordPress and WooCommerce process | In an external service that calls the store |
| How it identifies the order | Loads a WC_Order with wc_get_order() |
Uses the order resource path, such as /wp-json/wc/v3/orders/727 |
| Authentication model | Uses the current WordPress execution context | Requires authenticated API credentials and edit permission |
| Error signal | Order lookup plus the method’s Boolean return value | HTTP response plus the API error body |
| Local follow-up | Can participate directly in local hooks and application code | Requires a remote integration strategy for follow-up work |
| Best fit | Plugins, scheduled WordPress jobs, and in-store automation | External fulfillment, ERP, or synchronization services |
Choose PHP when the decision already belongs inside the store and you need the local WooCommerce object. Choose REST when another system owns the event and should cross an explicit API boundary.
React to status changes with hooks and webhooks
Changing a status is often only the first step. WooCommerce documents status-related actions including woocommerce_order_status_changed and woocommerce_order_edit_status. These hooks let local code respond to a transition instead of putting every notification or synchronization task directly beside the update call.
Use a hook when the receiving action belongs to the same WordPress installation, such as sending an internal notification or updating a local record. Use a webhook when another service needs an event from the store. WooCommerce’s webhook system documents event topics for delivering those changes to external consumers.
Free tools Windows power users keep installed
One-click scans. No signup required.
Keep transition effects separate
A useful separation is:
- The command decides that the order should move to a destination status.
update_status()performs and saves the transition.- A hook or webhook consumer performs notification, fulfillment synchronization, or other follow-up work.
This arrangement makes it easier to retry a failed consumer without repeatedly inventing new status changes. The receiving code should still record failures and avoid assuming that delivery or processing occurred merely because the status update succeeded.
Independent reader supportYour contribution helps us test, update, and keep practical guides available for everyone.Common problems and fixes
The order object is empty
Check the value passed to wc_get_order() and confirm that the code is running after WooCommerce has loaded. Do not call update_status() until the lookup has returned an object. Log the identifier in a safe form so an administrator can correct the source data.
Best Value
The status never changes
Confirm that the value is a documented slug, is lowercase, and uses the hyphen in on-hold. Remove the wc- prefix if it was copied from an internal label. Then inspect the Boolean return value and application logs rather than relying only on a screen refresh.
The method returns false
Treat this as an unsuccessful transition. Preserve the triggering event for retry, inspect the logged error, and verify that the order can be edited in the current execution context. Avoid acknowledging an external message or launching dependent fulfillment until the update succeeds.
Do these 3 things before closing this tab:
1Fix the driver behind crashes, sound loss and screen glitches2Clear out junk files and repair common Windows errors3Scan for outdated or missing drivers - takes under a minuteThe REST request is rejected
Verify the HTTP method, the /wp-json/wc/v3/orders/{id} resource shape, JSON content type, credentials, and permission to edit orders. Make sure the request reaches the intended store and that transport encryption is enabled. Read the response body for the specific API error instead of retrying blindly.
Follow-up automation runs more than once
Status changes can be retried by jobs or remote systems. Design notification and synchronization handlers to recognize duplicate events, and store a durable event or correlation identifier where your integration requires exactly-once business effects.
Implementation checklist
- Confirm that the code runs in a WooCommerce-loaded WordPress context, or choose REST API v3 for an external caller.
- Load the order with
wc_get_order( $order_id ). - Stop safely when no order object is returned.
- Pass a documented slug without the
wc-prefix. - Use the second argument to explain an automated transition when an audit note is useful.
- Pass the third Boolean argument only when the manual designation is intentional.
- Inspect the
true/falseresult fromupdate_status(). - For REST, send an authenticated
PUTrequest to/wp-json/wc/v3/orders/<order-id>with a JSONstatusfield. - Separate the status command from local hooks, webhook consumers, and retry logic.
- Test missing IDs, invalid slugs, failed saves, permission errors, and duplicate events before enabling automation.
Complete reference example
The following function keeps lookup, status selection, note creation, and failure handling in one small unit. It returns a Boolean so its caller can decide whether to retry or report the result:
function mark_order_completed( $order_id ) {
$order = wc_get_order( $order_id );
if ( ! $order ) {
error_log( 'Unable to load the WooCommerce order.' );
return false;
}
if ( 'completed' === $order->get_status() ) {
return true;
}
$updated = $order->update_status(
'completed',
'Marked complete by the fulfillment automation.'
);
if ( ! $updated ) {
error_log( 'WooCommerce rejected the order status update.' );
return false;
}
return true;
}
The function treats an already-completed order as successful without writing a second transition note. If your business process requires a fresh audit note on every invocation, remove that early return and make the duplicate-event policy explicit instead.
Quick Recap
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.




