Как заменить WordPress Cron заданием Linux Cron

Встроенный WP-Cron в WordPress срабатывает не по таймеру системы, а при заходах на сайт: кто-то открыл страницу, и WordPress заодно проверяет очередь задач. Как сказано в справочнике для разработчиков плагинов, WP-Cron не работает постоянно, и для задач, которые должны выполняться вовремя, это проблема. Решение там же: отключить запуск на каждой странице и повесить вызов на системный планировщик. Ниже как это сделать на Linux через crontab.

Чем плох WP-Cron из коробки

  • нет посещений, нет запуска: отложенные публикации, рассылки и бэкапы плагинов опаздывают;
  • на каждой загрузке страницы WordPress проверяет очередь, и это лишняя нагрузка на занятом сайте;
  • нельзя гарантировать интервал «каждые N минут» независимо от посещаемости.

Системный cron вызывает задачи сам по расписанию и от посетителей не зависит.

Шаг 1. Отключить встроенный запуск

В wp-config.php до строки /* That's all, stop editing! */ и подключения wp-settings.php добавьте:

define( 'DISABLE_WP_CRON', true );

После этого WordPress перестанет запускать задачи при открытии страниц. Сама очередь никуда не денется, её теперь нужно вызывать снаружи. В документации по wp-config.php рядом описана ещё одна константа, WP_CRON_LOCK_TIMEOUT: она не даёт cron запускаться чаще, чем раз в указанное число секунд, по умолчанию 60.

Шаг 2. Задание в crontab

Откройте crontab пользователя, от которого работает сайт, например www-data, или своего, если файлы сайта принадлежат вам:

sudo crontab -u www-data -e
# или для текущего пользователя
crontab -e

Есть три способа вызвать очередь. Первый, самый надёжный, через WP-CLI: он запускает задачи прямо в PHP, без веб-сервера и кэша.

*/5 * * * * cd /var/www/html && /usr/local/bin/wp cron event run --due-now --quiet

По документации WP-CLI, ключ --due-now запускает все задачи, у которых подошло время, и учитывает блокировку doing_cron, поэтому запуски не наложатся друг на друга. Для мультисайта есть ключ --network, он проходит по всем сайтам сети.

Второй способ через HTTP, его и показывает справочник WordPress. Подставьте свой домен:

*/5 * * * * wget -q --delete-after "https://example.com/wp-cron.php?doing_wp_cron" >/dev/null 2>&1
# или curl
*/5 * * * * curl -fsS -o /dev/null "https://example.com/wp-cron.php?doing_wp_cron" >/dev/null 2>&1

Ключ --delete-after нужен, чтобы wget не складывал ответ сервера в файл при каждом запуске. Этот вариант работает где угодно, но зависит от веб-сервера, файрвола и защиты от ботов: если запрос к wp-cron.php режется, задачи не выполнятся.

Третий способ через PHP CLI, если WP-CLI нет:

*/5 * * * * cd /var/www/html && /usr/bin/php wp-cron.php >/dev/null 2>&1

Путь к PHP, WP-CLI и корню сайта замените на свои: which php, which wp и ваш document root.

Интервалы в crontab

Формат строки: минута, час, день месяца, месяц, день недели, команда.

  • */5 * * * * каждые 5 минут, обычный выбор для WordPress;
  • 0 * * * * каждый час в :00;
  • 0 3 * * * каждый день в 03:00;
  • 0 3 * * 1 каждый понедельник в 03:00.

Большинству сайтов хватает запуска раз в 5-15 минут. Чаще имеет смысл, только если есть задачи, критичные по времени, и сервер это выдерживает.

Проверка

crontab -l                      # список заданий
wp cron event list              # очередь задач и время следующего запуска
journalctl -u cron -n 50        # логи cron в Debian и Ubuntu

Если WP-CLI нет, очередь удобно смотреть плагином WP Crontrol: после системного вызова задачи с подошедшим временем должны уходить из списка. Для отладки можно временно писать вывод в файл:

*/5 * * * * cd /var/www/html && /usr/local/bin/wp cron event run --due-now >> /tmp/wp-cron.log 2>&1

Изменить или удалить задание

Снова crontab -e: поправьте строку или удалите её и сохраните файл. Команда crontab -r удаляет все задания пользователя сразу, с ней осторожно.

Плюсы и риски

  • Плюсы: стабильный интервал без посетителей, никаких сюрпризов на тихих сайтах, нет лишней проверки очереди на каждой странице.
  • Риски: нужен доступ к серверу; опечатка в пути или адресе, и cron молча ничего не делает; слишком частый запуск тяжёлых задач грузит процессор и базу; на shared-хостинге crontab может быть ограничен панелью.

На обычном shared-хостинге без доступа к cron иногда оставляют WP-Cron как есть или используют планировщик в панели хостера. На VPS связка DISABLE_WP_CRON и системного cron это нормальная практика.

Если хочется, чтобы на сайте это настроили вместе с обновлениями и бэкапами, по прайс-листу доработки существующего сайта стоят от 5 000 ₽, техническая поддержка от 20 000 ₽ в месяц.

В итоге замена занимает пять минут: строка define( 'DISABLE_WP_CRON', true ); в wp-config.php, задание в crontab раз в 5 минут через wp cron event run --due-now или wget, и проверка через wp cron event list. После этого задачи WordPress выполняются по расписанию, а не тогда, когда на сайт кто-то зашёл.

Источники и ссылки


Комментарии загружаются…