Если на сайте WordPress не отправляются отложенные письма, не обновляются фиды, не выполняются задачи WooCommerce или зависают фоновые процессы, проблема часто не в самом хуке, а в том, как запускается WP-Cron. В стандартной схеме WordPress проверяет запланированные события только при посещении сайта. На небольшом проекте это ещё терпимо, но на сайте с редким трафиком или агрессивным кэшированием задачи начинают срываться.
Ниже — практический сценарий: как диагностировать проблему, отключить псевдо-cron WordPress и перевести выполнение задач на системный cron на сервере. Без выдуманных плагинов и без магии.
Когда проблема действительно в WP-Cron
Сначала стоит убедиться, что вы ищете не там. Если отложенные действия не выполняются, это может быть связано не только с cron, но и с ошибками в самом коде, недоступной почтой, конфликтом плагинов или блокировкой запросов к wp-cron.php.
Типичные симптомы
- запланированные публикации не выходят вовремя;
- WooCommerce не отправляет часть служебных писем;
- очереди фоновых задач копятся, но не обрабатываются;
- в
wp_optionsрастёт массивcron, а задачи остаются в статусе pending; - на сайте с кэшем запросы к
wp-cron.phpпочти не происходят.
Что проверить до изменений
- Есть ли ошибки в
wp-content/debug.log, если включёнWP_DEBUG_LOG. - Не блокирует ли хостинг обращения к
wp-cron.php. - Не отключён ли запуск cron через
DISABLE_WP_CRONвwp-config.php. - Не стоит ли плагин безопасности, который режет внутренние HTTP-запросы.
Если задачи не выполняются только на сайте с низкой посещаемостью, а вручную через прямой вызов /wp-cron.php они отрабатывают, почти наверняка нужен системный cron.
Почему стандартный WP-Cron нестабилен
WP-Cron — это не настоящий системный демон. Он запускается при веб-запросах. Отсюда и ограничения:
- при нулевом трафике задачи не стартуют;
- при высокой нагрузке несколько посетителей могут одновременно инициировать cron-проверку;
- кэширующие прокси и CDN не помогают запуску фоновых событий;
- долгие задачи могут конфликтовать друг с другом, если сайт часто открывают.
Для большинства production-сайтов лучше отключить псевдо-cron и запускать wp-cron.php по расписанию на уровне сервера.
Пошаговое решение: переводим WP-Cron на системный cron
Шаг 1. Отключите внутренний запуск WP-Cron
Откройте wp-config.php и добавьте константу до строки /* That's all, stop editing! */:
define( 'DISABLE_WP_CRON', true );Это не выключает сами запланированные события. WordPress просто перестаёт пытаться запускать их при каждом посещении сайта.
Шаг 2. Настройте системный cron на сервере
На Linux-хостинге обычно используют crontab. Самый безопасный и предсказуемый вариант — вызывать wp-cron.php через HTTP с интервалом в 5 минут. Пример записи:
*/5 * * * * curl -sS https://example.com/wp-cron.php?doing_wp_cron > /dev/null 2>&1Если на сервере есть WP-CLI и вы уверены в окружении, можно использовать и его, но для большинства хостингов HTTP-вызов проще и совместимее.
Если сайт работает на отдельном домене с HTTPS и редиректами, проверьте, что запрос не уходит в бесконечную цепочку редиректов. В этом случае лучше указывать конечный URL без лишних промежуточных переходов.
Шаг 3. Проверьте расписание задач в WordPress
После настройки cron полезно посмотреть, что именно висит в очереди. Если у вас есть WP-CLI, выполните:
wp cron event listКоманда покажет список событий, их расписание и время следующего запуска. Это удобно, когда нужно понять, не застряла ли конкретная задача.
Если WP-CLI недоступен, можно временно поставить диагностический плагин для просмотра cron-событий или проверить данные в базе через wp_options. Но для постоянной работы лучше не опираться на ручной просмотр таблицы.
Сравнение вариантов запуска
| Подход | Когда уместен | Минусы |
|---|---|---|
| Стандартный WP-Cron | Тестовый сайт, небольшой трафик | Зависит от посещаемости, нестабилен на кэшированных сайтах |
| Системный cron через HTTP | Большинство production-сайтов | Нужно доступное расписание на сервере и контроль редиректов |
| WP-CLI cron event run | Есть SSH и управляемый сервер | Не всегда доступен на shared-хостинге |
Как проверить, что решение сработало
Проверка должна быть не формальной, а практической. Не ограничивайтесь тем, что запись в cron добавлена.
- Создайте тестовое событие с ближайшим временем запуска.
- Посмотрите его в списке через
wp cron event listили в интерфейсе диагностики. - Дождитесь следующего запуска системного cron.
- Проверьте, что событие исчезло из очереди и выполнило действие.
Если вы тестируете на WooCommerce, удобно проверить не абстрактную задачу, а конкретный сценарий: отложенное письмо, смену статуса, очистку временных данных или фоновую обработку очереди. Так проще понять, что cron действительно работает, а не просто отвечает без ошибок.
Простой тест через собственное событие
Если нужен контролируемый тест, можно временно добавить в мини-плагин или functions.php такое событие:
add_action( 'init', function () {
if ( ! wp_next_scheduled( 'wp0_test_cron_event' ) ) {
wp_schedule_single_event( time() + 300, 'wp0_test_cron_event' );
}
} );
add_action( 'wp0_test_cron_event', function () {
error_log( 'WP-Cron test event executed at ' . current_time( 'mysql' ) );
} );После этого проверьте лог ошибок. Если запись появилась после запуска системного cron, настройка работает.
Частые ошибки и как их исправить
1. Отключили WP-Cron, но не добавили системный cron
Это самая частая ошибка. После define( 'DISABLE_WP_CRON', true ); сайт перестаёт сам запускать задачи. Если внешний cron не настроен, всё просто встанет.
Исправление: сначала добавьте cron на сервере, потом отключайте внутренний запуск.
2. Указали URL с редиректом или неверным доменом
Если сайт открывается с www, а cron ходит на без-www версию, или наоборот, можно получить лишние редиректы. На некоторых хостингах это ломает запуск или делает его нестабильным.
Исправление: используйте канонический URL сайта и проверьте ответ curl -I.
3. Хостинг режет внешние HTTP-запросы
Иногда запрос к wp-cron.php блокируется фаерволом, basic auth или ограничениями на loopback-запросы.
Исправление: уточните у хостинга, разрешены ли обращения к собственному сайту с сервера. Если есть SSH, иногда проще использовать WP-CLI.
4. Слишком частый запуск
Запуск каждую минуту не всегда нужен. Если задач немного, это лишняя нагрузка. Если задач много, лучше смотреть на реальную потребность, а не ставить минимальный интервал «на всякий случай».
Исправление: начните с 5 минут и уменьшайте интервал только если есть понятная причина.
Безопасность и производительность
Открытый wp-cron.php — обычная часть WordPress, но его не стоит дергать без необходимости. На нагруженных сайтах полезно следить за количеством фоновых задач и не плодить события в каждом запросе.
- Не ставьте cron-задачи внутри часто вызываемых хуков без проверки
wp_next_scheduled(). - Не используйте слишком короткий интервал, если задача не критична по времени.
- Если cron выполняет тяжёлую обработку, выносите её в отдельные порции, а не в один длинный запрос.
- Проверяйте, не создаёт ли плагин дублирующиеся события после обновления.
Для диагностики и чистки лишних дублей в админке иногда помогает Clearfy Pro, но сам перевод cron на системный запуск всё равно лучше делать на уровне сервера, а не маскировать плагином.
Что делать, если задачи всё равно не выполняются
Если системный cron уже настроен, а события по-прежнему зависают, смотрите в сторону конкретной задачи:
- проверьте, не падает ли callback с фатальной ошибкой;
- посмотрите, не блокирует ли выполнение плагин безопасности;
- убедитесь, что задача не зависит от недоступного внешнего API;
- проверьте, не переполнена ли очередь однотипными событиями.
В таких случаях полезно временно включить логирование и отследить, на каком этапе задача перестаёт выполняться. Сам cron может быть настроен правильно, но обработчик события — нет.