As it relates to scheduling events in WordPress, there’s a lot of articles that already exist on setting up a WordPress cron job, but – and for what I believe to be a number of reasons – there’s a surprising lack of clarity around the topic.

Of course, I could be wrong – maybe I’ve just been looking in all of the wrong places.

Whatever the case may be, this is something that I’ve been dealing with in a couple of projects, and I thought I’d capture my notes here if, for no other reason, than to reference in the future.

Understanding WordPress Cron Jobs

Before actually taking a look at WordPress cron jobs, it’s important to understand exactly what a cron job is.

Simply put, a cron job is a task that is set to run at a specified interval. Generally speaking, it’s available on Linux or Unix-based system (OS X included) and, thus, most web hosts.

So if you’re looking for a way to execute a certain command several times a day, a certain time of day, a certain time of the week, month, or whatever else, then this is what you use.

What Are WordPress Cron Jobs?

For anyone who has spent time working with WordPress, then you’ve no doubt noticed the wp-cron.php file or the WordPress codex articles for <a title="wp_cron" href="http://codex.wordpress.org/Function_Reference/wp_cron" target="_blank">wp_cron</a> or <a title="wp_schedule_event" href="http://codex.wordpress.org/Function_Reference/wp_schedule_event" target="_blank">wp_schedule_event</a>.

wp_cron

As convenient as this functionality is, the best way that I know how to describe WordPress cron jobs are as faux cron jobs.

Here’s why: whenever a cron job is defined within the context of an operating system, it is scheduled to run by the operating system for that particular time regardless of if the person is at the computer or not.

After all, what would be the purpose of scheduling a job if it had to run manually?

When it comes to WordPress, you can schedule an event to happen at a certain interval, but it doesn’t operate like a classical cron job.

Instead, the event is set and scheduled and written to the database. The next time a user hits the site, the WordPress cron system will look to see if an event is scheduled and, if so, will then fire the event.

Notice the problem?

Someone has to visit the site before the event actually kicks off. So if you’ve scheduled something to happen hourly, but no one has visited your site in the last hour, then the event will never kick off.

If you have a very active site, then this isn’t a problem, but if you’re, say, building a plugin that needs to execute some code every hour, day, week, month, or whatever then using the default WordPress cron job system is simply not a good idea.

Setting Up a WordPress Cron Job

To give a real world example, here’s a scenario in which I’ve been working:

  • A user drops a CSV file into a directory
  • Every hour, the directory needs to be checked for the presence of a file
  • If a file exists, then the data needs to be imported and the file deleted; otherwise, the job can be skipped

Easy enough, right?

But here’s the challenge: If I setup a job using wp_schedule_event and no one visits the site, then nothing will actually happen until the next person visits the site.

Sad story.

Here’s what needs to happen:

  • From a code level, an algorithm for the above procedure needs to be defined
  • An actual Unix-level cron job needs to be scheduled to fire each hour

Specifically, the cron job defined at the Unix level needs to be setup such that it runs at whatever interval you like and that it mimics a user visiting the site.

Luckily, this is really easy to do.

Defining a WordPress Cron Job

To fully define a WordPress cron job, then this is what needs to happen:

  1. Disable the WP Cron System
  2. Setup your event code using wp_schedule_event in your plugin or in functions.php
  3. Define a cron job

Nothing terribly complicated – here’s code for how to handle all of the above.

1. Disable WP Cron

In your wp-config.php file, add the following line:

define('DISABLE_WP_CRON', true);

Done and done.

2. Setup Your Event Code

Note that YMMV based on whether or not you’re working with a plugin or with wp-config.php, but here’s the gist of everything that needs to happen.

1. Add Event Action

First, define a custom action for your, say, hourly event and give it the name of the function that will be fired each hour.

add_action( 'my_hourly_event',  'update_db_hourly' );

In our case, that function is update_db_hourly .

2. Define The Function

Now, define the function update_db_hourly for scheduling the event with WordPress.

If you’re working with a plugin, then you can schedule the event during the plugin’s activation (but also remember to remove the schedule when the plugin is deactivated):

public static function activate() {
    wp_schedule_event( time(), 'hourly', 'my_hourly_event' );
}

public static function deactivate() {
    wp_clear_scheduled_hook('my_hourly_event');
}

Finally, define the function that’s responsible for actually, y’know, doing the work:

public function update_db_hourly() {

    // 1. Check for a new file
    // 2. If it exists, read it, upload it, delete it
    // 3. Otherwise, do nothing

}

3. Setup The Cron Job

Most web hosts provide an interface for defining cron jobs, but not all applications are running within the context of a cPanel-based web host.

Some are simply running on an internal server or something similar where all you have is access to the command line. And considering that the cPanel is nothing more than a GUI to the command line, here’s what you need to know to define a cron job at the operating system level:

Launch the cron job file editor in your terminal using crontab -e:

crontab -e

This will bring up a seemingly empty file (if you’ve not defined any other jobs):

Empty Cron File

Next, add the following line into the cron file:

