Правильный запуск WP-Cron в мультисайтовых сетях WordPress
У меня есть мультисайтовая сеть WordPress с несколькими сайтами. Я установил DISABLE_WP_CRON
в значение true
в файле wp-config.php
.
Если мы настраиваем cron-задачу с помощью wget или curl, у нас есть ограничение в 30 секунд на выполнение PHP-скрипта. Это слишком мало для отправки большого количества email-уведомлений и других задач (возможно, медленное соединение с SMTP-сервером или действительно огромное количество уведомлений от bbPress).
Можно ли использовать что-то вроде этого?
php -q wp-cron.php
Но это запускает cron только для одного сайта в мультисайте (каждый сайт имеет свои собственные cron-задачи в разных таблицах MySQL).
P.S. На форуме wpmudev.org я нашел странное "решение", которое также использует Curl.
Еще P.S. WP CLI имеет отличные команды wp cron
, но они позволяют запускать cron-задачи только вручную (да, мы можем использовать атрибут --url
). Например:
wp cron event list --url=multisite.com
wp cron event list --url=subdomain.multisite.com

После того как вы добавили константу в wp-config.php
defined('DISABLE_WP_CRON') or define('DISABLE_WP_CRON', true);
WP-CLI
И предполагая, что ваш config.yml
настроен правильно, вы можете опустить флаг --path
при вызове cron run
.
wp cron event run --due-now
[<hook>…]
Один или несколько хуков для выполнения.
[--due-now]
Выполнить все хуки, которые должны быть выполнены сейчас.
[--all]
Выполнить все хуки.
Чтобы выполнить все запланированные задачи cron по порядку:
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;
Если вы хотите выполнить их параллельно (сначала выполнив кроны, не зависящие от сайта):
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;
Вы можете поместить любой из вариантов в исполняемый файл
chmod +x run_all_wp_cron_events_due_now.sh
добавить задачу в crontab
crontab -e
и, вероятно, выполнять каждую минуту
* * * * * run_all_wp_cron_events_due_now.sh > /dev/null
Если вы хотите запустить пользовательскую команду из cron, вам может потребоваться указать полные пути для работы wp-cli.
* * * * * cd /home/username/public_html; /usr/local/bin/php /home/username/wp-cli.phar your-custom-cron-commands run >/dev/null 2>&1
PHP
Единственная причина, по которой вам может понадобиться загружать WordPress здесь — это получить URL-адреса из базы данных, а не использовать предопределённый список. Мы просто будем обращаться к этим URL-адресам, и нам не важно, каков будет ответ.
custom-cron.php
<?php
// Загрузка WP
require_once( dirname( __FILE__ ) . '/wp-load.php' );
// Проверка версии
global $wp_version;
$gt_4_6 = version_compare( $wp_version, '4.6.0', '>=' );
// Получение блогов
$args = array( 'archived' => 0, 'deleted' => 0, 'public' => 1 );
$blogs = $gt_4_6 ? get_sites( $args ) : @wp_get_sites( $args ); // >= 4.6
// Запуск Cron для каждого блога
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 );
}
И добавить один вызов вашего custom-cron.php
в crontab
* * * * * wget -q -O - http://your-site.com/custom-cron.php?doing_wp_cron

Я считаю, что лучший способ - использовать WP-CLI, но вам нужно будет написать bash-скрипт для этого. Вот скрипт, который должен сработать:
WP_PATH="/путь/к/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
Затем вам нужно будет добавить этот скрипт в crontab и запускать его, например, каждую минуту, если нужно.

Хм, спасибо за ваше мнение, но я считаю это грязным решением. Думаю, будет лучше написать PHP-аддон для wpcli, который просто выполнит все необходимые задачи. Мне нужно больше времени, чтобы разобраться в функциях и коде WordPress для этого.

@KolyaKorobochkin Я не согласен. Это совсем не грязное решение, поскольку WP CLI был создан для использования в командной строке и bash-скриптах.

wp cron event run --due-now --url="$SITE_URL" --path="$WP_PATH
- Согласно документации run
, следует использовать флаг --due-now
. Это сократит количество проверок и отдельных вызовов событий. Смотрите: http://wp-cli.org/commands/cron/event/run/. В любом случае, я согласен с @OmarJackman - он использует командную строку для работы с инструментами командной строки WordPress. Отличный пример чистого Bash-кода. Можно дополнить этот ответ, показав запись в crontab.

Для удобства будущих читателей, скрипт выглядит следующим образом: 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

Это гораздо более разумное использование доступных инструментов в WP CLI, чем ответы, в которых прилагают массу усилий для разбора результатов вывода в CSV. Отлично работает!

Очень умно! Теперь мы используем это в SlickStack для Multisite, когда пользователи выбирают метод wpcli
для управления их WP-Cron: https://github.com/littlebizzy/slickstack/blob/master/crons/01-cron-minutely.txt

Вот моё решение:
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; // заменяем на основной хост
}
require './wp-cron.php';
}
function shutdown()
{
run_cron();
}
run_cron();
Мы вызываем это из crontab, надеюсь, поможет

Вы можете найти полное руководство здесь о том, как правильно настроить задание cron для системы WordPress Multisite, чтобы оно запускалось на всех подсайтах и выполняло задания cron. https://support.shorturl.gg/business-marketing-and-seo-forums/topic/you-are-using-wp-cron-incorrectly-in-wordpress-multisite/
Использование стандартного задания cron для отдельных сайтов WordPress работает не очень хорошо, так как стандартное задание WP cron будет запускать задания cron только для основного сайта, и, как следствие, задания cron не будут выполняться на подсайтах.

Хотя данная ссылка может ответить на вопрос, лучше включить основные части ответа здесь и предоставить ссылку для справки. Ответы, состоящие только из ссылок, могут стать недействительными, если страница по ссылке изменится. - Из обзора

Прежде всего, нужно уточнить, что вы подразумеваете под "правильным запуском wp-cron.php". Согласно документации WordPress, нелогично отключать wp-cron, но при этом хотеть, чтобы он работал... С точки зрения Linux, использование wget или /bin/php для запуска wp-cron.php было бы правильным, но похоже, что ваш хостинг ограничивает количество вызовов php из соображений безопасности? — эта часть не совсем ясна из вашего описания.
Другой вопрос: сколько именно писем вы имеете в виду под "кучей"? Есть веские причины, по которым не стоит пытаться отправлять слишком много писем так быстро.
Возможно, вам придётся пересмотреть свои цели.
(Я бы оставил комментарий вместо ответа, но у меня недостаточно репутации на wpstack.)

Существует несколько способов запуска WordPress cron. Встроенный механизм активируется при посещении страниц, и общепринятой практикой является установка DISABLE_WP_CRON
для отключения этого метода при настройке более надежного системного cron.

Вопрос не в том, почему это нужно делать/имеют ли причины смысл, а в том, как правильно вызывать wp-cron.php в мультисайтовой установке. Для меня всё вполне понятно ;)
