31

I have WordPress Multisite with several sites. I set up DISABLE_WP_CRON to true in my wp-config.php.

If we set up cron task with wget or curl we have 30 sec rule to execute PHP script. It's so small to send tons of email notifications and do other stuff (maybe remote SMTP server connection is slow, maybe it's really huge bunch of email notifications from bbPress or anything).

Maybe we can use something like this?

php -q wp-cron.php

But it's only run cron to one site in Multisite (each site have their own cron tasks in different MySQL tables).

P. S. On wpmudev.org forum I found strange "solution" which also use Curl.

Another P. S. WP CLI have awesome wp cron commands but it's only allow run cron tasks manually (yep, we can use --url attr). For example:

wp cron event list --url=multisite.com
wp cron event list --url=subdomain.multisite.com
7
  • Have you taken a look at WP-CLI core code?
    – kaiser
    Commented Nov 3, 2014 at 1:36
  • Yes. I dig into the source code right now and trying to understand :) Command to run all tasks (events) not exists, maybe I can create it in future. Commented Nov 4, 2014 at 13:27
  • Do you have wp/WP-CLI in your PATH? If yes, why not trigger that from a bash file running in cron?
    – kaiser
    Commented Nov 4, 2014 at 13:38
  • Sounds great! But how to run all cron tasks from wp cli? I don't see any commands for this. Commented Nov 15, 2014 at 14:45
  • 1
    Worth mentioning that if you only have a few sites in your multisite network with no plans to grow you could always just run them individually with wp cron event run --due-now --url=mysite1.com && wp cron event run --due-now --url=mysite2.com etc. ... but if you might be adding sites frequently I think the answer from @Anastis works best. Commented Apr 17, 2021 at 3:49

6 Answers 6

19

After you've added the constant in wp-config.php

defined('DISABLE_WP_CRON') or define('DISABLE_WP_CRON', true);

WP-CLI

And assuming you have your config.yml setup correctly, you can ommit the --path flag when calling cron run.


wp cron event run --due-now

[<hook>…] One or more hooks to run.

[--due-now] Run all hooks due right now.

[--all] Run all hooks.


To run all due cron tasks in order:

function run_crons_due_now_in_order { for SITE_URL in $(wp site list --fields=url --format=csv | tail -n +2 | sort); do wp cron event run --due-now --url="$SITE_URL" && echo -e "\t+ Finished crons for $SITE_URL"; done; echo "Done"; }; run_crons_due_now_in_order;

If you want them to run concurrently (running the non-site-specific cron first):

function run_all_crons_due_now { for SITE_URL in $(wp site list --fields=url --format=csv | tail -n +2 | sort); do wp cron event run --due-now --url="$SITE_URL" && echo -e "\t+ Finished crons for $SITE_URL" & done; wait $(jobs -p); echo "Done"; }; run_all_crons_due_now;

You would want to put either option in an executable file

chmod +x run_all_wp_cron_events_due_now.sh

add a crontab task

crontab -e

and probably execute each minute

* * * * * run_all_wp_cron_events_due_now.sh > /dev/null

If you want to run a custom command from cron, you might need to specify the full paths for wp-cli to work.

* * * * * cd /home/username/public_html; /usr/local/bin/php /home/username/wp-cli.phar your-custom-cron-commands run >/dev/null 2>&1

PHP

The only reason you would need to load up WordPress here is to gather the URLs from the database rather than using a pre-defined list. We're only going to ping those URLs and we don't really care what the response is.

custom-cron.php

<?php

// Load WP
require_once( dirname( __FILE__ ) . '/wp-load.php' );

// Check Version
global $wp_version;
$gt_4_6 = version_compare( $wp_version, '4.6.0', '>=' );

// Get Blogs
$args  = array( 'archived' => 0, 'deleted' => 0, 'public' => 1 );
$blogs = $gt_4_6 ? get_sites( $args ) : @wp_get_sites( $args ); // >= 4.6

// Run Cron on each blog
echo "Running Crons: " . PHP_EOL;
$agent = 'WordPress/' . $wp_version . '; ' . home_url();
$time  = time();

foreach ( $blogs as $blog ) {
    $domain  = $gt_4_6 ? $blog->domain : $blog['domain'];
    $path    = $gt_4_6 ? $blog->path : $blog['path'];
    $command = "http://" . $domain . ( $path ? $path : '/' ) . 'wp-cron.php?doing_wp_cron=' . $time . '&ver=' . $wp_version;

    $ch = curl_init( $command );
    $rc = curl_setopt( $ch, CURLOPT_RETURNTRANSFER, false );
    $rc = curl_exec( $ch );
    curl_close( $ch );

    print_r( $rc );
    print_r( "\t✔ " . $command . PHP_EOL );
}

And add a single call to your custom-cron.php in a crontab

* * * * * wget -q -O - http://your-site.com/custom-cron.php?doing_wp_cron
18

I think the best way is to use WP-CLI but you'd need to write a bash script to do this. Here is one that should do it for you:

