На shared-хостинге WordPress сам «просыпается» при заходе посетителя и дёргает wp-cron.php. На VPS с нормальным трафиком это ещё терпимо. На сайте с редкими визитами, агрессивным page cache или WooCommerce в фоне виртуальный cron начинает врать: рассылки опаздывают, Action Scheduler копит pending, формы «отправились», а письмо ушло через два часа.

Ниже — как отключить pseudo-cron, повесить system cron на wp cron event run, и не сломать Woo, membership и плагины рассылок.

к содержанию ↑

Как устроен WP-Cron

WordPress не держит демон. При каждом запросе (если не отключён) ядро проверяет wp_optionscron и при наступлении времени в том же HTTP-запросе выполняет хуки: publish_future_post, очистка ревизий, задачи плагинов.

  • Точка входа: wp-cron.php или встроенный вызов в wp-settings.php.
  • Расписание хранится в БД, не в crontab сервера.
  • Плагины вешают свои события через wp_schedule_event().

На бумаге удобно. На проде с cache и малым трафиком — ненадёжно.

к содержанию ↑

Почему на VPS virtual cron — слабое место

СитуацияЧто происходит
Page cache отдаёт HTML без PHPЗапрос не доходит до WP → cron не тикает
Ночью нет визитовЗадачи сдвигаются на утро
Долгая cron-задача в HTTPТаймаут nginx/PHP-FPM, обрыв на полпути
DDoS / ботыЛишние срабатывания wp-cron.php в логах
Несколько инстансов WPГонки за одну таблицу cron (реже, но бывает)

Связка с мониторингом аномалий: всплеск фоновых задач и wp_mail часто совпадает с «cron наконец догнал очередь».

к содержанию ↑

Когда переходить на system cron

Делайте на VPS/dedicated, если:

  • WooCommerce, подписки, LMS, newsletter-плагины с расписанием.
  • Action Scheduler / WP-Cron events больше пары десятков.
  • Включён полный page cache (nginx, LiteSpeed, Cloudflare APO).
  • Уже видели «зависшие» scheduled posts или отложенные письма.

Можно оставить virtual cron, если:

  • Лендинг без фоновых задач и трафик стабильный весь день.
  • Shared-хостинг запрещает править crontab (тогда хотя бы мониторьте wp cron event list).
к содержанию ↑

Пошагово: отключить pseudo-cron и включить system cron

1. Бэкап и staging

Сначала на копии сайта. После переключения проверьте: оформление заказа, форму, отложенную публикацию, рассылку тестовым списком.

2. Отключить запуск cron из HTTP

В wp-config.php до строки /* That's all, stop editing! */:

define('DISABLE_WP_CRON', true);

Не путать с удалением wp-cron.php — файл остаётся, просто ядро не стартует его на каждом хите.

3. System cron от пользователя веб-сервера

Узнайте путь к PHP и корню WP. Типичная строка в crontab -e (пользователь www-data или deploy):

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

Или через WP-CLI (предпочтительно на VPS с CLI):

*/5 * * * * cd /var/www/example.com && /usr/bin/wp cron event run --due-now --path=/var/www/example.com > /dev/null 2>&1

Интервал 5 минут — разумный дефолт. Раз в минуту — только если плагин требует (редко). Раз в 15 — рискуете опозданием Woo-задач.

к содержанию ↑

4. Защитить wp-cron.php снаружи (опционально)

Раз HTTP-cron отключён, прямой вызов https://site/wp-cron.php ботами бессмысленен. В nginx:

location = /wp-cron.php {
    allow 127.0.0.1;
    deny all;
    include fastcgi_params;
    fastcgi_pass unix:/run/php/php8.2-fpm.sock;
}

System cron бьёт в CLI — этот блок режет только внешний шум.

5. Проверка после переключения

wp cron event list --fields=hook,next_run,recurrence
wp action-scheduler status   # если WooCommerce

Создайте тестовый отложенный пост на +10 минут — должен выйти без ручного захода на сайт.

WooCommerce и Action Scheduler

Woo перевёл очереди на Action Scheduler — отдельные таблицы, свой воркер поверх cron-хуков.

Что проверить:

  1. Tools → Scheduled Actions — нет ли тысяч pending / failed.
  2. Хук action_scheduler_run_queue должен попадать в расписание; без тикающего cron очередь растёт.
  3. После DISABLE_WP_CRON не отключайте system cron «на выходные» — заказы и письма встанут.
  4. Тяжёлые импорты и sync-плагины — смотрите peak CPU; при необходимости вынесите wp cron event run в отдельный low-traffic слот, но не реже 5 мин.

Если failed растёт аномально — это сигнал к SMTP, API маркетплейса или битому плагину, не к интервалу cron само по себе.

к содержанию ↑

Типичные ошибки

  • DISABLE_WP_CRON без system cron — тихая смерть всех фоновых задач.
  • Cron от root, файлы от www-data — permission denied, задачи «выполняются» в логе crontab, WP молчит.
  • Неверный --path в WP-CLI — другая копия сайта или пустая установка.
  • Два crontab на один сайт — двойной запуск, дубли писем (редко, но неприятно).
  • Забыли про staging — на тесте тоже отключили HTTP-cron, но не добавили system — «на стейдже всё сломалось».
  • Плагин «Disable WP Cron» + ручной crontab — дублирующие плагины; оставьте один способ.
к содержанию ↑

Чеклист на первую неделю

  • wp cron event list — нет просроченных overdue событий.
  • Action Scheduler: pending стабилен, failed не растёт.
  • Отложенная публикация и Woo order emails уходят вовремя.
  • В access-логе нет сотен хитов /wp-cron.php с интернета (если закрыли nginx).
  • В runbook сервера записана строка crontab и путь к PHP/CLI.
  • После деплоя плагинов — разовый wp cron event run --due-now на staging.

Итог

На VPS virtual WP-Cron — legacy-удобство, не продакшен-стратегия. Пара строк в wp-config.php и одна строка в crontab дают предсказуемый фон для Woo, форм и рассылок. Это логичное продолжение после Redis и мониторинга: сначала ускоряете и наблюдаете, потом убираете «случайный» запуск задач из визита бота.

Как у вас сейчас — чистый WP-Cron на хите или уже system cron? Напишите в комментариях на web7.pro — подскажу интервал под ваш стек.

Плагин рейтинга создан автором этого блога. Буду очень признателен, если вы сможете его поддержать (ссылка)

p.s. Если статья была полезной и вас переполняет чувство благодарности, можете поддержать меня долларом на патреоне

Об авторе

Web Developer. I have expirience in FrontEnd, Backend, Devops. PHP, Python, Javascript (Vue.js, React.js)

Все статьи