Here’s how I recently got Linux Cron to drive wp-cron.php file on one of my WordPress sites. This was an utter nightmare! But it now works (for me). Please be aware these are my notes. They are basically a reminder for me as to what I did. But if you are struggling and they help you then that’s great.
Be aware they may/may not give the optimum setup. All I know is that for some god-forsaken reason(s) this was unreasonably painful. I really do not know why this more-or-less trivial Linux/php setup caused me so much grief. But I don’t intend revisiting it to refine it or find out. Here’s what I did:
Background
WordPress uses (by default) a built-in pseudo cron system that relies on people visiting your site in order to operate. This has two distinct disadvantages.
- If you site gets few visitors then cron jobs are run rarely. This can be a problem in flagging up (for example) updates.
- If your site gets many visitors the cron jobs are run too often. You are continually looking for updates this can slow your site load time down.
If you control the server, or at least have access to cron then you can get round this by disabling the pseudo cron and using the system cron to fire off cron events to your WordPress site.
The Fix: Getting Linux Cron to drive wp_cron.php
This is for a site I have (not this one) which is on it’s own Apache2 server. So the changes in this case involve using the Linux crontab. If you are using shared hosting the setup is more-or-less the same, just use the cron facility in cpanel (assuming your host provides cpanels).
The first thing you need to do is disable the on-board pseudo cron. Do this by adding this line in file wp-config.php in your WordPress directory.
define('DISABLE_WP_CRON', true);
Now after you restart Apache2 with..
sudo service apache2 restart
wp-cron.php is now no longer being run using the inbuilt pseudo cron.
Now we need to set up a crontab for the owner of wp-cron.php and run it from there
Under Ubuntu the usual owner of the files that make up a wordpress install in /var/www has the name of www-data. This user is usually created when you install apache2.
www-data is a headless user with no shell or home directory. It’s done like that to make things a little more secure and difficult for anyone trying to hack your system.
You can change this default name by modifying fields APACHE_RUN_USER and APACHE_RUN_GROUP in file /etc/apache2/envvars
if you want to. But I’ll continue using it here for clarity.
You create a crontab for www-data with
sudo -u www-data crontab -e
This drops you into an edit session using nano. There is a red warning stating that there are problems with the history file. Which is unsurprising as there isn’t one. www-data has no shell or home directory. So there is nowhere for user www-data to put one. Never mind. Ignore it
To get linux cron to drive wp-cron.php every (say) 15 minutes add this line in the nano editor
0/15 * * * * cd /var/www/<path to wordpress files>; usr/bin/php /var/www/<path to wordpress files>/wp-cron.php >>/<path to file writeable by www-data> 2>&1
You almost certainly do not need the path change (i.e. cd command) but as I said, it works for me. I also fully pathed php as I have assumed that www-data will not know where it is otherwise. But I don’t know that for certain. It works. I’ve had enough with tinkering with it. The other thing you need to ensure is that you have actually make <path to file writeable by www-data> actually writeable by www-data.
Save and exit nano. Nano seeks your permission to store the file in a temporary directory which it may do. But I also <believe> the system cron saves it away as well. Whatever. It works.
Notice I’m using php not wp-cli. That is because for some god-forsaken reason I could not get wp-cli to issue the command to run wp-cron.php from within the crontab. It worked perfectly outside of crontab. But not within it. I don’t know what I was doing wrong. Now I am past caring.
Also, you’ll no doubt notice that my php invocation of wp-cron.php is different to just about every other one I have seen relating to this issue on Google. Mostly other solutions I’ve seen which get Linux Cron to drive wp-cron.php add a parameter to the end of the wp-cron.php. Something like this:
/usr/bin/php wp-cron.php?doing-cron.
Why? (i.e. why the ?doing-cron bit ?)
Having the parameter did not work for me. So I ditched the parameter (i.e. i.e. the ?doing-cron bit.) . Then it worked.
I have no idea why that parameter was there in the first place. But I (initially) slavishly followed what I read. Only when it bit me did I remove it.
So (hopefully) wp-cron.php is now being run from crontab. But how do you know it’s working? More to the point how will you know in (say) two weeks time that it hasn’t fallen over for some reason?
Solution: You get it to send you an email once in a while just to show it is still running.
You need to add some simple code to your functions.php file in the root of your active theme. This also caused me much grief and suffering. Again, it is a trivial modification! And to a file I have added lots to in the past with little problem. Maybe I was just having a bad day.
This is what I added:
//-----------------------------------------------------------------
// Trigger cron from linux rather than use the
// sub-optimal wordpress trigger
//-----------------------------------------------------------------
add_filter('cron_schedules', 'thisfunctionname');
function thisfunctionname ($schedules )
{
/*$schedules['every_hours'] = array(
'interval' => 3600, //in seconds
'display' =>__('Every hours' ),
);*/
$schedules['2_minutes'] = array( 'interval'=> 120, 'display' => __('2_minutes' ),);
/*$schedules['60_minutes'] = array( 'interval'=> 3600, 'display' => __('60_minutes' ),);
$schedules['4_minutes'] = array( 'interval'=> 240, 'display' => __('4_minutes' ),);*/
return $schedules;
}
add_action( 'wp', 'custom_cron_job' );
function custom_cron_job()
{
if ( !wp_next_scheduled( 'send_this_email' ))
{
wp_schedule_event(time(), '2_minutes', 'send_this_email' );
/*wp_schedule_event(time(), '60_minutes', 'send_this_email' );*/
/*wp_schedule_event(time(), '4_minutes', 'send_this_email' );*/
/*wp_schedule_event(time(), 'every_hours', 'send_this_email' );*/
}
}
add_action( 'send_this_email', 'generate_this_email');
function generate_this_email()
{
$email_subject = "Test 2min subject";
$email_content = "This is the 2m test";
wp_mail( 'your-email-address', $email_subject, $email_content);
}
And that’s it. That’s what I did to get Linux cron to drive wp-cron.php. It will in turn generate an email to the specified email address at whatever time period you choose – (above settings it is just for testing – I’ve left some commented out alternatives). Obviously, do not forget to put your email address in the last line.
If you stop getting emails when you expect them – there is something wrong.
Now I’m going to have a beer (or three).
The rest of my Linux-ish posts are catalogued Here