WP Cron in Practice: wp_schedule_event Examples + More

A few weeks ago we talked about what “cron jobs” were in WordPress and beyond. That tutorial about what “WordPress scheduled tasks” are hopefully gave you a good understanding of some of the things that you might do with them. Today we’ll instead focus on how you’ll use wp_schedule_event to actually do them. That is, we’ll cover a number of WordPress cron job examples.

At a high level, these means that we’ll come to understand the wp_schedule_event function, and see how we can use it and few helpful other functions to use WP-Cron in a WordPress plugin. We’ll also briefly look at really useful WP cron plugin for finding out if/when your scheduled tasks for WordPress will run. Let’s get to it.

Refreshing our Understanding of WP Cron for Plugins (& more)

Before we get to our WordPress cron example, a quick overview. We call the general class of “solve scheduling of function calls” in the computer space to be about “cron.” This is why we often see people refer to the WordPress scheduling system as “WP-Cron” even though it’s member functions refer to WordPress “scheduled events.” They’re all about the same thing: scheduling things to happen on a WordPress site.

To help make this concrete, here are a few things using wp_schedule_event on WPShout itself right now:

  • WordPress (core) cleaning up auto-drafts of posts that shouldn’t be kept any longer
  • Jetpack cleaning up its transients (temporarily cached variables) on a schedule more aggressive then WordPress’s.
  • WordPress (core) cleaning up transients
  • Yoast SEO scheduling some thing (I’m not sure what) called onpage_fetch to run weekly
  • Updraft Plus running backups to Dropbox

I could go on, or name a large number of other similar things. I think it gets you started to think about when and why you might want to reach for wp_schedule_event yourself. So let’s get to it, how do you use that function and others to schedule task running in WordPress.

The Main WordPress Cron Hook: wp_schedule_event

So first we’ll start to understand how to create a “WP Cron Job” by understanding that function signature of wp_schedule_event. It looks like:

wp_schedule_event( $timestamp, $recurrence, $hook, $args);

So, those parameters in more detail:

  1. $timestamp is meant to be the first time you want the event to occur. So the most common value submitted here is the current time. You get that in PHP with the time() function.
  2. $recurrence is a string value saying when you want the event to run. By default WordPress expects the values hourly, twicedaily or daily. As we’ll show off in just a bit, you can make a wp_schedule_event registered events run on a different schedule than those three, but those are the most common by far.
  3. $hook will be the (name of the) function you want WordPress to call when your event runs. This is a string like 'updraft_backup' where your function is called updraft_backup.
  4. $args is any argument(s) that your $hook function will need to see when called. I’ve never used it, and we won’t see it in any examples, but it’s good to know you can pass them.

Making wp_schedule_event Daily Run Your Function

Now that we have a sense of how to call wp_schedule_event, let’s see it used in context to schedule a function we made up called wpshout_do_thing to run every day. In a plugin, that might look like:

register_activation_hook( __FILE__, 'wpshout_plugin_activation' );

function wpshout_plugin_activation() {
    if ( ! wp_next_scheduled( 'wpshout_do_thing' ) ) {
        wp_schedule_event( time(), 'daily', 'wpshout_do_thing' );
    }
}

Now, you can run your code which calls wp_schedule_event a bunch of ways. But one of the best ones is to tie it to a single-time event, like the plugin being activated. That’s what we’re doing here.

Then we’re making sure that an event for us is not already scheduled. We’ll go into more detail on this later, but this is a good practice just to make sure you don’t end up running your event a few different times because someone was, for example, trying out your plugin and deactivating it over-and-over.

Clean Up After Yourself: wp_clear_scheduled_hook

If you’ve gone the path of rooting your scheduled task to the plugin being activated, you may also want to make sure that your task doesn’t cause an error if your plugin is turned off (deactivated). To do that, you can remove your scheduled event when they deactivate the plugin. That’d look like:

register_deactivation_hook( __FILE__, 'wpshout_plugin_deactivation' );

function wpshout_plugin_deactivation() {
    wp_clear_scheduled_hook( 'wpshout_do_thing' );
}

As you might have guessed, wp_clear_schedule_hook will just un-register the $hook or “task name” you’ve scheduled with a call to wp_schedule_event.

