Jan 29
Run WordPress tasks from real cron job
I had to pull off my sleeves, open WP code and see by myself because all I finally found was this article (well I must admit that it was very helpful):
http://wordpress.org/support/topic/273381
To explain, in short, how WordPress crons are working, here is a shortened call stack:
- Web User Request
- => WP API initialisation
- ==> wp_cron() // if authorized to run, the cron array is loaded (from a get_option call)
- ===> spawn_cron() // this is called if a job pending execution is found in the cron array.
- ====> wp_remote_post(‘wp-cron.php?doing_wp_cron’) // the asynchronous call
wp_cron() is the function that initiate the process of executing the jobs if one needs to be executed. And wp-cron.php is the one that will, at the end, execute those jobs.
In order to run the jobs from a real cron, it is simple as scheduling a wget call to wp-cron.php and disabling PHP calls to wp_cron() function. Damn, if I knew that from beginning… When you open the wp_cron() function declaration, you will notice that first line checks for a constant definition: DISABLE_WP_CRON. So you define(‘DISABLE_WP_CRON’, true) in your wp-config.php and that’s it.
Well, if you are using WordPress MU, that’s not totally it. Remember the comments in the stack call above? The cron array is loaded from a function call to get_option. In WordPress MU, get_option reads data from wp_xx_options which is per blog database table. So it has a set of scheduled tasks per blog. So you need to call wp-cron.php in the context of each blog. So it’s starting to bug me… I don’t want to do maintenance tasks everytime a blog is created in WordPress MU! To prevent this, I created a small php script that I called wp-cron-multi-blog.php that is calling wp-cron.php for each active blogs defined in WordPress MU.
Here is a wrap-up of the information without the bells and whistles. To run WP tasks from a real scheduled cron you should do this:
in wp-config.php, add the following line :
define('DISABLE_WP_CRON', true);
for a standard WordPress installation, configure a crontab that:
wget http://www.server.com/wp-cron.php?doing_wp_cron
for a WordPress MU installation, configure a crontab per blog like:
wget http://www.server.com/wp-cron.php?doing_wp_cronwget http://www.server.com/whatever/wp-cron.php?doing_wp_cronwget http://www.server.com/what-a-blogger/wp-cron.php?doing_wp_cron...
or, a single crontab calling my wp-cron-multi-blog.php (placed in root installation of WP):
wget http://www.server.com/wp-cron-multi-blog.php
A final note about wp-cron-multi-blog.php. If your WordPress MU installation has a lot of blogs and each of them tends to have many time consuming tasks (ex: cache cleaning), it may be a good idea to edit this script in order to limit the number of blogs to run for at one time.
Hope this helps.
Pascal.
Pages: 1 2
30 comments
I implemented this in WPMU 2.9.1.1 with the wp-cron-multi-blog.php script and a /etc/crontab setup and it does not work at all for me. If I manually browse to the script, it reports back as if its working/doing something, but doesn’t appear to actually spawn the cron jobs.
Ok I will double-check it in case I did a copy/paste mistake.
What are your cron jobs skipped? pre-publishing?
Pascal.
Thank you for this post. It helped me alot
You can probably make your script more efficient by managing the list of scheduled task, or the blog which has them, in a separate DB table.
Another enhancement might be to directly call the WP cron task execution API, after calling switch_to_blog for the appropriate blog number.
How often do you run this crontab? Every minute? Every hour? If you turn it of on a standard wp-mu instance.. What will stop working? Only posting set to be published in the future?
Hi,
I run it every 30 minutes. From what I have seen, it is used for publishing in future and cache clean-up. So the good answer is it depends…
It depends on the plugins you are using. Some plugins (like caching) sets scheduled tasks. So based on your plugins and the latency (for publishing future posts for example) you are willing to accept, you should set the longest period as possible. It is possible to run it every minutes as long as it doesn’t run over 1 minute. Otherwise it may overlap and start overloading your server.
Pascal.
Hi,
Can anyone suggest that how can I stop the execution of a cron through page load for a particular plugin not for whole wordpress.
Actually, I want to run cron script through cron job.
I would appreciate your suggestion.
Thanks for writing this. The line which disables wp-cron looks like its doing wonders for my sites, at least for now..
[...] here: Pascal’s blog » Run WordPress tasks from real cron job » page 2 Tags: [...]
Thanks for this good post!
I’ve searched long to get this information.
But I’m wondering why the cronjob isn’t directly triggered like this:
/path/to/php/cli/cli/php -f /path/to/wordpress/wp-cron.php
in my php experince I always call cron jobs like this – i use wordpress since three months and haven’t found no page or post where this practice is used?
Hi,
For a standard WordPress installation, you are right. And I would prefer that way instead of the wget method. But for a WordPress MU installation, that’s different because the API determine the current blog context based on the URI, so it cannot run from command line PHP.
Pascal.
[...] the original here: Pascal’s blog » Run WordPress tasks from real cron job Tags: disable-wp-cron, good-explanation, [...]
Thanks for this. I spent days looking for a solution for every minute cron run.
Well I use WPMU so also the php command didn’t work. I didn’t know I must use the wget command.
Bravo!
Thank you, thank you, thank you. Switched to a standard cron job and my scheduled posts and all the other stuff is now working beautifully… saved me a big headache!
Change wp_remote_post line to:
switch_to_blog($blog->blog_id);
wp_cron();
restore_current_blog();
Will run much faster.
I will definitly take a look at this switch_to_blog function and update my post accordingly.
Thanks!
Pascal.
I just upgraded to WP 3.0 and am having issues with the wp-cron.php spiking my vps. I am looking at solutions like yours but wondering about the new multisite function in WP.
Will this need to be run like the MU example, and what difference in setup with sub-domain or sub-directory.
Thanks,
Len
I haven’t try WordPress 3.0 yet but I guess it would be like WordPress MU.
Also consider doing the change stated by Jason Potkanski above.
Pascal.
Pascal:
I tried your fix however when I put in line of code
define(‘DISABLE_WP_CRON’, true);
I get blank page on my wp admin panel that states “syntax error line 1″ which causes me to have to go back into wp-config.php file and delete that line of code. As a result I am unable to disable the wp-cron….Any other suggestions on how I can make this work?
Thanks,
Rick
Looks like you are breaking the PHP code.
Syntax error on line 1… hum did you put the define before the “
Pascal.
@Rick : be aware if you copied the DEFINE from here, the quotes getting copied are not the ones PHP like. You have to manually edit them (I’m talking about the single charachters preceding and after DISABLE_WP_CRON)
I’m not sure how relevant this is with WP3.0
w3 total cache is what’s killing my cpu with this internal wp-cron.php garbage.
One of my sites (www.supercars-for-sale.com) is on a free hosting account.
It kept getting suspended due to excessive resource use. (Feedwordpress plugin on wordpress..)
I’ve switched fwp to manual/cron option, AND used the disable_wp_cron setting. If it stays up 24 hours I’m going to look at implementing a Non-MU version of your script. (I’ve already written it.).
I’ll let you know what happens..
I’ve successfully implemented this on one of my sites, however it is leaving a load of zero byte files in my root folder. Is there anything I can add after the wget command so that the zero byte files are not saved. If there is anything in the files, then I would need to see that for debugging purposes.
Thanks for the useful post.
I’ve worked it out! I should have looked at the manual for wget, but anyway… Here is what I have:
wget http://www.domain.com/wp-cron.php?doing_wp_cron –output-document=cron.txt
Hope someone finds it useful.
@Joe Brewer
Just add this:
wget http://domain.tld/wp-cron-multi-blog.php > /dev/null 2>&1
For the /dev/null 2>&1 part:
If one run a cron job, any output that the script would send to stderr is sent as a mail to the owner of the script, which can be a tad annoying if the script runs regularily, with output you don’t need or want, or can do anything about.
The graceful way to handle this in any shell is as follows: Redirect the output of stderr to stdout, and then redirect this combined output to /dev/null
Simple but brilliant. Thank you. Your idea saved me hours.
Thanks for sharing your research and script. I was having the same issue you experienced using WP-Supercache with mod_rewrite caching not triggering garbage collection, and future posts failing to publish with “schedule missed” errors.
Hi,
Thank you for this post.
Here is a new version of wp-cron-multi-blog.php
http://goo.gl/Tz9GC
Thanks for the detailed information! The WordPress developers should revisit how they implement cron in core.