- Что такое WP Cron
- Как добавить событие в планировщик WP Cron
- Пример, как добавить событие в WP Cron в виде PHP класса
- Как отладить работу WP Cron
- WP Crontrol — плагин отладки WP Cron
- Недостатки WP Cron
- Как правильно отключить WP Cron
- Как заменить WP Cron на серверный планировщик cron
- Настройка серверного cron для WordPress MultiSite MU
- Ошибки, связанные с WP Cron
- There was a problem spawning a call to the WP-Cron system on your site
- Убираем doing_wp_cron из URL
- Я отключил WP Cron, но в логах access.log снова появляется POST /wp-cron.php?doins_wp_cron?параметры
- WP Cron очень сильно тормозит, валятся ошибки, что делать?
Что такое WP Cron
WP Cron — это встроенный в ядро WordPress планировщик, позволяющий выполнять различные задачи строго по заранее заданному расписанию, например:
- Публикация запланированных записей;
- Проверка обновлений ядра WordPress;
- Проверка обновлений плагинов (если плагин зарегистрирован в репозитории плагинов WordPress);
- Проверка обновлений тем (если тема есть в репозитории тем WordPress);
- Рассылка email уведомлений;
- И прочее подобное.
Преимущество WP Cron в том, что он абсолютно не зависит от настроек сервера и будет работать на любой платформе. Про недостатки будет ниже, когда дойдём до оптимизации настроек, а пока пару примеров, как создать и добавить своё событие в планировщик.
Как добавить событие в планировщик WP Cron
Ключевые функции:
wp_schedule_single_event( time() + 3 * DAY_IN_SECONDS, "sheensay_once_event" );
- Используется для добавления одноразового события. Пример выше выполнится через 3 дня, запустив
sheensay_once_event
wp_schedule_event( time(), 'hourly', "sheensay_regulat_event" );
- Используется для регулярного события. Пример выше стартует прямо сейчас, повторяется раз в час, выполняя
sheensay_regulat_event
А теперь перейдём к практике. Нижеуказанный код можно вставить в functions.php или создать MU плагин
// 0 шаг - можно (но не обязательно) добавить свой интервал, например, 6 часов add_filter( 'cron_schedules', function ( $schedules ) { $schedules['every6hours'] = array( // HOUR_IN_SECONDS - специальная константа, содержит число секунд в 1 часе. Умножаем на 6 часов. 'interval' => 6 * HOUR_IN_SECONDS, 'display' => __( 'Every 6 hours' ), ); return $schedules; } ); // 1 шаг - добавляем в WP Cron новое событие add_action( 'init', function () { // Если событие ещё не зарегистрировано в планировщике if ( !wp_next_scheduled( 'sheensay_new_event' ) ) { // Добавляем событие, стартуя прямо сейчас, с периодом "hourly" (раз в час). А назовём его sheensay_new_event wp_schedule_event( time(), 'hourly', 'sheensay_new_event' ); // Если нужно одноразовое событие, то раскомментируем wp_schedule_single_event, а wp_schedule_event (выше) закомментируем // Событие сработает через 1 час. Можно настроить свой интервал //wp_schedule_single_event( time() + 1 * HOUR_IN_SECONDS, 'sheensay_new_event' ); // Если на 0 шаге добавили свой интервал, то можно использовать его. В нашем случае: "every6hours" (каждые 6 часов) //wp_schedule_event( time(), 'every6hours', 'sheensay_new_event' ); // wp_schedule_event( strtotime('03:00:00'), 'hourly', 'sheensay_new_event' ); // Стартуем в 3 ночи } }); // 2 шаг - описываем подробно, что будем делать, когда наступит очередь событие исполнять "sheensay_new_event" add_action( 'sheensay_new_event', function () { // Допустим, нужно удалять все Записи старше 10 дней // Получим все Записи $p = get_posts( [ 'post_type' => 'post', 'posts_per_page' => -1, ] ); // Если записи есть, переберём их if ( $p ) { foreach ( $p as $post ) { // 10 дней живёт запись $days = 10; // DAY_IN_SECONDS - сколько секунд в 1 дне - это специальная константа, определённая в WordPress $offset = $days * DAY_IN_SECONDS; // Если Запись старше, чем 10 дней, удаляем её if ( get_post_time( $d = 'U', $gmt = TRUE, $post ) < time() - $offset ) { // Удаляем Запись в корзину, оттуда она позже удалится автоматически wp_delete_post( $post -> ID ); } } unset( $post ); } } );
Полный список волшебных констант времени в WordPress:
- MINUTE_IN_SECONDS — число секунд в минуте;
- HOUR_IN_SECONDS — число секунд в часе;
- DAY_IN_SECONDS — число секунд в дне;
- WEEK_IN_SECONDS — число секунд в неделе;
- MONTH_IN_SECONDS — число секунд в месяце;
- YEAR_IN_SECONDS — число секунд в году.
Это был абстрактный пример. Вы можете легко адаптировать схему под себя.
А для отладки, чтобы понять, работает ли код, я рекомендую использовать следующие подходы.
Пример, как добавить событие в WP Cron в виде PHP класса
final class Sheensay_Test_WP_Cron { function __construct() { // Добавление в планировщик cron задания add_action( 'init', [ $this, 'add_wp_cron_event' ] ); // Хук, за который цепляется планировщик, когда приходит время срабатывать add_action( 'sheensay_new_event', [ $this, 'sheensay_new_event__callback' ] ); /** * Добавление в планировщик cron задания * */ function add_wp_cron_event() { $timezone = get_option( 'timezone_string' ); // Если событие ещё не зарегистрировано в планировщике if ( !wp_next_scheduled( 'sheensay_new_event' ) ) { // Добавляем его, стартуя в 21:00 по часовому поясу сайта, с периодом "daily (раз в сутки)" wp_schedule_event( strtotime( '21:00 ' . $timezone ), 'daily', 'sheensay_new_event' ); } } /** * Callback */ function sheensay_new_event__callback() { // Тут запускаем функционал по крону error_log( $message = 'Привет из sheensay_new_event__callback :-) ' ); } } } new Sheensay_Test_WP_Cron();
Как отладить работу WP Cron
WP Cron запускает данные асинхронно, поэтому чтобы отладить его работу, можно воспользоваться следующим (за основу берём код выше, то есть, у нас уже есть add_action( 'sheensay_new_event', function () {...
:
-
Добавляем PHP код:
add_action( 'admin_action_sheensay_cron_debug', 'sheensay_new_event' );
- Теперь открываем в браузере
http://example.com/wp-admin/admin.php?action=sheensay_cron_debug
(вместоexample.com
наш сайт); - Код вызовет хук
sheensay_new_event
, и мы получаем результат сразу же, не дожидаясь наступления события, прописанного в планировщике.
Но, на мой взгляд, в целях отладки гораздо удобнее пользоваться специальным плагином WP Crontrol
WP Crontrol — плагин отладки WP Cron
WP Crontrol — это очень полезный плагин, который позволяет:
- Просматривать все события WP Cron вместе с аргументами, периодичностью повторений, функциями, которые они вызывают (callback), а также их запланированными действиями;
- Редактировать, удалять, а также запускать сиюминутно любое событие крона (очень сильно выручает при отладке событий);
- Добавлять новые события в расписания;
- Добавлять, редактировать и удалять собственные расписания в WP Cron.
Очень рекомендую использовать, всё наглядно и удобно.
Скачать WP Crontrol из официального репозитория Wordress.org
Итак, возвращаясь к предыдущей теме, если добавили код из вышеуказанного примера, то в списке событий Events http://example.com/wp-admin/tools.php?page=crontrol_admin_manage_page
должно появиться новое событие sheensay_new_event
Если событие sheensay_new_event не появилось, попробуйте загрузить любую страницу сайта с фронтенда, например, главную. Тогда сработает хук wp, и событие добавится в планировщик.
Теперь достаточно справа от нужного события нажать на Run Now и проверить результат (в нашем случае, не отправились ли старые записи в корзину).
Как видите, эта тема довольно проста в освоении. Если возникнут дополнительные вопросы, задавайте в комментариях. Далее, про настройку и оптимизацию WP Cron.
Недостатки WP Cron
Вся суть механизма работы встроеного планировщика заключается в том, что при каждом посещении сайта на WordPress любым пользователем идёт обращение к файлу wp-cron.php
. Тот, в свою очередь, при каждом обращении проверяет расписание, и если время исполнения какого-то события в очереди наступило или уже прошло, то запускает его. Отсюда, понятно, какие могут быть недостатки у данного подхода:
- Если у сайта большой трафик, то обращения к WP Cron будут слишком частыми, избыточными, что на сайтах с большой нагрузкой трафика может вызывать некоторые проблемы с производительностью сервера;
- Если у сайта мало посетителей, то WP Cron может сильно запаздывать в работе.
Отсюда вывод — если есть возможность, постарайтесь настроить серверный cron взамен встроенному, а встроенный WP Cron отключить (инструкция будет далее).
Как правильно отключить WP Cron
в wp-config.php
находим строку define( 'WP_DEBUG', false );
и под ней прописываем:
define('DISABLE_WP_CRON', true);
Если отключить стандартный WP Cron, строго необходимо настроить ему замену, так как иначе перестанут выполняться задачи по расписанию, например, не будут опубликовываться запланированные записи. Идеально подойдёт серверный планировщик задач, обычный cron, который есть в любом нормальном сервере (подробнее далее).
Как заменить WP Cron на серверный планировщик cron
Сначала отключаем WP Cron, в wp-config.php
прописываем где-нибудь в начале файла, как было в примере выше:
define('DISABLE_WP_CRON', true);
Затем запускаем команду в консоль SSH
crontab -e
Откроется файловый редактор планировщика cron со всеми существующими расписаниями.
Далее, есть несколько вариантов (выберите один из них, я рекомендую первый):
- Используем WP CLI
-
* * * * * cd /var/www/example.com/public_html; /usr/local/bin/wp cron event run --due-now --allow-root > /dev/null 2>&1
Здесь мы каждую минуту командой
cd /var/www/example.com/public_html
переключаемся в каталог с файлами сайта (в корень сайта), аwp cron event run --due-now --allow-root
делаем запрос php кwp-cron.php
с помощью WP CLI.
Это вариант имеет свои тонкости: php тут запускается из консоли, и потому пригодится, скажем, если на сервере закрыты порты 80 или 443, и wget или curl бессильны.WP CLI
работает в режимеPHP-CLI
, а значит, что на исполнение php нет временных лимитов. Это означает:- Все задания гарантированно исполнятся;
- Если какое-то из заданий, в силу ошибок синтаксиса или иных, не может завершить свою работу, это может вызвать проблемы.
Поэтому, тут решайте самостоятельно, взвесив плюсы и минусы, выбирать ли
WP CLI
или нет. - Или используем
php
-
* * * * * cd /var/www/example.com/public_html; php wp-cron.php doing_wp_cron > /dev/null 2>&1
Здесь мы каждую минуту командой
cd /var/www/example.com/public_html
переключаемся в каталог с файлами сайта (в корень сайта), аphp wp-cron.php
делаем запрос php кwp-cron.php
Это вариант с php пригодится, скажем, если на сервере закрыты порты 80 или 443, и wget или curl бессильны. - Или используем
wget
-
* * * * * wget http://example.com/wp-cron.php?doing_wp_cron > /dev/null 2>&1
Это правило каждую минуту с помощью wget обращается к файлу крона
http://example.com/wp-cron.php?doing_wp_cron
WordPress, тем самым заставляя регулярно запускаться запланированные в WP Cron события.- Из плюсов — wget стоит практически на любой машине по умолчанию.
- Из минусов — его разработка ведётся долго, и потому он не поддерживает нормально https и другие некоторые опции, доступные curl. К тому же, проблемы могут возникнуть, если запросы к сайту блокируется по портам.
- Или используем
curl
-
* * * * * curl -O http://example.com/wp-cron.php?doing_wp_cron > /dev/null 2>&1
Это правило каждую минуту будет посылать запросы с помощью curl к
http://example.com/wp-cron.php?doing_wp_cron
.- Плюсы curl — это продвинутый вариант wget, много опций с возможностью менять протоколы, user-agent, принудительный TLS, возможность сжимать ответ и многое другое.
- Минусы — не всегда идёт по умолчанию с ПО сервера, и нужно устанавливать отдельно. Однако, в Ubuntu и Debian делается это легко:
apt-get install curl php5-curl
- Ещё минус — бывает, что сервер не принимает запросы (например, защита от парсеров)
Одну из вышеуказанных команд добавляете в конце файла (example.com
заменяете на свой домен).
Работаем в putty. Инструкция для стандартного редактора nano (не vim, для vim инструкция ниже):
- Прописываем одну из вышеуказанных команд;
- Выходим Ctrl+X;
- На выходе спросят, сохранять ли изменения. Сохраняем Y;
- Имя файла для записи — оставляете без изменения — Enter;
- Если увидите подпись
crontab: installing new crontab
, значит изменения были сохранены
Если редактором выступает vim:
- Включам режим редактирования — Insert;
- Вносим правила в конец файла (примеры рассматривали выше);
- После внесения изменений отключаем режим редактирования — Esc;
- Сохраняем изменения — Shift+: (двоеточие), в появившемся поле вводим
wq
и сохраняем Enter;- Если увидите ответ
crontab: installing new crontab
, значит изменения были сохранены и вступили в силу.
Чтобы выбрать подходящий редактор, можно воспользоваться командой
select-editor
Если хотите проверить, применились ли изменения к расписанию крона, воспользуйтесь командой
crontab -l
Если у вас есть панель управления хостингом, возможно, там есть функционал, позволяющий задавать собственное расписание для планировщика cron. В таком случае, просто пропишите там правило обращаться раз в 5 минут к адресу
http://example.com/wp-cron.php?doing_wp_cron
(подставьте свой домен вместоexample.com
).
Настройка серверного cron для WordPress MultiSite MU
Если у вас сборка WordPress Multisite, то подходы выше не подойдут.
Самый лучший вариант — это в консоли SSH открыть Crontab командой crontab -e
и вписать:
* * * * * cd /var/www/example.com/data/www/example.com; /usr/local/bin/wp site list --field=url --allow-root | xargs -n1 -I \% /usr/local/bin/wp --url=\% cron event run --due-now --allow-root
Что это всё значит — серверный cron будет делать следующее:
- * * * * *
- Делаем запрос каждую минуту.
- cd /var/www/example.com/data/www/example.com;
- Переходим в вышеуказанную директорию
/var/www/example.com/data/www/example.com
— тут нужно указать абсолютный путь к корню сайта WordPress. - /usr/local/bin/wp site list —field=url —allow-root
- Получаем список сайтов сети WordPress Multisite.
- |
- Передаём результат команды
wp site list
командеxargs
— утилите, которая принимает строки ввода и передает их следующей команде. - xargs -n1 -I \% /usr/local/bin/wp —url=\% cron event run —due-now —allow-root
- Команда будет последовательно для каждого сайта из списка выполнять команду:
wp --url=\% cron event run --due-now --allow-root
. Вместо \% будет подставляться URL сайта сети WP MU.
Если в целях дебага нужно отследить работу этой команды, можно включить лог, добавив в конце строки
>> /root/wp-cron_log.txt 2>&1
, тогда результат работы команды будет писаться в файл/root/wp-cron_log.txt
(можно указать другой путь и файл):* * * * * cd /var/www/example.com/data/www/example.com; /usr/local/bin/wp site list --field=url --allow-root | xargs -n1 -I \% /usr/local/bin/wp --url=\% cron event run --due-now --allow-root >> /root/sensorLog.txt 2>&1
Осталось отключить WP Cron
в файле wp-config.php
в корне сайта:
define('DISABLE_WP_CRON', true);
Крайне рекомендую вариант выше, он надёжнее нижеследуюшего.
Ещё один вариант, если не подошёл вариант выше — это создать файл mu-cron.php
и положить его в корень сайта рядом с wp-load.php
.
Код файла mu-cron.php
ниже:
<?php /** * Настройка серверного Cron для WordPress Multisite * * @author Sheens * @link https://sheensay.ru/wp-cron * **************************** */ // Подключаем ядро WordPress require 'wp-load.php'; // Инициализируем подключение к базе данных mysql global $wpdb; // Получаем список сайтов в сети WordPress MU $blogs = $wpdb -> get_results( "SELECT domain, path FROM {$wpdb -> blogs} WHERE archived='0' AND deleted ='0' " ); // Перебираем сайты WordPress foreach ( $blogs as $blog ) { // Получаем строку вида: http://example.com/wp-cron.php $cron_url = "http://" . $blog -> domain . ($blog -> path ? $blog -> path : '/') . 'wp-cron.php'; // Делаем запрос curl на вышеуказанный адрес $ch = curl_init( $cron_url ); curl_setopt( $ch, CURLOPT_HEADER, 1 ); curl_setopt( $ch, CURLOPT_FOLLOWLOCATION, 1 ); curl_setopt( $ch, CURLOPT_RETURNTRANSFER, 0 ); $result = curl_exec( $ch ); curl_close( $ch ); }
Теперь настраиваем серверный Cron
. Команда для консоли:
crontab -e
И туда вписываем:
# Настраиваем серверный крон для WP MU через wget * * * * * wget http://example.com/mu-cron.php -O /dev/null
Или через IP своего сервера
# Вместо 1.2.3.4 подставляем IP сервера, а вместо example.com - свой домен * * * * * wget http://1.2.3.4/mu-cron.php --header="Host: example.com" -O /dev/null
Ну, и конечно же, не забываем отключить нативный WP Cron
в файле wp-config.php
в корне сайта:
define('DISABLE_WP_CRON', true);
Ошибки, связанные с WP Cron
There was a problem spawning a call to the WP-Cron system on your site
There was a problem spawning a call to the WP-Cron system on your site. This means WP-Cron events on your site may not work. The problem was: cURL error 7: Failed to connect example.com port 80 443: connection refused
Ошибка выше означает, что curl не может получить доступ к сайту по стандартным портам 80
или 443
.
Вы можете решить эту проблему, включив альтернативный вариант для работы WP Cron, прописав в wp-config.php
:
define('ALTERNATE_WP_CRON', true);
Однако, у этого подхода есть недостаток — иногда к адресам страниц будут добавляться параметры ?doing_wp_cron=
. Если Вас это не смущает, выбирайте его, он самый простой в настройке. Если нет — расскажу, как убрать doing_wp_cron
из адреса страницы и настроить серверный планировщик cron взамен WP Cron.
Убираем doing_wp_cron из URL
?doing_wp_cron= появляется в адресе страницы, когда используется альтернативная версия ALTERNATE_WP_CRON
, то есть, в корне сайта в файле wp-config.php
определена константа:
define('ALTERNATE_WP_CRON', true);
Как правило, её включают, когда WP Cron не работает в стандартном варианте. Вам нужно постараться избежать её использования:
// Отключаем альтернативную версию WP CRON define('ALTERNATE_WP_CRON', false);
Если WP Cron не заработает или будет выдавать ошибку в работе, можно полностью отключить WP Cron и использовать серверный крон (подробнее были выше).
Также, не лишним будет настроить редирект с ?doing_wp_cron=
на оригинальную версию страницы:
- Как сделать редирект из ?doing_wp_cron= в NGINX
-
# В секции location / location / { # ... if ( $arg_doing_wp_cron ) { # Если в query string есть запрос ?doing_wp_cron= return 301 $uri; # Редиректим на основной адрес } # Тут обычно далее идёт try_files $uri $uri/ /index.php?$args # ... }
- Как сделать редирект из ?doing_wp_cron= в .htaccess (Apache)
-
# Прописываем блок в самом начале .htaccess <IfModule mod_rewrite.c> RewriteEngine On RewriteCond %{QUERY_STRING} (^|&)doing_wp_cron= [NC] RewriteRule (.*) /$1? [R=301,L] </IfModule>
Я отключил WP Cron, но в логах access.log снова появляется POST /wp-cron.php?doins_wp_cron?параметры
Бывает так, что, казалось бы, WP Cron отключен (всё сделано по инструкции выше), однако, в логах всё равно появляются отметки о том, что идут стандартные запросы
127.0.0.1 - - [08/Jun/2017:06:38:49 +0300] "POST /wp-cron.php?doing_wp_cron=1496893129.1262209415435791015625 HTTP/1.0" 200 236 "https://sheensay.ru/wp-cron.php?doing_wp_cron=1496893129.1262209415435791015625" "WordPress/4.7.5; https://sheensay.ru"
Дело в том, что тут может быть так, что Вы неверно прописали отключение WP Cron, а именно, строку define('DISABLE_WP_CRON', true);
прописали в самом конце файла wp-config.php
. Обязательно перенесите её к define('WP_DEBUG', false);
:
define( 'WP_DEBUG', false ); define( 'DISABLE_WP_CRON', true );
Далее, попробуйте очистить все запланированные задания (об этом ниже).
WP Cron очень сильно тормозит, валятся ошибки, что делать?
Для начала, установите плагин WP Crontrol (про него описано выше). Затем зайдите в Инструменты — Cron Events (http://example.com/wp-admin/tools.php?page=crontrol_admin_manage_page
):
В норме, вы увидите примерно следующее:
Если страница не открывается, либо открывается, но в её таблице очень много позиций, значит, стоит их очистить.
Самое простое: через functions.php:
- Открываете functions.php и прямо в самом начале файла под
<?php
прописываете:<?php update_option('cron', '');
и сохраняете результат;
- Открываете любую страницу сайта;
- Возвращаетесь в
functions.php
и удаляете строкуupdate_option('cron', '');
, сохраняете результат; - Снова открываете Инструменты — Cron Events и смотрите, таблица должна придти в норму (быть пустой или иметь мало значений).
Всё, теперь WP Cron должен работать нормально. Но я советую отключить его и настроить серверный планировщик (инструкция выше), тогда сайт будет работать, как часы.
Свежие комментарии