wp_schedule_event Daily at a Specific Time

Let’s say your website gets the least traffic at 3am. And so you want your backups not when the plugin is initially activated, but at a specific time. In this example code of wp_schedule_event, we’ll aim for 3am on your server. I’d do that like this:

wp_schedule_event( strtotime( '3am tomorrow' ), 'daily', 'wpshout_do_thing' );

The PHP function strtotime means “make this string into a time.”So it returns the same sort of value as time, but lets us use a more English-y phrase. So this task will first run at 3AM tomorrow morning and not right now. And then, because we’ve set the $frequency to 'daily', it should keep recurring every day at 3am. The downside to consider: if your users will have needed/wanted this to happen right away, you’ll want some other system to do that for them too. Which could be wp_schedule_single_event. But I want to cover another example before we get there…

wp_schedule_event every minute

So WP-Cron has a few really useful default intervals, but “every minute” isn’t one it offers. There are lots of reasons for this. Primarily these two:

  • Running at task every minute can add a lot of overhead on your server.
  • Running a task every minute is kind of at odds with the need-for-visits that makes WP-Cron a little unreliable for low-traffic sites. I talked a bit more about this in my introduction to WordPress scheduled tasks.

That said, there may be reasons that you want “every minute” or some other interval that WordPress doesn’t support for cron intervals out of the box. If you find yourself in that situation, this example code should help. First you must declare your interval:

add_filter( 'cron_schedules', 'wpshout_add_cron_interval' );
function wpshout_add_cron_interval( $schedules ) {
    $schedules['everyminute'] = array(
            'interval'  => 60, // time in seconds
            'display'   => 'Every Minute'
    );
    return $schedules;
}

So here the WordPress cron_schedules filter hook passes us an array of the interval it knows about. And we add to the passed array our interval, in this case I named it everyminute.

Then we just use wp_schedule_event, knowing that our interval, everyminute, exists (same as the stock daily one does):

wp_schedule_event( time(), 'everyminute', 'wpshout_do_thing' );

This system is exactly what it looks like to make all kinds of custom intervals. If you’re a true chaos monkey, you could even do this (I don’t recommend it):

add_filter( 'cron_schedules', 'wpshout_add_weird_cron_interval' );
function wpshout_add_weird_cron_interval( $schedules ) {
    $schedules['wpshout_random'] = array(
            'interval'  => rand(100, 9999999), // time in seconds
            'display'   => 'Random Interval'
    );
    return $schedules;
}

But that’d be making chaos in your WordPress cron schedules, so I don’t really recommend it.

WP Cron Not Working: Some conceptual prep

I’ve said it before and I’ll say it again: WP-Cron isn’t a “real” cron. It requires that your site gets visits onto which WordPress can tack the function-runs you’re scheduling. To that end, if WP-Cron isn’t working in the way you’d expect, you may need to “make WordPress cron into a real cron.” What that looks like is covered well in this little SiteGround tutorial.

Other Powers, like How do I Schedule Once in WordPress?

So far we’ve mentioned a number of the major WP Cron functions, but I want to quickly run through the others that you may encounter or need to know in a bit more depth.

What’s wp_schedule_single_event?

Sometimes you’ll want your event or scheduled code to happen just once, and “not now.” So how do you schedule something to run once in WordPress? There’s a function called wp_schedule_single_event for that. As you might guess it lets you make a “WordPress cron job” that’s a one off.

As you might guess, it works pretty similarly to wp_schedule_event. wp_schedule_single_event is called just like this:

wp_schedule_single_event( strtotime( '3am tomorrow' ), 'wpshout_do_thing' );

You’ll notice that this example code for wp_schedule_single_event looks familiar. What’s different? We lose the second “recurrence interval” that you’ll see on wp_schedule_event. Which makes perfect sense, because that _single_ in the name of the function makes it pretty clear that an $interval doesn’t really make sense. Other than that, everything is pretty similar in wp_schedule_event and wp_schedule_single_event code samples.

DISABLE_WP_CRON?

