WordPress cron + Crontrol + Events Calendar plugin

Займемся созданием планировщика для WordPress, который будет отправлять почту и смс о предстоящих событиях. Используем api wp-cron.php в связке с плагином Crontrol. Скрипт будет брать события, созданные в категории Events Calendar WD (плагин). Далее проверит события за текущий день, завтрашний, а также на всю неделю вперед.


Событие регистрируется как wp_schedule_event(). Оно проверяется на хите, т.е. надо будет запускать его серверным кроном, обращаясь к wp-cron.php( оставим на финал статьи). В параметрахwp_schedule_event() передается точка отсчета крона, частота, хук. Перед запуском события надо проверить не выполнялось ли оно ранее
!wp_next_scheduled(‘name’)
К хукам добавим функции
add_action(‘hook_name’ , ‘func_name’);
Крон запустит хук, хук — функцию, функции проверят события в календаре. Если найдутся совпадения — отправиться уведомление на почту и по смс.
Поместим скрипт планировщика в отд. файл. cron_tasks.php


// functions.php
require_once( get_template_directory() . '/inc/cron_tasks.php' );

Зарегистрируем 3 события.


$date1 = new DateTime("now");
if( !wp_next_scheduled('weekly_hook') ){
    // события календаря от понедельника на неделю
    $monday = new DateTime("monday this week");
    $week_date = $monday->setTime("10","00","00");
    wp_schedule_event( $week_date->getTimestamp() , 'weekly', 'weekly_hook');
}
if( !wp_next_scheduled('daily_hook') ) {
    // ежедневная проверка
    $day_date = $date1->setTime("10","00","00");
    wp_schedule_event( $day_date->getTimestamp() , 'daily', 'daily_hook');
}
if( !wp_next_scheduled('daily_tomorrow_hook') ) {
    // проверка событий на завтра
    $day_date = $date1->setTime("18","00","00");
    wp_schedule_event( $day_date->getTimestamp() , 'daily', 'daily_tomorrow_hook');
}

Назначим функции для хуков


add_action('weekly_hook' , 'weekly_func');
add_action('daily_hook' , 'daily_func');
add_action('daily_tomorrow_hook' , 'daily_tomorrow_func');

Ниже сами функции


/**
 * еженедельно
 */
function weekly_func(){
    $monday = new DateTime("monday this week");
    $week_date = $monday->setTime("10","00","00");
    check_posts($week_date->format("Y-m-d H:i:s"), "week");
}

/**
 * ежедневно
 */
function daily_func(){
    $date_today = new DateTime("now");
    $date_today->setTime("9","00","00");
    check_posts($date_today->format("Y-m-d"), "day");
}

/**
 * на завтра
 */
function daily_tomorrow_func(){
    $date_today = new DateTime("now");
    $date_today->add(new DateInterval('P1D'));
    $date_today->setTime("21","00","00");
    check_posts($date_today->format("Y-m-d"), "tomorrow");
}

Они вызывают калбек check_posts(), к-й проверяет наличие запланированных событий. check_posts()в параметрах принимает точку отсчета и период.
Получим события календаря для проверки их актуальности.


// посты типа ecwd_event
$args = array(
    'posts_per_page' => -1,
    'orderby'     => 'date',
    'order'       => 'DESC',
    'include'     => array(),
    'exclude'     => array(),
    'post_type'   => 'ecwd_event',
    'suppress_filters' => true,
);

$posts = get_posts( $args );

Пробегаясь по массиву постов типа ecwd_event, проверяем даты этих постов from и to методами check_week_interval() и check_day_interval(). В параметрах check_xxx_interval() — дата когда крон выполнился (сегодня) и интервал поста-события. Событие календаря может длиться несколько дней.
Забегая вперед, если условие сработало — формируется тело письма и отправляется смс-почта.


/**
 * @param $cron_date
 * @param $period
 */
// проверка актуальных постов
function check_posts($cron_date, $period){
    global $posts, $body_week, $body_day, $body_day_tomorrow, $body_week_text , $body_day_text;
    foreach($posts as $post){
        $post_meta = get_post_meta($post->ID, '', true);
        // посты типа ecwd_event
        $from_date = $post_meta["ecwd_event_date_from"][0];
        $to_date =  $post_meta["ecwd_event_date_to"][0];

        // еженедельная проверка
        if($period == "week"){
            if(check_week_interval($cron_date, $from_date)){
                $from_date = new DateTime($from_date);
                $body_week .= "".$post->post_title." ".
                    "начало в ".$from_date->format("d.m").";
 ";
                $body_week_text = true;
            }
        }// ежедневная проверка
        else if($period == "day"){
            if(check_day_interval($cron_date, $from_date, $to_date)){
                $from_date = new DateTime($from_date);
                $body_day .= "".$post->post_title." ".
                    "начало в ".$from_date->format("H:i").";
 ";
                $body_day_text = true;
            }
        }// проверка завтрашнего дня
        else if($period == "tomorrow"){
            if(check_day_interval($cron_date, $from_date, $to_date)){
                $from_date = new DateTime($from_date);
                $body_day_tomorrow .= "".$post->post_title." ".
                    "начало в ".$from_date->format("H:i").";
 ";
                $body_day_tomorrow_text = true;
            }
        }
    }

    if($body_week_text == true && $period == "week"){
        send_email_sms($body_week);
    }
    if($body_day_text == true && $period == "day"){
        send_email_sms($body_day);
    }
    if($body_day_tomorrow_text == true && $period == "tomorrow"){
        send_email_sms($body_day_tomorrow);
    }
}

