wp_schedule_event() — при помощи WP_Cron создаём задачу, выполняющуюся регулярно через заданные промежутки времени

Цель этой статьи — показать на простых примерах и целиком разобраться в том, как в WordPress запланировать задачу (функцию), которая будет выполняться регулярно через заданный вами промежуток времени.

Прежде, чем перейти к примерам, взглянем на саму функцию.

wp_schedule_event( $timestamp, $recurrence, $hook, $args = array())
$timestamp
(целое число) Время в UNIX формате, в которое задача выполнится в первый раз. На UNIX формате времени я уже подробно останавливался в предыдущей статье.
$recurrence
(строка) Интервал времени, через который задача будет выполняться вновь, однако этот параметр не позволяет задать непосредственно временной промежуток, он работает только с уже предопределёнными интервалами, то есть вам следует указать имя интервала, по умолчанию доступны:

  • hourly — ежечасно,
  • twicedaily — дважды в день, а если точнее, то каждые 12 часов,
  • daily — ежедневно.

Но вы также легко и просто можете создать свой собственный интервал, о том как — читайте ниже.

$hook
(строка) Название хука, который запустится функцией wp_schedule_event(), после чего уже будут выполнены все функции, которые привязаны к этому хуку. Если вы не знакомы с хуками, то это предложение может показаться вам непонятным — не стоит беспокоиться, на примерах ниже всё будет показано наглядно.
$args
(массив) Массив параметров, которые будут переданы в хук, а соответственно и во все привязанные к нему функции.

Примеры

1. Каждый час отправляем email.

Не спрашивайте зачем, основная цель — показать, как всё это работает, а там вы уже и сами свои функции подставить сможете. Письма мы будем отправлять через стандартную WP функцию wp_mail().

// функция, привязанная к хуку, понятное дело, что их может быть несколько
function true_otpravka_email() {
	wp_mail('true@truemisha.ru','Тема тестового письма','Тестовое сообщение');
}
 
// собственно вот он и хук, true_hook_1
add_action('true_hook_1', 'true_otpravka_email');
 
// time() - текущее время в UNIX-формате, то есть в первый раз задача выполнится моментально
if( !wp_next_scheduled('true_hook_1') )
	wp_schedule_event( time(), 'hourly', 'true_hook_1');

Так как код мы отправляем в functions.php и так как у функции wp_schedule_event() нет никакой встроенной проверки на дубликаты задач, мы сами проверяем, не было ли уже запланировано событие при помощи wp_next_scheduled(), которая возвращает false, если указанный хук ещё не был запланирован, либо же UNIX-время его следующего выполнения.

У этого примера есть и альтернативный вариант — вариант, который позволят на каждый email (тему/сообщение) запланировать уникальную задачу.

// видите, мы не создаём никаких дополнительных функций, а wp_mail вешаем на хук напрямую
add_action('true_hook_1', 'wp_mail', 10, 3);
 
$parametri = array( 'true@truemisha.ru','Тема тестового письма','Тестовое сообщение' );
 
// если хотя бы один из вышеуказанных параметров изменится, хук уже будет считаться уникальным и запланируется снова
if( !wp_next_scheduled('true_hook_1', $parametri ) )
	wp_schedule_event( time(), 'hourly', 'true_hook_1', $parametri );

2. Регистрируем собственный интервал времени и отправляем себе письмо каждые два часа.

Единственное, что вам понадобится для создания собственного интервала, это вспомнить таблицу умножения, а именно то, что в минуте 60 секунд, в часе 3600, в дне 86400, в неделе 604800, в месяце… пожалуй стоит притормозить.

// создание интервала делается на раз-два при помощи хука cron_schedules
add_filter( 'cron_schedules', 'true_moi_interval'); 
 
function true_moi_interval( $raspisanie ) {
	// как я уже упоминал в заголовке, будем высылать письмо каждые два часа, если торопитесь - поставьте раз в две минуты
	$raspisanie['kajd_2_chas'] = array(
		'interval' => 7200,
		'display' => 'Каждые два часа'
	);
	/* пример еженедельного интервала
	$raspisanie['nedelya'] = array(
		'interval' => 604800,
		'display' => 'Раз в неделю'
	);
	*/
	return $raspisanie;
}
 
// ну а дальше уже всё то же самое, что мы делали, только уже с другим интервалом
add_action('true_hook_1', 'wp_mail', 10, 3);
 
$parametri = array( 'true@truemisha.ru','Тема тестового письма','Тестовое сообщение' );
 
if( !wp_next_scheduled('true_hook_1', $parametri ) )
	wp_schedule_event( time(), 'kajd_2_chas', 'true_hook_1', $parametri );

3. Как просмотреть, какие задачи запланированы и как отменить их выполнение?

На этом я тоже уже подробно останавливался в предыдущей статье, про просмотр задач тут, а про снятие их с регистрации тут.

Миша

В последние годы я долго не знал, что мне делать с сайтом misha.blog, ведь он практически не приносит никакого профита, но недавно я осознал, что моя миссия – способствовать распространению WordPress. Ведь WordPress – это лучший движок для разработки сайтов – как для тех, кто готов использовать заложенную структуру этой CMS, так и для тех, кто предпочитает headless решения.

