In the previous chapter, I walked you through WordPress caching. In this chapter I will demonstrate how to configure WordPress cron and set up outgoing email.

Cron

WordPress has built-in support for scheduled tasks, which allows certain processes to be performed in the background at designated times. Out-of-the-box WordPress performs the following scheduled tasks:

  • Automatic updates which are pushed out by the WordPress core team to fix security vulnerabilities
  • Check WordPress is running the latest stable release
  • Check for plugin updates
  • Check for theme updates
  • Publish any posts scheduled for future release

However, the cron system used by WordPress isn’t the most performant or accurate of implementations. Scheduled tasks in WordPress are triggered during the lifecycle of a page request, therefore if your site doesn’t receive any visits for a set period of time, no cron events will be triggered during this time.

This is especially true of sites that use page caching, such as Nginx FastCGI cache introduced in the previous chapter. With page caching enabled, WordPress is no longer processing each page request if the page cache is hit. This means that cron will not fire until the page cache expires. If you have configured the cache to expire after 60 minutes this may not be an issue, however, if you are caching for longer periods of time this may become problematic.

Using page requests to execute the cron is also problematic on sites without page caching that receive a lot of traffic. Checking if the cron needs to be executed on every page request is hard on server resources and several simultaneous requests could cause the cron to execute multiple times.

To overcome these issues cron should be configured using the operating system daemon (background process), available on Linux and all Unix-based systems. Because cron runs as a daemon it will run based on the server’s system time and no longer requires a user to visit the site.

Before configuring cron it’s recommended that you disable WordPress from automatically handling cron. Add the following line to your wp-config.php file:

define('DISABLE_WP_CRON', true);

Introducing Crontab

Scheduled tasks on a server are added to a text file called crontab and each line within the file represents one cron event. If your server hosts multiple sites you will need one entry per site.

Begin by connecting to your server.

ssh ashley@pluto.ashleyrich.com

Open the crontab using the following command. If this is the first time you have opened the crontab, you may be asked to select an editor. Option 2 (nano) is usually the easiest.

crontab -e

Crontab Editor

I’m not going to go into detail on the crontab syntax, but adding the following to the end of the file will trigger WordPress cron every 5 minutes. Remember to update the file path to point to your WordPress install and to repeat the entry for each site.

*/5 * * * * cd /home/ashley/ashleyrich.com/public; /usr/local/bin/wp cron event run --due-now >/dev/null 2>&1

Some articles suggest using wget or curl for triggering cron, but using WP-CLI is recommended. Both Wget and cURL make requests through Nginx and are subject to the same timeout limits as web requests. However, you may want your cron jobs to run for longer periods of time, for example if a plugin is uploading hundreds or thousands of media files to Amazon S3 as a background process. There is no timeout limit when running WordPress cron via WP-CLI, it will execute until complete.

The >/dev/null 2>&1 part ensures that no emails are sent to the Unix user account initiating the cron job.

Save the file by hitting CTRL + X followed by Y.

Cron is now configured using the Unix system cron tool, but I’ll demonstrate how to check it’s running correctly later on.

Email

Email servers are notoriously difficult to set up. Not only do you need to ensure that emails successfully hit recipient inboxes, but you also have to consider how you’ll handle spam and viruses (sent as email attachments). Installing the required software to run your own mail server can also eat up valuable system resources and potentially open up your server to more security vulnerabilities. This DigitalOcean article discusses in more detail why you may not want to host your own mail server.

I do not recommend that you configure your server to handle email and instead use a ‘best of breed’ service provider, such as Google Workspace. However, WordPress still needs to send outgoing emails:

  • Admin notifications
  • New user signups
  • Password resets
  • Auto update notifications

And that’s just WordPress core. Add plugins to the mix and the volume and importance of emails sent from your site can balloon. Think WooCommerce and order receipts.

Outgoing Email

Although it’s popular to configure WordPress to use SMTP for outgoing email, we do not recommend it. Instead, you should use a WordPress plugin that connects directly to an email sending service via an API.

Preferably a plugin that queues emails to be sent later when the API is unreachable instead of never sending them. WP Offload SES and WP Offload SES Lite are such plugins. In addition to simplifying the setup process WP Offload SES sends emails via Amazon SES, so you can be sure of high deliverability and low costs.

Testing Cron and Outgoing Email

In order to test that both cron and outgoing emails are working correctly, I have written a small plugin that will send an email to the admin user every 5 minutes. This isn’t something that you’ll want to keep enabled indefinitely, so once you have established that everything is working correctly, remember to disable the plugin!

Create a new file called cron-test.php within your plugins directory, with the following contents:

<?php
/**
 * Plugin Name: Cron & Email Test
 * Plugin URI: https://spinupwp.com/hosting-wordpress-yourself-cron-email-automatic-backups/
 * Description: WordPress cron and email test.
 * Author: SpinupWP
 * Version: 1.0
 * Author URI: http://spinupwp.com
 */

/**
 * Schedules
 *
 * @param array $schedules
 *
 * @return array
 */
function db_crontest_schedules( $schedules ) {
    $schedules['five_minutes'] = array(
        'interval' => 300,
        'display'  => 'Once Every 5 Minutes',
    );

    return $schedules;
}
add_filter( 'cron_schedules', 'db_crontest_schedules', 10, 1 );

/**
 * Activate
 */
function db_crontest_activate() {
    if ( ! wp_next_scheduled( 'db_crontest' ) ) {
        wp_schedule_event( time(), 'five_minutes', 'db_crontest' );
    }
}
register_activation_hook( __FILE__, 'db_crontest_activate' );

/**
 * Deactivate
 */
function db_crontest_deactivate() {
    wp_unschedule_event( wp_next_scheduled( 'db_crontest' ), 'db_crontest' );
}
register_deactivation_hook( __FILE__, 'db_crontest_deactivate' );

/**
 * Crontest
 */
function db_crontest() {
    wp_mail( get_option( 'admin_email' ), 'Cron Test', 'All good in the hood!' );
}
add_action( 'db_crontest', 'db_crontest' );

Upon activating the plugin, you should receive an email shortly after. If not, check your crontab configuration and WP Offload SES settings.

That concludes this chapter. In the next chapter we’ll look at configuring automatic backups for your sites.