Рассмотрим проверку интервалов постов.


/**
 * @param $cron_date
 * @param $from_date
 * @return bool
 */
function check_week_interval($cron_date, $from_date){
    return strtotime($from_date) >= strtotime($cron_date) && strtotime($from_date) <= strtotime($cron_date) + WEEK_IN_SECONDS + 60*60*6 ;
}

WEEK_IN_SECONDS — это константа WP. Еженедельная проверка осуществляется в рамках недели, т.е. дата начала события ($from_date) должна быть в интервале недели от ПН. Ежеденная проверка же — в рамках события-поста.


/**
 * @param $cron_date
 * @param $from_date
 * @param $to_date
 * @return bool
 */
function check_day_interval($cron_date, $from_date, $to_date){
    // интервал преобразуется в ранжированный массив
    $dates_range = dateRange($from_date, $to_date);
    return in_array($cron_date, $dates_range);
}

Ранжирование временного периода поста


/**
 * @param $first
 * @param $last
 * @param string $step
 * @param string $format
 * @return array
 */
function dateRange($first, $last, $step = '+1 day', $format = 'Y-m-d' ) {
    $dates = array();
    $current = strtotime($first);
    $last = strtotime($last);
    while( $current <= $last ) {
        $dates[] = date($format, $current);
        $current = strtotime($step, $current);
    }
    return $dates;
}

Если сегодняшний день в пределах рамок события календаря — значит событие надо добавить в рассылку. check_day_interval() вернет true.
Итак, проверки интервалов завершились, сформировались тела сообщений. Начало сообщений общее, поэтому заранее выносим его.


$body_week = "<p>Здравствуйте! На следующей неделе запланировано: </p>";
$body_day = "<p>Здравствуйте! Сегодня запланировано: </p>";
$body_day_tomorrow = "<p>Здравствуйте! На завтра запланировано: </p>";
$body_week_text = $body_day_text = $body_day_tomorrow_text = false;

Сработал колбек send_email_sms(). Здесь для каждого польз-ля проверяется его подписка на смс и почту.


$subject = 'mess';
$headers = array();
$headers[] = 'Content-Type: text/html; charset=UTF-8';
// $headers = 'From: aaa@aaa.ru';
$users = get_users( array() );
/**
 * @param $text
 */
function send_email_sms($text){
    global $users, $subject, $headers;
    foreach($users as $user) {
        $user_id = $user->data->ID;
        // проверка подписок
        $subscribe_sms = get_user_option('subscribe_sms', $user_id);
        $subscribe_email = get_user_option('subscribe_email', $user_id);
        $phone = get_user_option('phone', $user_id);
        $to_recepient = $user->data->user_email;
        if($subscribe_email == true) {
            wp_mail($to_recepient, $subject, $text, $headers);
        }
        if($subscribe_sms == true){
            if(!empty($phone)) {
               send_sms($text, $phone);
            }
        }
    }
}

Отправка смс отдельно


/**
 * @param $text
 * @param $phone_number
 * @return mixed
 */
function send_sms($text, $phone_number){
    $login = 'mp123456';
    $password = '123456';
    $sender = 'aaa';
    $text = strip_tags($text);
    $text = urlencode($text);
    $url = "http://api.lalala-sms.ru/messages/v2/send/?phone=%2B7$phone_number&text=$text&login=$login&password=$password&sender=$sender";
    $ch = curl_init($url);
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
    $res = curl_exec($ch);
    curl_close($ch);
    return $res;
}

По умолчанию апи wp-cron не имеет еженедельной частоты выполнения wp_schedule_event(timestamp, ‘weekly’, ‘hook’). Надо добавить weekly


add_filter( 'cron_schedules', 'true_moi_interval');

function true_moi_interval( $raspisanie ) {
    $raspisanie['weekly'] = array(
        'interval' => WEEK_IN_SECONDS,
        'display' => 'Еженедельно'
    );
    return $raspisanie;
}

Плагин crontrol покажет нам его во вкладке Настройки — Cron Schedules.
В инструментах плагин добавил вкладку Cron Events, где как раз появились наши события daily_tomorrow_hook, daily_hook, weekly_hook. Можно попробовать их запустить — Run Now.

Событие запускается на хите, но нам надо мануально. Напишем серверный крон, к-й вызовет wp-cron.php. На разных серверах и хостингах команда разная. Можно curl, wget. Пишу нечто стандартное.


*/30 * * * * wget http://example.com/wp-cron.php > /dev/null 2>&1

скачать cron_tasks.php

Leave a comment

Your email address will not be published.


*