WooCommerce performance: Send emails asynchronously
Published: ā Leave a comment
When purchasing a product in WooCommerce, it sends several emails by default. This delays the actual process, which already can take very long. Thus, a good strategy would be to send them asynchronously via a cron job.
Whatās a cron job?
A cron job is a task that is executed on a certain point in time. WordPress allows to define recurring tasks as well as single events (we use the latter here for every email). By default, it getās triggered via an asynchronous request from any user in the frontend, which requests the /wp-cron.php file.
On a highly frequented website (or when you want to control the exact moment the cron jobs are executed), you probably want to disable this builtin mechanic via \define( 'DISABLE_WP_CRON', true ) in your wp-config.php and define a system cron job or timer to regularly request the file (or use WP-CLI).
The solution
Luckily, we donāt even need to reinvent the wheel, since the solution is already available since 2015 on Stack Overflow. This is not limited to WooCommerce emails, but delays all emails to be only sent via cron job.
<?php
/**
* Email Async.
*
* We override the wp_mail function for all non-cron requests with a function that simply
* captures the arguments and schedules a cron event to send the email.
*/
if ( ! \defined( 'DOING_CRON' ) || ( \defined( 'DOING_CRON' ) && ! \DOING_CRON ) ) {
function wp_mail() {
// Get the args passed to the wp_mail function
$args = \func_get_args();
// Add a random value to work around that fact that identical events scheduled within 10 minutes of each other
// will not work. See: http://codex.wordpress.org/Function_Reference/wp_schedule_single_event
$args[] = \mt_rand();
// Schedule the email to be sent
\wp_schedule_single_event( \time() + 5, 'cron_send_mail', $args );
}
}
/**
* This function runs during cron requests to send emails previously scheduled by our
* overrided wp_mail function. We remove the last argument because it is just a random
* value added to make sure the cron job schedules correctly.
*
* @hook cron_send_mail 10
*/
function example_cron_send_mail() {
$args = \func_get_args();
// Remove the random number that was added to the arguments
\array_pop( $args );
\call_user_func_array( 'wp_mail', $args );
}
/**
* Hook the mail sender. We accept more arguments than wp_mail currently takes just in case
* they add more in the future.
*/
\add_action( 'cron_send_mail', 'example_cron_send_mail', 10, 10 );
Code language: PHP (php)
Just save this code and place it inside /wp-content/mu-plugins/asynchronous-emails.php (if the directory does not exist, create it) and it will be automatically executed by WordPress as a āmust useā plugin. That way, you can probably save a second in the checkout.
Reposts