WP_PATH="/path/to/wp"
for SITE_URL in = $(wp site list --fields=domain,path,archived,deleted --format=csv --path="$WP_PATH" | grep ",0,0$" | awk -F ',' '{print $1 $2}')
do
    for EVENT_HOOK in $(wp cron event list --format=csv --fields=hook,next_run_relative --url="$SITE_URL" --path="$WP_PATH" | grep \"now\"$ | awk -F ',' '{print $1}')
    do
        wp cron event run "$EVENT_HOOK" --url="$SITE_URL" --path="$WP_PATH"
    done
done

You'd then need to add this script to crontab and run it maybe every minute if you like

5
  • Hm thank you for your opinion but I think this is hacky (dirty) solution. I think will be better write some PHP addon for wpcli which just run all needed tasks. I need more time to understand WP functions and code to do it. Commented Jan 31, 2015 at 14:15
  • 11
    @KolyaKorobochkin I disagree. This isn't hacky at all since WP CLI was made to be used on the command line and in bash scripts. Commented Dec 3, 2015 at 18:15
  • 3
    wp cron event run --due-now --url="$SITE_URL" --path="$WP_PATH - According to the run docs, you should utilize the --due-now flag. This would reduce the lookups and individual event calls. See: wp-cli.org/commands/cron/event/run. Either way, I'm with @OmarJackman - he's utilizing the command line to use WordPress command line tools. Props for a clean Bash example. You could round out this answer by showing the crontab entry.
    – jgraup
    Commented Sep 14, 2016 at 16:18
  • 1
    For the benefit of future readers, the script then looks like: WP_PATH="/path/to/wp"; for SITE_URL in $(wp site list --fields=domain,path,archived,deleted --format=csv --path="$WP_PATH" | grep ",0,0$" | awk -F ',' '{print $1 $2}'); do wp cron event run --due-now --url="$SITE_URL" --path="$WP_PATH"; done
    – puzzlement
    Commented Apr 16, 2017 at 0:44
  • Several bloggers seem to have ripped off this answer over the years without crediting you, it's one of the earliest snippets I have seen, so kudos! Commented Mar 28 at 10:38
13

Easier one-liner with less bash:

wp site list --field=url | xargs -i -n1 wp cron event run --due-now --url="{}"

You can either run it manually or put it in a script and call it from cron as in the other answers.

4
  • 1
    Exactly what I was looking for - works just as advertised, thanks!
    – kero
    Commented Oct 15, 2020 at 11:19
  • 1
    This is a much smarter use of the available tools in WP CLI than the answers that are going through a lot of effort to parts out the results of the CSV output. Works great! Commented Apr 17, 2021 at 3:45
  • This is the most smartest answer. And you can put this directly into your crontab.
    – Edd
    Commented Jan 31 at 11:13
  • Very clever! We are using this in SlickStack for Multisite now, when users select wpcli method to manage their WP-Cron: github.com/littlebizzy/slickstack/blob/master/crons/… Commented Mar 28 at 11:04
1

This is my solution:

global $multisite_hosts;
$multisite_hosts = Array('xxxx.dev.xxx.oondeo.es','x2.dev.xxx.oondeo.es','x3.dev.xxx.oondeo.es');

function run_cron(){
  global $multisite_hosts;
  $host=array_pop($multisite_hosts);
  if (!$host)
    return;
  register_shutdown_function('shutdown');
  if (!isset($_SERVER['HTTP_HOST'])) {
       $_SERVER['HTTP_HOST'] = $host;  // replace with primary host
  }

  require './wp-cron.php';
}

function shutdown()
{
  run_cron();
}
run_cron();

We call this from crontab, hope it helps

1

Well you can find a full guide here on how to setup the cron job correctly for a WordPress Multisite system to it fires on all sub-sites to and runs the cron jobs. https://support.shorturl.gg/business-marketing-and-seo-forums/topic/you-are-using-wp-cron-incorrectly-in-wordpress-multisite/

Using the standard cron job for WordPress standalone websites doesn't work well as the standard WP cron job only will fire the cron job for the main site and as such no cron jobs will run on sub-sites.

2
  • While this link may answer the question, it is better to include the essential parts of the answer here and provide the link for reference. Link-only answers can become invalid if the linked page changes. - From Review
    – cjbj
    Commented Oct 14, 2022 at 7:22
  • Right I understand. It was just easier to link to it. Thank you. Commented Oct 14, 2022 at 11:47
-6

I think you need to tell us what you mean by "run wp-cron.php the right way" first and foremost. According to Wordpress, it doesn't make sense that you disable wp-cron and yet want it to run... From the Linux perspective, wget-ing or /bin/php-ing wp-cron.php would be correct, but it seems your particular host is limiting your number of php invocations for security reasons? -- that part isn't completely clear from your description.

Another question: how many emails are "a ton"? There are great reasons why you shouldn't try to send too many emails that quickly.

You may have to re-think your objectives.

(I would comment instead of replying but I don't have enough reputation on wpstack.)

3
  • 5
    There are multiple ways of running the WordPress cron. The built-in mechanism is triggered by page views, and it's common practice to set DISABLE_WP_CRON to disable this method when setting up the more reliable system cron method instead. Commented Jul 11, 2016 at 14:28
  • The question is not why to do it/if the reasons are meaningful but how to correctly call wp-cron.php on a multisite installation. Quite clear for me ;)
    – Philipp
    Commented Oct 26, 2017 at 20:26
  • 2
    I hope you realize you're commenting on a very old and already hidden answer. Commented Oct 27, 2017 at 21:03

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.