So let’s say you want WordPress to never run WordPress “cron jobs” when the page loads? That’s where the DISABLE_WP_CRON constant comes in. What it does is allow you to run the site’s cron jobs via a direct call (with cURL, a browser, etc) to example.com/wp-cron.php to do the tasks, but means that it’ll never add cron work to a page load. This’ll make page responses that might have been caught by a big cron task a whole lot faster.

To use it, you’ll put define( 'DISABLE_WP_CRON', true ); in your wp-config.php. But don’t do so unless you find some other way that WordPress can do cron jobs. If you just disable cron and don’t build a real cron job (on Unix, etc) to make up for it, scheduled tasks simply won’t run on your WordPress site.

What wp_next_scheduled does

We mentioned it earlier, but to recap wp_next_scheduled is a way that we can pass WordPress a name and it can tell us if or when that task will run next. This is super useful for us to not schedule a new event when there’s already another one scheduled for us. This is why our ideal way to use wp_schedule_event is like this:

register_activation_hook( __FILE__, 'wpshout_plugin_activation' );

function wpshout_plugin_activation() {
    if ( ! wp_next_scheduled( 'wpshout_do_thing' ) ) {
        wp_schedule_event( time(), 'daily', 'wpshout_do_thing' );
    }
}

(Because the above WP-Cron code snippet is the same as before I’ll not really explain it.) Though it is worth noting that wp_next_scheduled will give us the (Unix epoch) time that a task will run if it was going to. So you could also use it to do something like this:

$seconds_until_task_will_run = 
    wp_next_scheduled( 'wpshout_do_thing' ) - time(); 

Now you might get a negative value if wpshout_do_thing isn’t scheduled. But I can see a few reasons you’d do this. Again, what this’ll do is get when your next task is scheduled (in seconds since Jan 1, 1970), and then subtract the current time.

More on wp_clear_scheduled_hook

Like above, we covered wp_clear_scheduled_hook a bit already. In short, it’s how you make sure that you’ve cleaned up after yourself and your WordPress plugin cron tasks. So that relevant code snippet from above:

register_deactivation_hook( __FILE__, 'wpshout_plugin_deactivation' );

function wpshout_plugin_deactivation() {
    wp_clear_scheduled_hook( 'wpshout_do_thing' );
}

As I said, it just clears tasks. So please only use it on your own scheduled tasks, unless you really know what you’re doing.

See Scheduled Cron Jobs

A last important thing: how do I confirm that I’ve successfully used wp_schedule_event to schedule my task in WordPress?

As you might have discerned, wp_next_scheduled could be used to do this. But it’s not the easiest to use. Instead, I’ve used and appreciated a great deal the WP Crontrol plugin. As you might guess, it shows you all the relevant hooked things on your whole WordPress site. Which makes it pretty darn easy to control cron tasks, or just make sure that your WordPress cron example code has worked. 🤓

What We’ve Learned about wp_schedule_event and WP Cron Jobs in General

So hopefully with what we’ve covered today you’re pretty comfortable understanding WP cron jobs, how to schedule them, and a few more of the relevant variables and elements you need. wp_schedule_event is the heart of the WP Cron system. And simply WordPress sites wouldn’t work without them.


2 Comments
Most Voted
Newest Oldest
Inline Feedbacks
View all comments
dkolarevic
January 30, 2024 2:10 am

strtotime( ‘tomorrow 3am’) works for me instead of strtotime( ‘3am tomorrow’)!!

Blaz K.
March 9, 2020 5:56 am

Hi David,

nice post about CRON in WordPress but there is a mistake in “MAKING WP_SCHEDULE_EVENT DAILY RUN YOUR FUNCTION” section. You are saying that the code in the example will make wpshout_do_thing function run daily, which is not the case. wpshout_do_thing is in that case a hook as the third parameter of wp_schedule_event function is not a function but a hook. So, the example will not work. Unless, you add the following:

add_action(‘wpshout_do_thing’, ‘wpshout_do_thing_run’);

And then you also need a function wpshout_do_thing_run which does what you want it to do once daily.

You could also just add:

add_action(‘wpshout_do_thing’, ‘wpshout_do_thing’);

Then wpshout_do_thing function will run daily.

Regards,
Blaz