/15 * * * wget -q -O - http://yourdomain.com/wp-cron.php?doing_wp_cron

Of course, you’ll want to change up the domain for your own purposes.

The complete guide the cron commands and tools such as wget is outside the scope of this article, but this will trigger an event to fire every 15 minutes that will make a request to your WordPress website thus kicking off any scheduled tasks.

Not bad, right?

WordPress Cron Jobs

Overall, it’s not a terribly complicated procedure to setup but there are several gotchas that, unless you’re familiar with how the WordPress cron system works, can really cause some serious problems in your work.

Hopefully the notes above demystify a bit of how WordPress handles scheduled events and how you can force them to kick off using your hosting environment.

Category:
Notes
Tags:

Join the conversation! 131 Comments

  1. Just had to run manual cron jobs on a few client sites and include cron locking with `define(‘WP_CRON_LOCK_TIMEOUT’,60);` because the client was getting huge process pile ons which was having huge effect on their bill.

    Do you always schedule cron manually or just leave it for 99% of the work and run manually with a proper cron job if the specific client requires it?

    • This is actually a good tip and isn’t something that I’ve run into yet, so I’m glad to know what you’ve done.

      Honestly, I tend to schedule cron jobs manually along with using `wp_schedule_event` simply because I like the peace of mind that comes knowing that it’s going to run and isn’t going to rely on a page load (especially for lesser visited sites), you know?

  2. Nice post Tom!

    As the old guy, I tend to forget that even the word “cron” can be abstract to some people trying to understand. So now I usually mention that the word Cron is derived from Chronos. So in teaching, I call them Chronological jobs. Jobs that are on a calendar, that the OS will execute at said time & date.

  3. One question I was hoping to see answered, although not a WordPress specific question, is how often is too often for a cron job?

    Last year I made a mobile social photo sharing site using buddypress. Because of the lack of ios support for web apps accessing the photo library, I set it up so that people at events could upload to Flickr, and then have them pulled into buddypress. As people want to see photos as soon as possible I wanted the cron set for the shortest time possible to check for photos with the appropriate tag. I couldn’t find anything on line to say if one minute would cause too much server load. It didn’t appear to on the tests I ran. Do you or anyone know the problems of setting really short time frames for cron jobs?

    • Honestly, the most frequent cron job I’ve ever run is one every 15 minutes.

      The thing is, it also depends on how much time the actual job takes to run; otherwise, they could start stacking and then – depending on your implementation – could cause some really mixed up results.

      So, in your example, let’s say one person upload 10 photos but another uploads 1,000 photos – the job would obviously take longer for the latter. In that case, you’d want to queue the jobs.

      Although “as fast as possible” would be nice, unless you’re willing to invest in some hardware or other software for splitting the jobs across multiple machines, giving a limit of photos or a wider time period of jobs would be your next best bet.

      Hope this helps!

      • Thanks for your reply. The web app was only designed for a small number of people, sharing a small number of photos at an event that could be viewed by everyone, and not just their facebook or twitter friends. If anyone has any experience or links to the problems of very frequent cron jobs on low intensive tasks, I’d be interested to know.

  4. Very nice article, and gives a good understanding of WordPress cron jobs, however just one thing I m not able to understand, we have to disable the WordPress cron by defining define(‘DISABLE_WP_CRON’, true); in wp-cron.php file, and then we are also using wp_schedule_event(); function, so if we disabled wordpress cron, how is this function working? I m guessing we are not disabling wordpress cron because other default crons still working like theme and plugin updates(which are scheduled twice a day).
    So what are we disabling then?

    • This is a great question.

      What you’re disabling is WordPress’ built in functionality for firing its cron jobs on every page loads. This is why `wp-cron` is kind of a pseudo-solution. It works fine for low traffic sites, but when you’re getting thousands of hits per day, then you can end up suffering performance.

      Hope this helps!

  5. Hi Tom,

    We are getting an error with order emails from WooCommerce sending numerous times – like 6 or 7 times for each order confirmation email. It has only just literally started happening today (as far as I know) but is obviously very annoying for both us and customers.

    Could this be an issue with WPCron do you think?

    Does using the built in WPCron funtionality on each page load have a negative effect on site performance for a site that receives around 12k visits per month?

    Cheers

    • This all depends on how the cron job is configured.

      If you’re using WPCron – rather than true cron jobs, yes, this is absolutely a possibility. If you’re using a standard cron job, it can still happen, but it depends on what the interval is set.

      Another thing that could be happening is a flag isn’t being set properly or quick enough to denote that emails have been sent.

      I know a couple of the Woo guys and I’ll see if I can get them to chime in, as well :).

      • Hi Tom,

        Yes we are using WP Cron at the minute. Looking at our log files, I think it is WP Cron which triggers the emails.

        Would changing the wp cron lockout time to something a bit longer fix the issue?

        Or do you think I should just sack off WP Cron altogether and just go to manual?

        Cheers

    • Hey Aaron, I don’t think this is an issue with WP-Cron since WooCommerce doesn’t use it to send order emails — they’re sent immediately after an order is received as part of the checkout process. This maybe sounds like there’s an errant plugin duplicating the hooks that send the transactional email, check out this section: https://github.com/woothemes/woocommerce/blob/v2.0.14/woocommerce.php#L524

      • Hi Max,

        I see – thanks for the update. I am using a plugin called WooCommerce Linnworks Integration to integrate woocommerce with our invoicing/shipping software.

        I believe that when we set the order as processed, and then re-sync with the website that plugin is automatically marking the orders as complete on the system.

        This error is not just happening on order received emails, but also on all order update emails – order complete etc.

        The weird thing is that sometimes one email gets sent, sometimes 2, and sometimes up to 7 or 8. Surely if there was just a duplication of transactional hooks it would just send 2 copies each time – not 7 or 8?

        On a side note, would disabling WP Cron and changing to manually configured cron jobs provide performance benefits to a site with 35k page views a month?

        Thanks

  6. Can you reliably replicate it sending multiple orders each time you checkout? If so, I’d try disabling the Linnworks integration (though I just glanced at the code and it doesn’t look like anything would cause this) and check out again. WooCommerce by itself will not send multiple emails like this, so it’s almost certainly a plugin or theme issue that’s wreaking havoc :)

    At 35k PV/month I don’t think WP-Cron would affect the performance of the site. Certainly using a system cron is way more reliable and if you have the ability to set one up, I’d definitely do that, but if you’re having performance issues they’re almost certainly with something else.

    • Hi Max,

      No it doesn’t happen during checkout as far as I can tell (it hasn’t sent duplicate emails, to me at least, for the “new customer order” emails).

      This only seems to occur with order update emails – for example order completed (when you change status from processing to completed) and emails such as those when a paypal payment is reversed and it sends you a notification.

      It also happens on emails from the WooCommerce Follow Up Emails plugin available from the WooThemes website.

      One thing I noticed which is probably related, is that on the “order notes” section where it usually leaves a note saying the status has been changed from processing to completed, it has put the note 7 times on the orders where the email fires 7 times.

      Also, there is evidence from the Follow Up emails plugin reporting system that emails have been fired to the same person for the same order multiple times.

      Thanks for all your help so far – if nothing else I have learnt a lot over the last few days of trawling the net looking for answers :-)

    • Oh and I meant to say – I can set up a system cron no problem. How often should I set them for? Once every 15 minutes or something?

  7. I have done some more digging and testing and I think that maybe the issue is coming from the init hook being called multiple times.

    I set up some code in the themes functions.php as follows:

    add_action('init', 'test_hook');

    function test_hook()
    {

    global $wpdb;
    $message = date("m/d/y H:i:s");;
    $wpdb->insert("pq_logs", array("message"=>$message), array("%s"));

    }

    When this is run, it actually adds more than one entry on each page load…and it seems to be somewhere between 1 and 8 times at random. This obviously means the init process is running more than once for some reason – and I am guessing the woocommerce order complete emails use init in some way.

    The question is – why is init being loaded more than once?

    Thanks

  8. Hmm, I’d definitely try deactivating all your plugins and switching to the 2012 theme and then run that test again. Then, switch back to the theme you’re using, test it, and then turn on the plugins one by one until you find which one is misbehaving. Once you find that, it should be much easier to fix the problem :)

    As for the cron, it depends on the sort of cron events you normally have scheduled. If you were running the Subscriptions plugin, I’d say every 2 minutes or so, but for regular cron stuff, 15 minutes is probably fine.

    • Hi again,

      Thanks for your continued help!

      So should the init hook only ever be called once? Even if going into woocommerce account? Into and out of https and in the back end of wordpress also?

      Cheers

  9. Yes, the init hook should only be called once per page load. However, this also includes AJAX requests, so when in wp-admin it can *appear* to be called multiple times because of the heartbeat script. I took a quick glance at the Linnworks code again and it’s hooking into init so I’d submit a support ticket at http://support.woothemes.com to have the Linnworks developer look at your install to see what’s going on :)

    • Would there be AJAX requests in certain areas of the front-end as well? For example when clicking the “add to cart” button (seems to run twice then)? Or when clicking on the “my account” page in the menu (seems to run 3 times then)? Or maybe even from a slider?

      My test server seems to be displaying different functionality to the live site as well which is bizarre (running the same setup)…but it is difficult to test without taking the live server offline as obviously other people may be requesting pages.

      As far as I can tell, it doesn’t seem to be affected by the Linnworks plugin, so I think maybe the firing of multiple emails is just a side effect of the init error (which seems to be caused by something else).

      The only thing (on the test server) which seems to bring it back to 1 init call per page load is deactivating WooCommerce itself…

      I am literally pulling my hair out now!

      Cheers

  10. Hi again,

    Thanks for all your help – I think I eventually have worked it out (touch wood).

    It seems like it was an error with my child theme and a plugin called Developer Formatter.

    Hopefully it won’t start happening again.

    Cheers,
    Aaron

    • hi there, any reason why it messed up your woocommerce? I am experiencing it right now, order is placed multiple times. but i don’t have the said plugin installed in mine. thank you in advance.

      • Hi,

        I never had orders placed multiple times. Just emails sent multiple times from the site.

        I thought I had fixed it, however it seems I have just made it less severe.

        The emails are still getting fired around 1 to 3 times. As opposed to what it used to be which was around 6 to 8 times.

        Not got a clue what it could be…!!

        Cheers

  11. Hi, thanks for the post.

    One question… what is the “doing_wp_cron”? from where did that came from?

    shouldn’t that be calling “update_db_hourly” in this case?

    thanks

  12. How can you generate output from the events? On my system, output from cron jobs are sent to an email address. I use this to notify me that things got done.

    • Depending on the project, I just open a file such as `log.txt`, write the output, then save the file.

      There are some PHP logging libraries available that could give you more flexibility and options, but that’s what I was going when working on this particular post.

      • Sorry. I should have been more clear. What I meant was how do you generate output and put it on stdout so that cron sees it? Cron automatically sends email for jobs that have output.

  13. All of the above was really useful however another alternative is just to set the cron to load a page of the website every minute. Ensures the WordPress cron gets fired and possibly slightly less work.

    • Well, I think that what Tom meant to do with this solution was to use only manual cron jobs so the server wouldn’t overload. Since you are already setting up a time interval for the events to be fired, it would be a good idea to get rid of the previous ineffective system along the way. But your solution would basically use both (wordpress intended functionality and an actual triggered event based on a time interval), which would seem like overkill to some people.

  14. Thank you for your article. I’m a new player in the game of crons-jobs. I’m receiving 2 emails “Expiring soon and Expired” on the same day the membership expires.

    I have followed your instructions above on setting up a cron job.
    The last instruction given was “Next, add the following line into the cron file:”
    */15 * * * * wget -q -O – http://yourdomain.com/wp-cron.php?doing_wp_cron
    should this code be inserted in wp-cron.php? also is the code inserted as is or are there brackets or semicolon needed

    Thank you for all your help
    Sanford

  15. I’m trying to stop the membership expiring soon and membership expired emails being sent on the same day at the same time. I have completed the other steps. This last one I need help.
    Do I just paste this code into wp-cron.php as is. is there any formatting needed?
    */15 * * * * wget -q -O – http://yourdomain.com/wp-cron.php?doing_wp_cron
    Thank you for your time and labors.

    Sanford Crawford
    Crawford Media

  16. I think, WordPress must use more abstract implementation for the Cron Job. So user can use “concrete” cron that fit with their system. I like how Laravel built their Queue, that basically same concept as Cron in WP.

    • Yeah – WordPress’ cron implementation is pseudo-cron. It basically kicks off whenever the first person loads the site if the specified time interval has passed.

      • Isn’t it also the case that all jobs that are scheduled must be completed before the page renders? I think I read that somewhere, and if that’s true a large job could hold things up a bit.
        Even with using the system cron mechanism as documented here, you still need to be careful with your design. There is no guarantee that your system will be running when a specific cron job needs to be run. For example, I have some jobs that need to run once a month, and it’s a problem if they don’t run. Rather than just running them on the first of the month and hoping they happen, I run them every day, but I record the month/year of the last run in the database. When the job first runs, it checks to see if the current month/year is the same as the last run and only continue if not.

        • Isn’t it also the case that all jobs that are scheduled must be completed before the page renders? I think I read that somewhere, and if that’s true a large job could hold things up a bit.

          Yes – this is something that you’ve gotta be really careful of setting up when scheduling WordPress cron jobs (and why I prefer to use actual cron jobs to trigger page loads).

  17. Great tutorial, however I’m left asking the question – why involve wp-cron at all?
    Sure, its presence will help those who do not have shell access or cannot set up cron jobs from the server, yes. But in this tutorial, you’re setting up a cron to hit wp-cron.php via terminal every 15 minutes which will make sure than an hourly scheduled event will run. Why not just */60 and wget a file that runs update_db_hourly() and be done with it?
    I guess what I’m wondering is, is there some other intrinsic value to using wp-cron? I read that it has a kind of locking system that prevents jobs from running all at once, is this the case? Are there any other benefits?

    • But in this tutorial, you’re setting up a cron to hit wp-cron.php via terminal every 15 minutes which will make sure than an hourly scheduled event will run. Why not just */60 and wget a file that runs update_db_hourly() and be done with it?

      You’re right – no disagreement there. It was just meant to be an example. You can easily knock it up to 60 minutes.

      I guess what I’m wondering is, is there some other intrinsic value to using wp-cron? I read that it has a kind of locking system that prevents jobs from running all at once, is this the case? Are there any other benefits?

      Personally, I don’t use wp-cron that much. The only time I use it if it’s a site that has relatively frequent visits and only has small jobs to complete; otherwise, I stick with normal cron jobs.

  18. Hello, this seems like a great reference for creating a cron job. Sorta new to WordPress, but not new to Web Development. I’ve got Step 1 understood and done, but looking at Step 2 (Setup Your Event Code), you really don’t explain where the add_action is supposed to go? Like, what file should the add_action go into? I don’t want this to be theme specific, since this will need to run every x minutes no matter what theme is selected. Can this be placed into wp-includes/functions.php in that case?? Will it work globally in that case?

    Thanks

    • Normally, add_action is placed within functions.php or within a plugin file somewhere.

      If you don’t want it to be theme specific, then it should not be placed in functions.php as functions.php is theme specific.

      To that end, I’d say go the plugin route so that it can be used throughout any theme. I hope this helps!

  19. Hey Tom,

    I’m having trouble getting the wp_schedule_event to fire when placed in the Activation hook, as soon as I move it out of there if works fine. I’m guessing it has something to do with not being able to access the add_action hook from inside a static method?

    Regards.

  20. Tom, I learned some things about Cron in reading this article, but this brought forth more questions and concerns. I have a cron job based off of your article and it basically extracts instagram posts (using Instagram API) and puts them into a custom post type as a WordPress post. I have my code here and was hoping you could help me… The issue is that I am getting duplicate even quadruple copies of the same post! I have since disabled the cron as per your article and this seems to fix the issue, but now the cron won’t run haha

    http://wordpress.stackexchange.com/questions/154810/prevent-duplicate-instagram-posts-using-instagram-api

    • I think you first need to determine whether or not the cron job is running multiple times each period . You have logging, so that should tell you right away if that’s happening.

      Do you have code in your addin that makes sure it only gets run as part of the cron job? Is it possible that it’s getting run again as a result of creating a post? The code you presented is out of context – is it inside on an event handler that you registered as part of an addin, or is it inline so that it’s getting loaded on every page load?

      I’m not an expert on debugging WordPress pages, so I depend a lot on log messages. If I was debugging this, I’d start by adding a lot more logging to see what’s going on.

      • Yes, the issue is that there are multiple cron jobs running the same thing, so even though I have checks for existing posts, if two or three cron jobs are executing same time, the checks are ignored, if that makes sense. For example, a log might look like:

        [2014-07-18 14:51:35 127.0.0.1 /wp-cron.php?doing_wp_cron=1405695095.1544818878173828125000] Creating Post Content… Half a dozen left! #jimnnicks #birmingham #cheesebiscuits #yum

        • Log#2:

          [2014-07-18 14:51:35 127.0.0.1 /wp-cron.php?doing_wp_cron=1405695095.1544818878173828125000] Inserted Post ID 38983 Insta_ID: 751700863055714021_347524756
          [2014-07-18 14:53:03 127.0.0.1 /wp-cron.php?doing_wp_cron=1405695183.4361529350280761718750] Creating Post Content… Half a dozen left! #jimnnicks #birmingham #cheesebiscuits #yum

        • Are you sure it’s actually that multiple cron jobs are running? That is, could this be caused by your code just getting run on a page as a result of your adding posts?
          I suggest trying to isolate this by just having the event log a message and not do any of the other stuff.

  21. My website is loading slow on mobile devices which is causing a higher bounce rate. When I deactivated the plug in that is causing this I get an error message:

    Warning Illegal offset in wp_includes cron.php file on line 180 …..

    This is what is on line 180 – “if ( isset( $cron[ $hook ][ $key ] ) ) {“

    Any suggestions??

  22. Hello!
    very good tutorial, clearly explained and detailed!
    but I still have a doubt…
    Considering that I need to set up a cron job to be used in a plugin that I’d like to share, I’d need that when installing the plugin, the cron job is set up automatically.
    so I can disable wp_cron, define the function and set up everything hooking the plugin activation event. but is it possible to add the cron rule line automatically on plugin activation or that will always need to be done manually?

    thanx!

  23. It’s not possible, but I don’t think it’s what you want to do.
    Your plugin should not care how the event is being invoked. If the person running the site wants to disable wp_cron and use Linux cron, they can, but if they want to use the standard WordPress event handler, that should still work.

    • thanx for your reply!
      so if I want to add a cron-job to my plugin (which needs to be shared) the only thing I can do is using the default wp_cron to schedule the event I need, even if is not a real cron-job, and then maybe just add a mini tutorial to tell the people how to set up a real cron-job and use that one in the plugin rather than the default.
      is this what you mean?

      cheers!

  24. Hi,

    I have installed “Newsletter ” plugin. i have configured cron job but it showing me error-

    ” The cron system seems not running correctly. See this page for more information. ”

    But Cron running on server

    Any solutions ?

  25. Thank you very much!
    This is a very good tutorial.

  26. on cpanel linux hosting(shared and vps) with ssl enabled (https://)
    following cron jobs command worked for me
    /usr/bin/curl -k https://www.yourdomain.com/test.php
    otherwise ssl was interfering to do cronjob its work.

  27. Very nice article.

    I just found your article suddenly when I was searching for how to use a cron job with wordpress,

    actually what I am trying to do is to check all the users (contributors) on the website that has no post published yet, and send them a notification email to remind them that they have to post!!!!

    Actually I don’t know how to code this yet, but I am trying to imagine how the scenario will be, and the first step is to run a php code in a realtime loop of work without any user’s interaction to fire the code. So, I think that (wp_schedule_event) should help me out with what I am going to do.

    CORRECT ME IF I AM WRONG!!??

    Thank you.

    Best,

    EF.

    • The pseudo-code for doing something like this would be:

      - Load all contributors
      - For each contributor, check to see if their post count if 0
      - If there post count is 0, send the email
      

      To setup a scheduled even to run, say, every 24 hours then you’d use something like this:

      wp_schedule_event( current_time( 'timestamp' ), 'daily', 'your_function_name' );

      Hope this helps.

      • Great…

        I was trying to test the cron job on my server (MediaTemple) and here is what I exactly did by following your steps:

        /////////////////////////////////////////////////////////////

        (Disabled WP Cron in “wp-config.php”)

        define(‘DISABLE_WP_CRON’, true);

        /////////////////////////////////////////////////////////////

        (Added the below code to “functions.php” in my theme)

        add_action( ‘my_hourly_event’, ‘update_db_hourly’ );

        class Foo {

        public static function activate() {

        wp_schedule_event( time(), ‘hourly’, ‘my_hourly_event’ );

        }

        public static function deactivate() {

        wp_clear_scheduled_hook('my_hourly_event');

        }

        public function update_db_hourly() {

        $to = 'me@efoula.com';
        $subject = 'Cron Jobs - MediaTemple Test';
        $message = '&lt;html lang="HE"&gt;&lt;head&gt;&lt;title&gt;&lt;/title&gt;&lt;/head&gt;&lt;body&gt;Cron Jobs MediaTemple Test Hourly&lt;/body&gt;&lt;/html&gt;';
        $headers[] = 'MIME-Version: 1.0' . "\r\n";
        $headers[] = 'Content-type: text/html; charset=UTF-8' . "\r\n";
        $headers[] = "X-Mailer: PHP \r\n";
        wp_mail( $to, $subject, $message, $headers );

        }

        }

        /////////////////////////////////////////////////////////////

        ( Added the below line of code to the cron job terminal on MediaTemple)

        /15 * * * wget -q -O – http://mydomain.com/wp-cron.php?doing_wp_cron

        /////////////////////////////////////////////////////////////

        but MediaTemple send me an email notification including an error msg for the cron job task

        (sh: /15: No such file or directory)

        what I am missing here !!??

        Thank you for your time.

  28. Sorry I made a stupid thing, and I have fixed it. Thank you.

    By the way, MediaTemple Cron Job command for wordpress is:

    curl -s http://domainname.com/wp-cron.php > /dev/null

  29. Cáspitas! Así se agradecen ver las cosas, gracias!

  30. Will it make any difference to the operation of the command if we use:

    wp-cron.php

    instead of the full:

    wp-cron.php?doing_wp_cron

    What does the ?doing_wp_cron at the end change?

    Thanks

    • ?doing_wp_cron indicates that you have ALTERNATE_WP_CRON setup in your wp-config.php file.

      Why it’s setup like that depends on who’s managing your install or what plugin wrote that line to the file (if one, in fact, did).

      If you remove the query string parameter, then it could prevent any of the scheduled jobs (whatever they may be) from properly running.

  31. We do not have ALTERNATE_WP_CRON set in the config file?

    So if we setup a cron job under apache/plesk using the scheduled tasks functionality do we use:

    cd /var/www/vhosts/mywebsite.com/httpdocs; /usr/bin/php wp-cron.php?doing_wp_cron

    or

    cd /var/www/vhosts/mywebsite.com/httpdocs; /usr/bin/php wp-cron.php

    • The lines of code that you’re mentioning above are calling wp-cron.php which is fine, but do you have any cron jobs defined?

      For example, something like this:

      /15 * * * wget -q -O – http://yourdomain.com/wp-cron.php?doing_wp_cron

      That’s how a cron job is defined – it’s get an interval, the program to call to the URL of the site, and then to call the wp-cron.php script with the proper query string variable to indicate that scheduled jobs should fire.

  32. yes it is like this

    */10 * * * * cd /var/www/vhosts/mywebsite.com/httpdocs; /usr/bin/php wp-cron.php

    my question is really whether I need to add ?doing_wp_cron to the end or not? And if yes, then why?

    • This will depend on your host. Sometimes, hosts disable certain things (like loopbacks) and so you have to define that query string parameter.

      If it works without it, then you’re fine; otherwise, use it and it should resolve the problem.

      • Hi Tom,

        I think not having the ?doing_wp_cron flag was causing the follow up emails plugin to not fire any emails.

        You know the DISABLE_WP_CRON option in config? What does that actually disable?

        i.e. if you left that on, what would it actually be doing in the background that we need to replace?

        Thanks

        •  I think not having the ?doing_wp_cron flag was causing the follow up emails plugin to not fire any emails.

          Perhaps – it depends on the cron configuration of your WordPress installation. See below:

           You know the DISABLE_WP_CRON option in config? What does that actually disable?

          If you disable that constant, then it disables WordPress’ check to see of a job needs to be run. The check runs on each page load (and it’s cheap, so it’s not like it’s hogging a lot of memory). 

          If you don’t disable it, then the check will occur and any outstanding jobs will fire.

          • Are you sure that your command is really working at all? I’m still surprised that your cron job is working without running under a web server.

            • @David – what do you mean without it running under a web server? I have a Linux box running Apache, so it is under a web server AFAIK

              • Running the command line

                cd /var/www/vhosts/mywebsite.com/httpdocs; /usr/bin/php wp-cron.php

                is not running the command under a web server. It’s just running it under the shell. When you use wget to call up the page, it runs it under the already-running server.

                • Why would that make a difference? Surely it is doing the exact same thing?

                  BTW, I’m not saying you are wrong, I’m just trying to learn :-)

                  Thanks

                  • Let me do some research.

                  • With other web applications (like a .NET application), the application is loaded either at startup or at the first request of a page that uses the application. This allows the application to load up everything it needs and get subsystems (login, database, etc.) up and running. Then, when a page is loaded, only the things not already loaded need to be loaded.

                    I remember trying to run a PHP file directly, and that didn’t work at all, even when I included the WP files I was referencing.

                    I assume that you’ve run this under a command line (e.g., bash) and it works fine. Correct?

                    • I think I tested it yeah, but can’t remember now of the top of my head.

                      What is the best way to test it is working correctly from the command line?

                    • I would ssh to the server host and then just run the command from the command line. Of course, this assumes that your host has ssh and is set up for you to use it.

                    • Yes I have a managed VPS so can access however I like :-)

                      The main thing I wondered was – what command do I run and how can I tell if it’s been successful?

                      Thanks

                    • This is getting too indented. I’ll add the info at the bottom.

          • What I meant was, what is it actually doing in the background if you have it as the default, not disabled?

            Is it just calling the page http://www.mysite.com/wp-cron.php or is it doing something completely different to that?

            What I’m trying to work out is how to replicate this with manual cron jobs without breaking things like follow up emails.

            Because at the moment follow up emails works with DISABLE_WP_CRON set to true, but not with it turned off.

            I want to replicate the default activity, but without doing it on every page load (I.e using proper cron jobs)

            Thanks

  33. Aha, I see. It works fine without because I am not using wget, and I am on a VPS which I manage myself.

    So shouldn’t need the query string?

  34. I can’t guarantee it, but if you’re managing it completely on your own, then you should be good to go.

  35. Hi Tom,

    Is there any reason to use wget instead of calling the file directly from the command line?

    Something like:

    php -f /var/www/example.com/wp-cron.php

  36. Aaron, cron just runs command lines, so in your case the command would be:

    cd /var/www/vhosts/mywebsite.com/httpdocs; /usr/bin/php wp-cron.php

    I don’t know if the output will go to your shell window or if it will go into the php log for the system.

  37. Hi Tom,

    I read your blog it is good.but I dont know where to add code(2. Define The Function) ?

  38. Hi Tom, I am very new to cron jobs – and I’m not able to find anywhere exactly how to create a new cron job. Specifically, I just want to paste a new command for Wishlist Member into a cron job. Where in WordPress is this cron job? Or do I need a plugin?? Thanks so much for your help!

    • This is a great question!

      Unfortunately, I’m only able to help in a limited capacity – to setup a true cron job, you’ll need to do so in the control panel of your website which actually varies from host-to-host.

      To define one within WordPress (which is more of a pseudo-cron-job), you’d need someone who’s capable of writing code in order to define it (and they’d need some more information about your configuration with WishList Member, as well).

      I hope this helps!

  39. Hi Tom,

    I’m a little confused about the best way to config a cron tab. I’ve tried several combinations but I’m not really sure what is the best.

    The most common recomendations is like yours:

    wget http://yourdomain.com/wp-cron.php?doing_wp_cron

    Others said that it is better to pass current date to doing_wp_cron flag, just like WordPress does in the core (they said):

    wget "http://yourdomain.com/wp-cron.php?doing_wp_cron=`date +\%s.\%N`"

    And others said that it is better to use php command:

    cd /home/user/public_html/; php -f wp-cron.php

    Using each one is causing some problems. Using php command and doing_wp_cron without any value, I get several notices from the server regarding long time running proccesses. Using doing_wp_cron=date +\%s.\%N I don’t get that notices but the server is consuming notably higher CPU in daily average % that the other options.

    What is the best option from your point of view? What is the real difference between those options?

    I’m thinking to run the php command and us define(‘WP_CRON_LOCK_TIMEOUT’,60);.

    Thank you very much!!

  40. Hi Tom,

    wget is making often trouble in conjunction with cron. One of the most common is that there is need to define the full path to wget in the cron table because wget is often not available from the cron home folder

    More reliable and easy to use is curl instead of wget:

    curl –silent “site.com/wp-cron.php”

    • Thanks for the tip, Rene. Personally, I’ve never had a problem with wget but I also tightly control the environment in which I work. Knowing this is helpful especially if we don’t have that kind of control over the environment in which our code is running.

  41. if I enter http://localhost/wp-cron.php?doing_wp_cron in the address bar (for debuggin purpose), I only get “invalid secret string”. Worpresd 4.5 here.

  42. What about letting some online service check your site every 5 minutes or so? statuscake.com i.e. has a free membership option. So even peeps without webserver can have “real” cronjobs. ;)

    • If the site is part of an intranet, you can’t really use that.

      And it’s not that I think what you’re proposing is a bad idea, but it seems like an odd dependency when I could use a standard *nix cron job to do it.

      The other thing is that I think the idea of using a third-party service like this would depend on how simple (or not) the site is.

    • There is no way I would trust an outside service for this kind of thing for anything real. It’s too common for things like this to shut down without any notice, and then you’re left scrambling for a new solution. It’s bad enough when WordPress developers stop supporting their plugin and it eventually breaks.

  43. The crontab line is missing a leading asterisk. It should be:

    */15 * * * * wget -q -O – http://yourdomain.com/wp-cron.php?doing_wp_cron

    And if you don’t want to save the output:

    */15 * * * * wget -q -O – http://yourdomain.com/wp-cron.php?doing_wp_cron >/dev/null 2>&1

  44. Are wordpress cron functions triggered if a user goes straight to a file url on your site?

    Let’s say I want to automatically delete files uploaded by users after at least an hours after being uploaded, this task does not need to be time specific, after the hour is up, it just needs to be performed when a user comes on the site so that nobody can access this public file. This being said, I need to know if entering a file url bypasses the trigger of a cron job

    • The cron functions are triggered when the WordPress application loads so if they hit a page, post, or anything on your site, it’ll work.

      Hitting a file that’s just located in the wp-content directory or that’s part of the WordPress installation isn’t likely to do it.

      Hope this helps!

  45. if i plan to bundle the cron jobs functionality into a plugin where i don’t have to access the command line to configure using wget. whats the procedure to do so.

    Because if you are building a commercial product , you won’t have access to their terminal or if you do so, start configuring for all of them say you have a 1000 sales .

    • if i plan to bundle the cron jobs functionality into a plugin where i don’t have to access the command line to configure using wget. whats the procedure to do so.

      One option is to setup a script that runs independently of WordPress on the server (and across the array of servers) that uses proper cron jobs. It may not be something you have access to all the time, but it’s something you’re going to need to handle in some way.

      If you opt to use WordPress, you will be using a faux cron job. That’s not necessarily a bad thing, but it can impact the first person to trigger it if they are the first person to land on it. You could, however, set this up as an Ajax call using the REST API (or the older admin-ajax.php functionality if the REST API isn’t supported by whatever version of WordPress you’re using).

  46. Tom, your article it’s great. Let me ask you something. Please, sorry about my english.

    1 – The check for upgrades (WordPress, plugins and themes) will not be affected by the disabled WP Cron System?

    2 – There’s a way to disable the WP Cron System on my theme or plugin? I’m thinking if it’s possible to avoid the file wp-config.php.

    3 – Let’s say that I have a scheduled post to a certain day and hour. The scheduling of the post doesn’t mean that the post it’ll be really posted on the given moment, but it’ll be available after that. So, WP Cron manage this turning the post available after a website’s load. That’s the default of WordPress.

    But let’s say that I have a task to be made hourly (send a message with WordPress content). My cron job (server side) will trigger wp-cron.php every 15 minutes and consequently check/trigger the execution of the task. It’s no clear to me, but the cron’s interval will not affect the effectiveness of the scheduled task?

    Thanks in advance. Cheers from Brazil ;)

    • 1 – The check for upgrades (WordPress, plugins and themes) will not be affected by the disabled WP Cron System?

      It shouldn’t be.

      2 – There’s a way to disable the WP Cron System on my theme or plugin? I’m thinking if it’s possible to avoid the file wp-config.php

      This article provides some good information about this, but it’s something that I’d be very careful doing if you’re looking to distribute this widely.

      3 – Let’s say that I have a scheduled post to a certain day and hour. The scheduling of the post doesn’t mean that the post it’ll be really posted on the given moment, but it’ll be available after that. So, WP Cron manage this turning the post available after a website’s load. That’s the default of WordPress.

      Correct.

      It’s no clear to me, but the cron’s interval will not affect the effectiveness of the scheduled task?

      If I understand you correctly: Having a real cron job hit your site will cause all scheduled tasks to fire as planned.

      I hope this helps! And you’re English is great! :)

  47. How would I setup a wordpress Cronjob to turn on certain wordpress plugins at certain times of the day and then turn them off at certain times of the day

    Chris

    • The first thing to note is that WordPress cron jobs aren’t real cron jobs. They are faux such that if a job hasn’t fired since a person hits the site, then it will fire.

      You may be better off using a real cron job on your server.

      Secondly, this all depends on the plugin’s name and location. For starts, I’d recommend taking a look at activate_plugin and then go from there.

  48. I hadn’t thought of using containers but that’s a great idea. Thanks so much for sharing!

Leave a Reply