How wp-cron works?
As you remember WordPress in-built Cron doesn’t work the same way as classical cron job does. Instead of time-triggering it fires every time when someone visits the website. No visits, no triggering wp cron and no tasks executed.
Why you should not use WP Cron?
And vice versa if you’ve been lucky to got loads of visitors on your website wp cron system will be triggered every single time when someone views any page and check for scheduled tasks. This way wordpress cron causes extra server load (CPU usage increases) which may significantly harm website performance. That’s speaking of single install.
When it comes to WordPress Multisite your problems multiply on quantity of websites on your install.
WordPress Cron on Multisite installs works independently on each blog. Say you got posts scheduled on website A and B. When someone visits website A posts on this blog though with delay but will be published. But posts on website B would never be published untill someone visits website B too. Having missed schedule issue on every site of network can be rather annoying thing. And you may face another problem when you get some significant traffic no your WP MU install. That CPU usage issue multiplies too according to the number of websites in your network.That’s why using in-bult WP Cron for Multisite is not great idea at all. Instead we shall set real cron job.
WordPress Cron Multisite: obvious approach
How to set cronjob for WP Multisite and fix missed schedule issue across the network?
To reduce CPU usage and get tasks executed no matter whether there are hits on the blog or not we should replace WP cron with server cron.
Here in details how we did it for single install.
For Multisite the steps are similar except that we need to trigger cron on every single site of the network because they works independently as you remember.
Replace WordPress Multisite Cron with real Cron job
- Disable WordPress cron across whole network in wp-config.php:PHP1define('DISABLE_WP_CRON', true);
- We will trigger publishing on every site with aid of foreach loop. Create trigger.php in the same directory. I have this awesome wrapper for doing bulk actions network wide. It has saved me loads of time with WP MU. Let it work for you too:
So we just place this piece of code after the line //here what we gonna do...PHP123$site_url = get_site_url($blog_id);$command = $site_url.'/wp-cron.php?doing_wp_cron';wp_remote_get( $command );
and it will trigger each site of our network automatically. Entire trigger.php will be
- All you need now is to add single cron job to your system cron:PHP1wget -O /dev/null http://network-main-blog.com/trigger.php
How to do it through CPanel see here in details. Mind to set reasonable time interval.
That’s all. According to specified recurrence (e.g. once a day) unix cron will fire trigger.php -> which will fire wp-cron.php on every blog in the network-> which will check if there are scheduled tasks and execute them
This is sufficient and clear way to set scheduled tasks on WP MU install. But what you gonna do if you’ve got rather large network and you are tight on server resources? Let’s see.
WordPress Cron Multisite: better approach
All scheduled tasks in WP are stored in wp_options table. When you schedule task to publish 50 drafts daily, 50 tasks are saved in your wp_options table. Most part of this table including cron jobs is loaded at every single page load. That’s OK for single install but can significantly slow down your pagespeed on Multisite Network. Say, you’ve got middle-sized netwotk of 100 sites which leads us to 50*100=5000 additional lines in all your options tables (mind, this is the same database!). Furthermore, the more visits your network gets the much recourses will be consumed for this operarion only.
To avoid memory leak and sleep peacefully at night without fearing your MySQL server collapse any moment we would rather skip WordPress scheduling. Instead of cronjob for publishing scheduled posts we’ll set cron job to publish posts directly.
Farther I’m giving detailed instructions how to arrange this, but before you proceed keep in mind this approach may not be suitable for every single project. For example, if publish time is extremely important for you this is not what you want to do.
But if you’ve got loaded network and you need to publish drafts daily, save server resources and don’t mind the publish time you should definetely try this out.
- First of all we need the very function that will actually publish 50 drafts. Create in the WordPress root directory publishing.php with the following content:
This simple piece of coe will publish drafts directly, without scheduling.
- Now we need this publishing.php triggered for execution across whole network. We are replacing WP Cron with system cron the same we did in previuos option. Just mind place publishing.php instead of wp-cron.php?doing_wp_cronPHP1$command = $site_url.'/wp-cron.php?doing_wp_cron';
and it will trigger each site of our network automatically.
- Voilà! We’ve managed to reduce CPU and memory usage by replacing WP Multisite Cron with real cron job across network and skipping scheduling at all.
Sounds nice? As I already said for small networks this approach is pretty good, but in case you got 100+ blogs it means publish function will be executed 50*100 = 5000 times at once. And you hardly want it, right?
WordPress Cron Multisite: my approach for high-loaded networks
Overview: WordPress Multisite network consists of 100+ blogs. 50 posts should be published daily on every blog which leads us to 50*100=5000 post publishes by cron everyday. This should be executed with minimal server load as this network is rather loaded apart of publish process.
How to publish 50 posts a day on more that 100 blogs without making your server collapse?
Here I’m using another approach which reduces CPU usage dramatically. This way we’ve got:
- no cron event to schedule posts for publishing
- no cron events for publishing each of 50 posts
- cron triggered once (!) a day on each website of the network
- no overload by bulk publishing, just 50 posts are published at a time
This approach may be somewhat tricky for developer but this is how we use as less server resourse as possible.
We’ll add a separate cron job for every website in the network and give it command to execute publishing.php directly. We have already got this file prepared, now we need to add separate cron job for every site in network. Each cronjob should be schedule with 1 minute interval. Imagine, you have 3 sites in your network (but you won’t bother with all these in that case, will you?). Cron jobs should be executed like this:
site A — at 00:01
site B — at 00:02
site C — at 00:03
Each executed once a day, at precise time. This way only one site got triggered in a minute, no overload, no problems.
So, there would be 3 commands which you add to your crontab will look like:
wget -O /dev/null http://siteA.com/publishing.php
wget -O /dev/null http://siteB.com/publishing.php
wget -O /dev/null http://siteC.com/publishing.php
Blimey, Sabrina, I’ve got 100+ sites in the network! Are you telling me to add 100+ cronjobs manually? O_o
Sure, I’m not! Cron job bulk scheduling in Linux is already waiting for you, my friend)