WooCommerce: orders not canceled after hold stock time frame

You may already know that WooCommerce has a feature called the Hold stock (minutes). This feature allows merchants to cancel pending orders automatically after a specific time frame.

Yet, you may experience where WooCommerce does not cancel a pending order despite the configuration in the inventory settings.

The reason is that WooCommerce will schedule a WP-Cron called woocommerce_cancel_unpaid_orders, where the frequencies follow the woocommerce_hold_stock_minutes. The scheduling design results in a delay in order status change.

Hence, the bigger the minutes set, the longer WooCommerce may take to change the order status from ‘pending payment’ to ‘canceled.’

The oversimplified worst-case formula is: Hold stock (minutes) X 2 + WP Cron.
Chronology example: Hold stock (minutes) = 60 minutes

Now, the statement may be confusing to some. Hence, I prepared the simulation chronology below to help you understand the root cause.

12:00:00 AM: WP-Cron executes and run woocommerce_cancel_unpaid_orders

12:00:01 AM: Customer places Order #1 and abandons it

12:05:00 AM: WP-Cron executes but does not run  woocommerce_cancel_unpaid_orders

12:09:00 AM: (Same status as above)

1:00:00 AM: WP-Cron executes and run woocommerce_cancel_unpaid_orders. (Order #1 remains pending since it has yet to meet the required time frame)

1:05:00 AM: WP-Cron executes but does not run woocommerce_cancel_unpaid_orders since it supposes to run at 2:00:00 AM. Hence, Order #1 remains pending until 2:00:00 AM.

2:00:00 AM: Order #1 is canceled (instead of at 1:00:01 AM)

How to solve it?

The solution is pretty straightforward.

You need to customize the WooCommerce plugin by hooking the woocommerce_cancel_unpaid_orders_interval_minutes to force the woocommerce_cancel_unpaid_orders task to be scheduled more frequently. 

Depending on the business requirement, you may set it to the lowest value, which is one (1). Setting the time interval to one (1) means, provided the WP-Cron runs every minute (considering ceteris paribus), the maximum starvation time is only one (1) minute.

You can code on your own and add filters accordingly as per below:

add_filter('woocommerce_cancel_unpaid_orders_interval_minutes', function($minute){
  return 1; // this will set frequency to 1 minute.
});

Alternatively, you may install the plugin I made at GitHub.

Hope this helps!

Related topic:

php – Woocommerce Doesn’t cancel orders on hold status – Stack Overflow


We’re always open to content contributions from our community. Join our Facebook Group and share your work or topic ideas to potentially be featured on our blog.

Moreover, if you have suggestions for our upcoming features, we’d love to hear them! Share your Wishlist with us.

Don’t forget to like and follow us on our social media platforms if you haven’t yet. You can find us on Facebook, Twitter, Instagram, and LinkedIn. We appreciate your support! 🙂

Share your love
Wan Zulkarnain
Wan Zulkarnain

Technical Sales Specialist

Articles: 2