Если у вас на WordPress периодически «не уходят письма», не чистится кэш, не обновляются фиды, не срабатывают расписания резервных копий или «залипают» задачи WooCommerce — очень часто виноват не плагин, а wp-cron. Точнее, то, как он запускается.
В WordPress нет «настоящего» демона планировщика внутри PHP. Вместо этого используется механизм, который имитирует cron через входящие веб-запросы. Это удобно для shared-хостинга и простых сайтов, но на продакшене создаёт неожиданные эффекты: задания выполняются пачками, с задержками, дублируются или вообще не стартуют.
Ниже разберём: как устроен «крон» в WordPress, в чём разница между wp-cron и реальным системным cron, когда стоит переходить на cron на уровне ОС, и как сделать это безопасно.
Что такое wp-cron и почему он «не настоящий» cron
wp-cron — это встроенный планировщик задач WordPress. Он хранит расписания в базе (в опции cron) и выполняет callbacks, зарегистрированные ядром и плагинами.
Ключевая особенность: WordPress не имеет отдельного процесса, который «тикает» каждую минуту. Вместо этого он пытается запускать выполнение задач при каждом посещении сайта. Когда приходит HTTP-запрос, WordPress проверяет: есть ли просроченные события, и если да — инициирует обращение к wp-cron.php.
wp-cron— это не системный планировщик, а механизм, который пытается запускать задания «по случаю» входящих запросов.
Отсюда следуют практические последствия:
- на сайте с низким трафиком задачи могут запускаться с большими задержками;
- при всплеске трафика возможны конкурирующие запуски и «шторм» cron-процессов;
- если сервер/защита ограничивает фоновые HTTP-запросы, задания могут не стартовать вообще;
- в момент пиковых нагрузок cron добавляет ещё одну нагрузку на PHP/MySQL.
Как WordPress запускает wp-cron.php и где ломается
В типичной конфигурации WordPress инициирует обращение к wp-cron.php неблокирующим HTTP-запросом (например, через wp_remote_post()). Запрос идёт «сам в себя» по доменному имени сайта. И вот тут начинаются тонкости:
- DNS/IPv6/прокси/CDN могут направлять запрос не туда, куда вы ожидаете;
- WAF/правила безопасности иногда режут запросы к
wp-cron.php; - мешают Basic Auth, IP allowlist или закрытая админка;
- при проблемах с TLS (SNI/цепочка/истёкший сертификат) запрос не выполнится;
- на слабых конфигурациях Nginx/Apache ↔ PHP-FPM это становится заметным источником нагрузки.
Real cron (системный cron) и что меняется для WordPress
Real cron — это системный планировщик на уровне ОС (cron/anacron/systemd timers), который запускает команду по расписанию независимо от посещаемости сайта. Для WordPress обычно делают так: отключают встроенный триггер wp-cron и запускают обработку задач по расписанию через системный планировщик.
Плюсы системного cron для WordPress:
- Предсказуемость: задания выполняются близко к расписанию.
- Контроль нагрузки: вы задаёте частоту, можно разнести по минутам разные сайты.
- Стабильность: меньше шансов на пропуски из-за блокировок фоновых HTTP-запросов.
- Диагностика: есть логи cron/systemd, проще понять, что запускается и с чем падает.
Минусы тоже есть:
- нужен доступ к планировщику (на некоторых тарифах/хостингах это ограничено);
- при нескольких сайтах на одном сервере важно не устроить одновременный пик запуска;
- для очень нагруженных проектов иногда нужна более тонкая архитектура (очереди/воркеры).
Если вашему проекту уже тесно в рамках ограничений общего окружения, логичным шагом становится перенос на VDS, где вы контролируете cron/systemd, лимиты PHP-FPM и правила доступа к wp-cron.php.

