You can automatically cancel unpaid orders in WooCommerce by scheduling a one-time event with wp_schedule_single_event() when an order enters “pending,” then checking the status again after your chosen delay and cancelling it if payment still hasn’t come through.
Why Not Just Use “Hold Stock Minutes”?
- The built-in Hold Stock Minutes setting only works when stock management is enabled — stores that don’t track stock get no automatic cancellation at all
- You may want to target a specific status like “failed” instead of “pending,” which the built-in setting doesn’t cover
- Conditional logic (only cancel orders under a certain value, or from certain payment methods) isn’t possible with the default setting
Step 1: Schedule the Cancellation When the Order Goes Pending
/** Automatically cancel a WooCommerce order if it's still pending after 2 hours */
add_action( 'woocommerce_order_status_pending', 'schedule_pending_order_auto_cancel' );
function schedule_pending_order_auto_cancel( $order_id ) {
$delay = 2 * HOUR_IN_SECONDS;
if ( ! wp_next_scheduled( 'run_pending_order_auto_cancel', array( $order_id ) ) ) {
wp_schedule_single_event( time() + $delay, 'run_pending_order_auto_cancel', array( $order_id ) );
}
}
add_action( 'run_pending_order_auto_cancel', 'cancel_order_if_still_pending' );
function cancel_order_if_still_pending( $order_id ) {
$order = wc_get_order( $order_id );
wp_clear_scheduled_hook( 'run_pending_order_auto_cancel', array( $order_id ) );
if ( $order && $order->has_status( 'pending' ) ) {
$order->update_status( 'cancelled', 'Auto-cancelled: no payment received within the allowed window.' );
}
}
Targeting a Different Status
Swap the hook to target another status instead, for example cancelling orders that go to “failed”:
add_action( 'woocommerce_order_status_failed', 'schedule_pending_order_auto_cancel' );Troubleshooting
Orders Aren’t Cancelling On Schedule
WP-Cron relies on site traffic to fire scheduled events — a low-traffic store might see delayed execution. Consider a real server cron job hitting wp-cron.php on a fixed schedule if timing accuracy matters.
Order Gets Cancelled Even After Payment Clears
Double-check the status condition in cancel_order_if_still_pending() — it should only cancel if the order is still pending at execution time, so a payment that clears in the meantime should already have moved the order out of “pending.”
Frequently Asked Questions
Will this restore stock automatically?
Yes, as long as you haven’t disabled WooCommerce’s default restocking behavior — cancelling an order restores stock the same way as any other cancellation.
Can I change the cancellation delay?
Yes, adjust the $delay value — it’s expressed in seconds, so use WordPress time constants like HOUR_IN_SECONDS or DAY_IN_SECONDS for readability.
Does this conflict with the built-in Hold Stock Minutes setting?
It can if both are active and targeting the same orders — pick one approach, or make sure their timing doesn’t overlap in a confusing way.
Conclusion
Automatically cancelling unpaid orders in WooCommerce with a scheduled event gives you far more control than the built-in stock-hold setting — you decide which statuses, how long to wait, and exactly what happens next.
See also How to Print WooCommerce Orders Automatically. Then read How to Automatically Complete Processing Orders in WooCommerce.
Prefer no code? All-in-One Utilities Woo Add-on adds over 50 WooCommerce features, so you can switch them on without code.