Table of Contents
In this post, we will uncover how WooCommerce order hooks are used to perform actions or events during the various stages of an order lifecycle. These hooks allow developers to modify or add custom functionality at specific points in the process without directly editing the core files.
List of Order Hooks in Classic Checkout
1. Order Creation and Update Hooks
woocommerce_checkout_create_order | Fired before the order is saved. |
woocommerce_new_order | Fired after the order is created. |
woocommerce_checkout_order_created | Fired after the order and its custom item meta are saved. |
woocommerce_checkout_order_processed | Fired after the order is created but before payment is processed. |
let’s explore how you can implement them to customize your store’s functionality.
- woocommerce_checkout_create_order:
With this hook ‘woocommerce_checkout_create_order‘, you can access and modify the order and the checkout data before it is saved into the database. For example, you can modify the billing or shipping details, add custom order meta, apply discounts, or trigger custom actions.
add_action( 'woocommerce_checkout_create_order', 'custom_checkout_create_order', 10, 2 ); function custom_checkout_create_order( $order, $data ) { // Add your custom code here to manipulate the order before it is saved // For example, you can modify billing or shipping details: // Example: Set a custom billing city // $order->set_billing_city( 'Custom City' ); // Example: Add a custom order note // $order->add_order_note( 'Custom order note' ); // Example: Add a custom fee // $order->add_fee( 'Custom Fee', 10, true ); // You can add any other logic to customize the order as needed }
- woocommerce_new_order:
This hook will perform an action just after the new order is created in WooCommerce, which happens after the checkout process is completed successfully. When the hook is triggered the order data will be already saved to the database. This might be used in many use cases such as sending order data to external API, sending order emails to customers or admins, and other post creation order actions etc.
add_action( 'woocommerce_new_order', 'custom_new_order_action', 10, 1 ); function custom_new_order_action( $order_id ) { $order = wc_get_order( $order_id ); // Your custom code }
- woocommerce_checkout_order_created:
Use this hook for tasks that depend on saved order details. If your order details have custom field options, such as ‘Gift Wrapping,’ which are stored as metadata, this hook allows you to retrieve and use that metadata for sending it in order confirmation emails.
function after_order_placed( $order ) { // Loop through each item in the order. foreach ( $order->get_items() as $item_id => $item ) { // Get custom metadata for the item. $custom_meta = $item->get_meta( 'Custom Key' ); // Perform actions with the custom metadata. if ( $custom_meta ) { // Example: Log the custom meta data for debugging. error_log( "Custom Meta for Item ID $item_id: $custom_meta" ); } } } add_action( 'woocommerce_checkout_order_created', 'after_order_placed' );
- woocommerce_checkout_order_processed:
This hook is used in scenarios where you want to perform action based on the order details just after an order is completed.
add_action('woocommerce_checkout_order_processed', 'reserve_inventory_on_order', 10, 3); function reserve_inventory_on_order($order_id, $data, $order) { // Custom inventory logic here }
2. Order Status Change Hooks:
Includes all hooks related to status changes (e.g., pending to processing).
woocommerce_update_order | Fired whenever an order is updated (e.g., status, items, shipping/payment changes). |
woocommerce_order_status_{$status_from}to{$status_to} | Fired for specific status transitions, such as from “Pending” to “Processing.” |
woocommerce_order_status_changed | Fired whenever the order status changes, regardless of the specific status. |
Look into the hooks of order status changes with the sample code given below:
woocommerce_update_order
: This hook is used for any kind of update to an order, like changing the order details, products, or status.
add_action( 'woocommerce_update_order', 'add_note_when_order_completed', 10, 1 ); /** * Adds a note to the order when the status changes to 'Completed'. * * @param int $order_id The ID of the updated order. * * @return void */ function add_note_when_order_completed( $order_id ) { // Get the order object $order = wc_get_order( $order_id ); // Check if the order status is 'completed' if ( $order->get_status() === 'completed' ) { // Add a note to the order $order->add_order_note( 'Order has been successfully completed.' ); } }
woocommerce_order_status_{$status_from}_to_{$status_to}
: This is a dynamic hook which is flexible at transitions of order statuses. For example, when an order changes from “pending” to “processing”, the hook would be ‘woocommerce_order_status_pending_to_processing
‘.
add_action( 'woocommerce_order_status_pending_to_processing', 'custom_action_on_pending_to_processing', 10, 1 ); function custom_action_on_pending_to_processing( $order_id ) { // Do something when the order status changes from "pending" to "processing" $order = wc_get_order( $order_id ); $order->add_order_note( 'Order status changed from pending to processing.' ); }
woocommerce_order_status_changed
: This is a more generic hook that fires every time an order’s status changes, regardless of which status it’s changing from or to.
add_action( 'woocommerce_order_status_changed', 'custom_order_status_changed', 10, 4 ); function custom_order_status_changed( $order_id, $old_status, $new_status, $order ) { // Check if the new status is 'completed' if ( 'completed' === $new_status ) { // Perform your custom actions here // Example: Log order ID when status changes to 'completed' error_log( 'Order #' . $order_id . ' status changed to completed.' ); } }
3. Payment and Thank You Hooks
woocommerce_payment_complete | Fired when the payment is completed for specific order statuses. |
woocommerce_thankyou | Displayed after the order is placed (though not recommended for all payment methods). |
This hook ‘woocommerce_payment_complete‘ gets triggered once a payment for an order is successfully completed. But the hook is triggered only if the orders are in certain statuses such as on-hold, processing, completed, Failed before the payment is completed.
add_action( 'woocommerce_payment_complete', 'ts_complete' ); function ts_complete( $order_id ) { $order = wc_get_order( $order_id ); // do anything }
This hook ‘woocommerce_thankyou‘ is typically used to customize the order confirmation experience on the thank you page, add upsell/cross-sell options, and send custom thank you messages via emails.This hook gets triggered once a payment for an order is successfully completed. But the hook is triggered only if the orders are in certain statuses such as on-hold, processing, completed, Failed before the payment is completed.
add_action( 'woocommerce_thankyou', 'custom_thank_you_message', 10, 1 ); function custom_thank_you_message( $order_id ) { $order = wc_get_order( $order_id ); echo '<h2>Thank You for Your Purchase!</h2>'; echo '<p>Your order number is: ' . $order->get_order_number() . '</p>'; }
List of Order Hooks in Blocks Checkout
While some traditional classic checkout hooks, such as woocommerce_new_order
, woocommerce_update_order
, woocommerce_payment_complete
, and woocommerce_thankyou
, are common, they might also work with the new checkout blocks. Since the new checkout blocks use more API-based interactions (via the REST API), hooks like woocommerce_store_api_checkout_order_processed
are unique to this block-based system.
1. Order Creation and Update Hooks
woocommerce_new_order | Fired when a new order is created |
woocommerce_update_order | Fired multiple times when the order is updated |
a. Order is Created or Updated Manually in the WordPress Admin
To differentiate whether the action is from the admin, you can check the nonce in the request. If the nonce is valid, the action comes from the admin.
add_action( 'woocommerce_new_order', 'ts_create_or_update_order', 25, 2 ); add_action( 'woocommerce_update_order', 'ts_create_or_update_order', 25, 2 ); function ts_create_or_update_order( $order_id, $order ) { if ( isset( $_REQUEST[ '_wpnonce' ] ) && wp_verify_nonce( $_REQUEST[ '_wpnonce' ], "update-order_{$order_id}" ) ) { // Do your stuff (e.g., log the order creation or update) } }
b. Order Created or Updated via REST API
To check if the hook is coming from the REST API, you can check if REST_REQUEST is defined.
add_action( 'woocommerce_new_order', 'ts_create_or_update_order_restapi' ); add_action( 'woocommerce_update_order', 'ts_create_or_update_order_restapi' ); function ts_create_or_update_order_restapi( $order_id ) { if ( defined( 'REST_REQUEST' ) ) { // Do your stuff when order is created/updated via API } }
2. Block Checkout-Specific Hook
woocommerce_store_api_checkout_order_processed | Specific to Block Checkout and this hook is triggered when checkout orders are processed via REST API. |
add_action( 'woocommerce_store_api_checkout_order_processed', 'ts_handle_block_checkout_order', 10, 2 ); function ts_handle_block_checkout_order( $order_id, $data ) { $order = wc_get_order( $order_id ); // Example: Log order ID and total amount error_log( 'Block Checkout Order Processed - Order ID: ' . $order_id ); error_log( 'Order Total: ' . $order->get_total() ); // Add any custom logic here, such as sending notifications or updating order metadata }
3. Order Status Change Hooks–
The below hooks are same as Classic Checkout hooks, but could be fired at different stages due to the Block Checkout flow.
woocommerce_update_order | Fired whenever an order is updated (e.g., status, items, shipping/payment changes). |
woocommerce_order_status_{$status_from}to{$status_to} | Fired for specific status transitions, such as from “Pending” to “Processing.” |
woocommerce_order_status_changed | Fired whenever the order status changes, regardless of the specific status. |
4. Payment and Thank You Hooks
woocommerce_payment_complete | Fired when payment for the order is completed |
woocommerce_thankyou | Triggered when the order is complete |
Common Hooks to Be Used Both in Classic and Checkout Blocks
1. Order Deletion Hooks
woocommerce_before_delete_order or woocommerce_before_trash_order | Triggered before the order is deleted or moved to trash. |
woocommerce_delete_order or woocommerce_trash_order | Fired when the order is deleted or moved to trash. |
When an order is deleted, depending on whether it is moved to trash or it is permanently deleted these hooks will be used.
add_action( 'woocommerce_before_trash_order', 'ts_trash_order' ); function ts_trash_order( $order_id ) { if( isset( $_REQUEST[ '_wpnonce' ] ) && wp_verify_nonce( $_REQUEST[ '_wpnonce' ], 'bulk-orders' ) ) { // Do your stuff when order is moved to trash } }
2. Order Refund Hooks
To handle actions specific to refunds, certain hooks are triggered, including:
woocommerce_order_fully_refunded or woocommerce_order_partially_refunded | Trigerred specifically related to full or partial refunds. |
woocommerce_update_order | triggered whenever an order is updated, not necessarily due to a refund. |
woocommerce_order_refunded | fires when a refund is processed, which could be partial or full. |
If you aim to use hooks dedicatedly to add custom content in cart and checkout pages, then refer to the the visual cart page hooks and the visual checkout page hooks guide that can be used to optimize cart and checkout layouts.