Когда wp-cron достаточно, а когда пора переходить на системный cron
wp-cron обычно подходит для небольших сайтов с регулярным трафиком и простыми задачами: публикация запланированных постов, лёгкая очистка временных данных, обновление кеша раз в несколько часов.
Переход на системный cron почти всегда оправдан, если:
- сайт с низкой посещаемостью, но есть критичные расписания (письма, синхронизации, платежи);
- WooCommerce и фоновые действия (обработка заказов, вебхуки, очистка транзиентов);
- есть интеграции, которые должны выполняться в конкретные окна времени;
- наблюдаете «cron шторм»: много процессов
wp-cron.phpодновременно; - плагины добавляют тяжёлые задания (импорт/экспорт, генерация изображений, рассылки).
Для общего понимания, как устроены расписания на Linux (crontab и systemd timers) и как их правильно логировать, пригодится материал: cron, crontab и systemd timers: выбор и практика.
Типичные симптомы проблем с wp-cron
На практике проблемы с wp-cron выглядят так:
- Задержки: запланированные записи публикуются через 30–60 минут или «когда зайдёшь в админку».
- Пачки: несколько часов ничего, потом внезапно массовое выполнение задач.
- Дубли: одно и то же действие происходит дважды (например, повторная отправка письма).
- Нагрузка: всплески CPU и одновременные PHP-процессы, совпадающие с входящим трафиком.
- Очередь не разгребается: события копятся, в списке scheduled actions растёт «pending».
Диагностика: как понять, что ломается
Дальше — практичные проверки, которые обычно дают быстрый ответ.
1) Проверьте, не отключён ли wp-cron
В wp-config.php может быть включена константа отключения:
define('DISABLE_WP_CRON', true);
Если она включена, а системный cron при этом не настроен — задания выполняться не будут (или будут запускаться только вручную).
2) Проверьте, доступен ли wp-cron.php по HTTP именно с сервера
Важно не «открывается ли в браузере», а выполняется ли корректный запрос с самого хоста, где крутится сайт. Типовые проблемы:
- редиректы HTTP→HTTPS или www↔non-www добавляют лишние переходы и иногда ломают запуск;
- доступ закрыт по IP или Basic Auth;
- CDN/WAF отвечает челленджем или 403;
- нестабильный DNS или проблемы с IPv6.
3) Проверьте lock и конкуренцию
WordPress использует блокировку (lock), чтобы не запускать cron параллельно слишком часто. Но при высокой нагрузке и медленных задачах бывают ситуации, когда:
- lock удерживается слишком долго из-за зависшего процесса;
- происходит гонка и запускается несколько обработчиков;
- процессы убиваются лимитами времени/памяти, и задания остаются «просроченными».
Если у вас в логах Nginx/Apache и PHP-FPM видно множество одновременных обращений к wp-cron.php — это прямой сигнал, что пора переводить на системный cron и ограничивать параллелизм.
4) WP-CLI: быстрая проверка событий
Если есть WP-CLI, диагностика становится проще:
wp cron event list
Можно принудительно запустить обработку просроченных задач:
wp cron event run --due-now
А чтобы понять, что «тяжёлое», смотрите конкретные хуки и их периодичность (часто виноваты плагины импорта/оптимизации/рассылок).
Как правильно перейти с wp-cron на системный cron
Переход делается в два шага: (1) отключить автозапуск wp-cron от посетителей, (2) настроить системный запуск по расписанию. Важно сделать это без окна, когда cron выключен «с двух сторон».
Шаг 1. Отключите встроенный триггер wp-cron
Добавьте в wp-config.php (обычно ближе к началу, до строки “That’s all…”):
define('DISABLE_WP_CRON', true);
Это отключит попытки WordPress запускать cron на каждом запросе.
Шаг 2. Настройте системный cron на запуск задач
Дальше есть два распространённых подхода: дергать wp-cron.php по HTTP или запускать WP-CLI. WP-CLI чаще надёжнее и быстрее, но не всегда доступен.
Вариант A (универсальный): запрос к wp-cron.php по HTTP
Пример для системного cron раз в 5 минут (команда должна быть одной строкой):
*/5 * * * * curl -fsS -m 30 -A 'cron' 'https://example.com/wp-cron.php?doing_wp_cron=1' >/dev/null
Пояснения по параметрам:
-f— считать HTTP 4xx/5xx ошибкой;-sS— тише, но показать ошибки;-m 30— таймаут, чтобы не копились зависшие процессы;- User-Agent помогает отличать cron-запуски в логах.
Если сайт доступен только по Basic Auth или через фильтры WAF/CDN, этот вариант может потребовать отдельного разрешающего правила для wp-cron.php. В таких схемах часто проще перейти на WP-CLI.
Вариант B (предпочтительно при доступном WP-CLI): wp cron event run
Запуск через WP-CLI меньше зависит от сети/HTTPS/CDN и не делает лишний HTTP-круг. Пример раз в 5 минут:
*/5 * * * * cd /var/www/site && wp cron event run --due-now --quiet
Если WP-CLI запускается не от того пользователя, проверьте права на файлы и доступ к wp-config.php. Также убедитесь, что окружение (PATH, PHP) соответствует вашему воркеру.
Как выбрать частоту: каждую минуту или раз в 5 минут
Универсальный старт — раз в 5 минут. Раз в 1 минуту имеет смысл, если есть задачи, чувствительные к задержке, и при этом выполнение стабильно укладывается в лимиты.
Важно: если ваши задачи реально выполняются 2–3 минуты, а cron запускается каждую минуту, вы можете получить параллельные запуски и повторную нагрузку. Тогда лучше:
- увеличить интервал (например, до 5 минут);
- уменьшить время выполнения задач (оптимизация/разнос);
- вынести тяжёлые процессы в воркеры/очереди на крупных проектах.
Практика: защита от параллельных запусков
Одна из главных целей системного cron — контролировать конкуренцию. На уровне cron это часто решают через блокировку.
Пример с flock (если запускаете WP-CLI):
*/5 * * * * flock -n /tmp/wp-cron.lock sh -lc 'cd /var/www/site && wp cron event run --due-now --quiet'
Так вы гарантируете, что новый запуск не начнётся, пока предыдущий ещё идёт (или просто пропустится, если lock занят).