Сам же я впервые познакомился с WordPress в 2009 году. Организатор WordCamp. Преподаватель в школах Epic Skills и LoftSchool.

Если вам нужна помощь с вашим сайтом или может даже разработка с нуля на WordPress / WooCommerce — пишите. Я и моя команда сделаем вам всё на лучшем уровне.

Комментарии — 6

Комментирование этого поста более не доступно.
  • Алексей 2 февраля 2020 #

    Доброго дня Михаил! Надоели плагины, пытаюсь освоить основы WP PHP и сейчас ищу код, как доработать функцию для автоматической смены роли по подписке.

    На сайте, имеется функция, которая изменяет роль после оплаты конкретного товара WooCommerce. Был Lead, стал ViP.

     
    add_action( 'woocommerce_order_status_completed', 'change_role_on_vip' );
    function change_role_on_vip( $order_id ) {
        $order = wc_get_order( $order_id );
        $items = $order->get_items();
     
        $products_to_check = array( '3420' ); // id товара WooCommerce
     
        foreach ( $items as $item ) {
            if ( $order->user_id > 0 && in_array( $item['product_id'], $products_to_check ) ) {
             $user = new WP_User( $order->user_id );
     
             // заменить роль
             $user->remove_role( 'lead' );
             $user->add_role( 'vip' );
     
                // окончание цикла
                break;
         }
        }
    }

    Как дополнить эту функцию условием: оплата по подписке (автоматическая смена роли).

    Например, оплатил тариф 15-го числа текущего месяца и ему включается роль vip на месяц или год в зависимости от id товара.

    По истечении времени, автоматически сбрасывается на роль: lead.

    Промежуток времени задается не числом (30 дней, 365 дней), а именно датой оплаты и подписка должна продлеваться от даты до даты. Например, и в феврале (28 дней) и в мае (31 день) одинаково продлевается 15-го числа.

    Условие: подписка должна продлеваться в день текущей оплаты. То есть, истек срок на 15-е, повисел в роли: lead и продлил 25-го. Новый цикл начался с 25-го по 25-е.

    * * *

    Что удалось найти в интернете:

     
    if ( ! wp_next_scheduled( 'alter_user_role_hook' ) ) {
      wp_schedule_event( strtotime('tomorrow'), 'daily', 'alter_user_role_hook' );
    }
    function alter_user_role_function() {
      global $wpdb;
      $today = date('Y-m-d H:i:s',strtotime('today'));
      $expired = $wdpb->get_col("SELECT user_id FROM {$wpdb->usermeta} WHERE expired_key <> $uid,
              'role' => 'havent_paid'
            )
          );
        }
      }
    }
    add_action( 'alter_user_role_hook', 'alter_user_role_function' );

    * * *

    Как связать два предложенных кода в один? Или создать доработать любой из них.

    * * *

    • Миша 2 февраля 2020 #

      Здравствуйте!

      Спасибо за классный вопрос! А можно уточнить, подписка у вас чем реализуется? WooCommerce Subscriptions?

      • Алексей 2 февраля 2020 #

        Спасибо Михаил за оперативный ответ! Буду следить за ответами быстрее.

        Вообщем, все плагины по подписке имеют много лишних функций и запросов к БД. Я решил сильно упростить задачу. Просто меняю роль пользователя и реализую разные доступы просто ограничивая контент или функции на определенные роли.

        Сейчас, реализована покупка роли через товар ВуКоммерсе. И приходится отслеживать актуальность вручную. Требуется автоматически добавлять/удалять роль пользователя по подписке.

        Купил товар А получил роль на месяц, товар Б - роль на полгода. Время истекло, роль вернулась обратно, например: подписчик или ЛИД.

        • Миша 4 февраля 2020 #

          Ну я не всегда сразу отвечаю 🙃

          С одной стороны поддерживаю ваше решение отказаться от плагинов подписки, но с другой – нужно будет проделать много работы, чтобы всё работало и без багов. Кстати говоря, по-моему у WooCommerce какой-то свой собственный scheduler ? Или я ошибаюсь и он как раз присутствует именно в WooCommerce Subscriptions?

          • Алексей 6 февраля 2020 #

            На самом деле, требований не так уж и много, чтобы задействовать целый плагин или писать с нуля. Сейчас, роль меняется по одной функции change_role_on (1 пример выше). Просто вставляю id товара и привязываю к функции. Подписчик оплачивает и, роль автоматически меняется на ВИП.

            Теперь, просто нужно сделать так, чтобы эта роль продлевалась на месяц с дня оплаты и откатывалась обратно после истечения срока. На данном этапе, этого будет достаточно.

            Когда же стартап выйдет на уровень действующего, системного бизнеса, то можно и купить плагин WooCommerce Subscriptions. Но я его еще не изучал.

            В нем подписка создается как отдельный тип записи или изменяется роль? Мне важно именно смена роли, так как, новичку именно под роль проще менять контент и функционал сайта.

  • Алексей 2 февраля 2020 #

    Сейчас подписка не реализуется ни одним из плагинов. Только меняется роль при покупке определенных товаров. Вот и озадачился автоматически изменять роль на промежуток времени одним хуком PHP.