Defer WooCommerce emails for a specified time after the normal delivery time.
After completing the code for Add Tracking Info to WooCommerce order Elizabeth reported intermittent issues where the tracking info was not in the Order Completed emails. I suspected that there was a small delay with Shippo pushing the tracking data back to her site. Shippo suggested delaying the Order Completed email to allow for the small delay (which could be a few minutes).
Stepping through the code
When WooCommerce 3.0 was released it deferred transactional emails (i.e. emails sent when the order status changes) by 5 seconds (increased to 10 seconds in later release). Deferring the emails was primarily to speed up the checkout process. In version 3.0.3 this was disabled by default but could be enabled with a filter.
I read through the WooCommerce code and later stepped through it with Visual Studio Code. The debugging confirmed what my code reading found – there was no WooCommerce filter to change the delay time from 10 seconds. I even looked at filters in the wp_schedule_event() function but there didn’t appear to be enough data to idenfity WooCommerce email events.
I found that another developer, Dan Wich, encountered the same issue. While typing a comment on his post I got an idea – set up my own scheduled event!
It happens frequently when, after extensive investigation and debugging of an issue, writing a post on a forum gives me an idea for a solution. It’s a sort of ‘a problem shared is a problem halved‘ type thing.
My experiments in trying to find a filter were very helpful in finding the existing WooCommerce filters that I needed to use. The final logic is quite simple:
- Enable deferred emails
- Examine an email just before it is to be sent – disallow it and schedule a future event to send it (include the order ID and email identifier)
- The scheduled event function directly triggers the email for the specified order ID.
When an email is deferred you can see it in a list of scheduled actions. I installed Advanced Cron Manager plugin while testing. The scheduled event is called ‘send_deferred_woocommerce_email‘. The arguments are the order number and the email identifier.
My initial code only deferred the Order Completed email but I generalised the code to allow any WooCommerce transactional email to be deferred and a different delay time for each one.