Частые ошибки при настройке системного cron для WordPress
Ошибка 1. Отключили wp-cron, но не настроили cron в ОС
Самая распространённая. В итоге wp-cron выключен, а системный cron не запускает ничего — задания «умирают» полностью.
Ошибка 2. HTTP-запуск ходит через CDN/WAF и блокируется
Если используете вариант A, убедитесь, что запрос реально доходит до origin. Если у вас строгие политики доступа, иногда проще перевести запуск на WP-CLI, чем «пробивать» исключения на периметре.
Ошибка 3. Слишком частый cron и параллельные выполнения
Частота «каждую минуту» не всегда лучше. Стабильные 5 минут без параллелизма обычно эффективнее, чем 1 минута с очередями и дублями.
Ошибка 4. Неправильный домен и лишние редиректы
Если cron запускается через HTTP, используйте канонический URL без цепочек редиректов. Редиректы — это лишнее время, лишние ошибки и иногда неожиданные блокировки.
Как понять, что всё работает: контрольные признаки
После переключения на системный cron проверьте:
- в логах web-сервера появились регулярные обращения к
wp-cron.php(если вариант A); - или в логах cron/systemd есть успешные запуски WP-CLI (если вариант B);
- запланированные записи публикуются вовремя;
- очередь scheduled actions не растёт бесконечно;
- исчезли всплески одновременных процессов
wp-cron.phpот трафика.
Если у вас cron-контур завязан на HTTPS и вы хотите заранее ловить ситуации с истёкшим сертификатом (когда фоновые запросы внезапно начинают падать), поможет материал: контроль срока действия SSL и продление без сюрпризов. А для надёжной цепочки доверия используйте нормальные SSL-сертификаты вместо временных решений.
Шпаргалка выбора: wp-cron или системный cron
- Оставляйте wp-cron, если сайт маленький, трафик есть всегда, а задержка задач некритична.
- Переходите на системный cron, если задачи критичны по времени, трафик нестабилен, есть WooCommerce/интеграции, или вы видите «cron шторм» и залипания.
Итого
wp-cron — компромиссный механизм, который хорошо подходит для простых сценариев и ограниченных окружений, но может подводить на продакшене. Перевод на системный cron — один из самых дешёвых по времени способов повысить стабильность WordPress: задачи начинают выполняться по расписанию, уменьшается хаотичная нагрузка, становится проще диагностика.
Если хотите, в следующем материале можно разобрать конкретные схемы: cron на виртуальном хостинге (без root), cron на VDS через systemd timers, и типовые настройки для WooCommerce/Action Scheduler.


