WordPress is a fantastic open source Content Management System. However there are some elements of WordPress that aren’t as efficient as they should be. One of these elements is the wp-cron.php file.

What is wp-cron.php?

wp-cron.php is WordPress’ automated task scheduler. It’s a ‘virtual’ cron job that checks whether there are any activities that need to be done on WordPress. Things like scheduled posts, cache synchronisation, CDN pushes and database backups are all scheduled by wp-cron.php. Plugins are also able to add scheduled tasks into the cron list. (For background, cron is a Unix time-based scheduling tool. See http://en.wikipedia.org/wiki/Cron)

By default, wp-cron.php runs every time WordPress loads a page – both internal admin pages and public site visitors. This is obviously not ideal. It’s normally pretty fast to execute wp-cron.php, but…

  • If you have a lot of traffic to your site then this means that wp-cron.php is running more than it really needs to.
  • If you have irregular, or limited traffic to your site, then scheduled jobs may not run when expected.
  • When you are using an EC2 micro instance, like I am, then resources are at a premium and you want to minimise wasted resources.
  • When spiders or bots trawl your site they will initiate unnecessary wp-cron.php tasks.

This is why I call it a ‘virtual’ cron job – as it’s not really time based – it’s using site visits as a proxy for time based events.

How to make wp-cron.php into a real cron job?

So – what should you do? My view is that you should convert wp-cron.php into a ‘real’ cron job that uses the Unix cron daemon to fire wp-cron.php in a time based manner. Eg. Maybe every 10-15 minutes? This is probably frequent enough without creating unnecessary overhead. Obviously this depends on how strictly you want time based events to run on your site.

Here’s how to do it.

  1. Disable the wp-cron.php in the WordPress config file.
    It’s fairly simple to disableWordpress from running wp-cron.php on each site visit. You simply need to add a line into yourwp-config.php file. I don’t think it matters where you add this line but I’ve put it near the top of the wp-config file. (Nb: You don’t do this in the wp-cron.php file rather the wp-config.php file.)

    define('DISABLE_WP_CRON', true);
  2. Check that wp-cron.php is disabled by scheduling a post and confirming that the post doesn’t publish. If wp-cron.php has been disabled properly then you will see a message that the post has Missed Schedule in the ‘All Posts’ page after the scheduled time has passed.
  3. Manually trigger the wp-cron.php job to see that it still works. You can do this by entering the URL for the wp-cron.php file. For my site it is
    www.stevenhallam.com/wp-cron.php?doing_wp_cron
  4. Insert a new Unixcron system task that will trigger the wp-cron.php file. This is the most complex part of the process and took me a while to get the trigger working properly. You need to understand a bit about how cron works across system & user tasks to get it working properly.
    1. If you have cPanel for your hosting platform, you can use the cPanel dashboard to insert the cron task.
    2. If you are using EC2 (like I am), the you can create a batch file in the cron.d directory or edit the system crontab file.
  5. There are two methods to trigger wp-cron.php. I found it simpler to run the PHP file directly rather than use a wget to run the file on your webserver.
    The first part of both of these methods is thecron shorthand for how often the command runs by editing the batch file from above. I’m runningcron as a system task, rather than as a user task,  so you also need to specify which user to run thecron task.

    # * * * * *  command to execute
    # ┬ ┬ ┬ ┬ ┬
    # │ │ │ │ │
    # │ │ │ │ │
    # │ │ │ │ └───── day of week (0 - 6) (0 to 6 are Sunday to Saturday, or use names; 7 is Sunday, the same as 0)
    # │ │ │ └────────── month (1 - 12)
    # │ │ └─────────────── day of month (1 - 31)
    # │ └──────────────────── hour (0 - 23)
    # └───────────────────────── min (0 - 59)
    
    1. PHP method
      */15 * * * * ec2-user php /var/www/html/wp-cron.php

      Just update the location of your WordPress files. Mine are under /var/www/html

    2. WGET method
      */15 * * * * ec2-user wget -q -O - http://ec2-52-62-235-187.ap-southeast-2.compute.amazonaws.com/wp-cron.php?doing_wp_cron >/dev/null 2>&1

      The second part of the wget line suppresses the return values of the wp-cron.php from your logs.

  6. Check that the unix cron task is working correctly by scheduling a post and see if the post is published as expected. This will obviously depend on the frequency that you set for the cron task.

That’s it. This will smooth out your wp-cron.php tasks into a more consistent, time based manner. It has stopped a lot of CPU spikes on my site as well.

Resources

Here are some good resources on how wp-cron and cron.

  1. Should you be making the exact URL and key of your cron job public if it causes load on your server? This could be used as a method to DoS the site by repeatedly requesting that page with a tool like ab or siege. An alternate method would be to block the wp-cron.php path at Varnish/.htaccess and then continue to use your local php execution method.

Leave a Reply