Публикация в группе: Otshelnik-Fm - мои работы (код, плагины, дополнения, статьи и руководства)

Категории группы: Работаем с Wp-Recall

В этом уроке мы напишем не просто дополнение для WordPress плагина WP-Recall, а напишем дочернее дополнение. В качестве родительского у нас будет дополнение AutoBot Cabinet

Что значит дочернее дополнение? Это значит, что наш маленький доп будет использовать функции другого допа. Зачем так сложно? Не сложно. Наоборот - нам придется написать меньше кода. Принцип DRY - не повторяйся. Зачем писать повторно код? Зачем нам опять писать скрипт-обработчик? Зачем писать свои стили - когда уже всё это сделано?! Бери и используй.

Принцип такого подхода вас сопровождает везде:
Например вордпресс функция wp_mail() - использует php функцию mail() улучшая его под свою экосистему.
Плагин WP-Recall и его функция rcl_mail() использует вордпресс функцию wp_mail() и тоже улучшает её под себя и свою экосистему.
Дополнения используют функции ядра WP-Recall.
Другие дополнения используют функционал дополнения магазина, или чата - как дополнения Автобота.

Всё это позволяет не залезать в дебри: есть функция - она принимает аргументы, на выходе даёт результат. Это мы и будем использовать, а разработчик этой функции (он же предоставляет нам эту возможность) пусть и занимается логикой внутри функции или решает вопросы неверной работы этой функции.

Именно поэтому под вордпресс плагин WP-Recall создано более 200 дополнений - есть удобное ядро, хуки, фильтры, функции и классы - всё это позволяет зацепиться, отработать - используя уже написанный Андреем код, дописать немного своей логики - и вот дополнение готово. Конечно если строить сложные дополнения - работы всё равно много предстоит, но помощь ядра бесценна.

Дополнение AutoBot Cabinet v2.0 принесло поддержку чат-ботов. В себе доп содержит несколько функций, стили и скрипты. Я вначале начал писать независимого чат-бота. А когда перешел ко второму - то понял дублируется функционал - стили кнопок, скрипты обработчики, функции. Тут я подумал: должно быть какое-то ядро для этого, и эти повторяющиеся сущности надо выносить туда. Ну а так как дополнение автобота уже было и свободно распространяется - то он идеальный приемник всего этого. Так ядро Автобота и получили поддержку чат-ботов.

Скрипты и стили трогать не будем - их вам касаться не придется. А вот пару функций из ядра дополнения автобота я тут вначале опишу. И только потом перейдем к описанию урока: создадим чат-бота, он будет зависим от дополнения Автобота и этот чат-бот по команде будет показывать погоду в выбранном вами городе. Назовём дополнение: "Bot Weather In The City" (я специально всех ботов создаю используя в начале имя "Bot" - так они будут идти в списке дополнений в админке сайта друг за другом)

Я придерживаюсь мнения: что дополнение должно решать одну задачу - поэтому чат-ботов вышло сразу 5 штук (и вот шестой). Поддерживать такие дополнения легче - ведь в конечном счете они данные дергают из разных уголков интернета используя в некоторых случаях свои парсеры. Ну и пользователям все они разом может тоже не нужны. Поэтому было принято решение - каждый чат-бот - отдельно. Так они поселились в каталоге CodeSeller в товарной метке "Автобот"

долго запрягаю... погнали!


I часть: обзор функций ядра AutoBot Cabinet

1. Добавление кнопки

autobot_add_button($arg)

функция позволяет добавить кнопку - т.е. вы получите готовую вёрстку со своими атрибутам и подготовленную для скрипта

Стандартное применение:

$arg = [
    'icon'=>'fa-info',   // иконка с https://fontawesome.com/v4.7.0/icons/
    'text'=>'Правила',   // текст на кнопке
    'command'=>'rules',  // команда
];

- аргументы передаваемые в функцию:
Передаём аргументы: иконка, текст кнопки, команда которую будем ловить

В данном случае ответ сообщения увидят все пользователи - т.к. оно будет записано в базу данных чата.

Второй пример:
В этом примере мы добавляем параметр исключения записи в базу данных. Но в этом случае нам надо будет самостоятельно выполнить отправку пользователю - для этого укажем аргумент в "callback"

$arg = [
    'icon'=>'fa-info',   // иконка с https://fontawesome.com/v4.7.0/icons/
    'text'=>'Правила',   // текст на кнопке
    'command'=>'rules',  // команда
    'exclude_db'=> 1,    // не писать в базу данных
    'callback'=>'rul_get_rules', // если прошлый выставлен, то указываем обработчик
];

exclude_db - не писать в базу данных (ставим 1) и в этом случае в коллбеке необходимо указать имя функции, что будет отрабатывать и пересылать ajax-ом сообщение
В данном случае пользователь отправит команду в чат. Команду увидят все. Но ответ придет только ему в виде ajax-ответа. При обновлении страницы пользователь ответ не увидит - понятно почему - этот случай не пишет в базу данных.

Подобное стоит применять или для конфиденциальных данных или при больших объемах - хранить их в базе данных не нужно. Это использовать мы в данном уроке не будем - смотрите как устроено в дополнении Bot Rules - но опираясь на этот урок - тогда всё будет понятно.

2. Вёрстка для сообщения чата

Если исключаем запись в базу данных - используем функцию вёрстки сообщения чата

autobot_chat_wrapper($message)
- функция содержит в себе всю верстку чата. Вам в нее стоит передать только текст чата.

Данная функция применяется если вы указали 'exclude_db'=> 1 в функции выше. Содержит в себе аватарку, имя отправителя и обёртку для сообщения.

 

3. Константа: ID автобота

AUTOBOT_ID - константа хранит в себе идентификатор (число) юзера который назначен как автобот


II часть: пишем чат-бота

Создать дополнение для WP-Recall очень просто. Вот список уроков по этой теме:
Создаем свое дополнение для WP-Recall, выводим свою вкладку в личном кабинете
Создаём дополнение для плагина WP-Recall. Структура дополнений. Подключаем скрипты и стили. Ajax
Пишем дополнение WP-Recall — XML карта для PrimeForum


Что необходимо знать для этого урока:

1. Знание php (начальный-но-продвинутый уровень - работа с массивами, объектами, циклы, конкатенация)
2. По второму руководству я объяснял уже значение файла info.txt - в этом уроке повторять эту информацию не буду.
3. Знать как работают ВП хуки: экшены и фильтры. Понимать их предназначение и работу с ними.
4. Уметь работать с документацией по ВП функциям (описание функций, и как с ними работать - я повторять не буду)
5. Уметь работать с библиотекой SimpleXML


Структура нашего дополнения:

Как и в прошлом уроке - тут всё просто и стандартно:

info.txt - файл необходимый для подключения в списке дополнений
index.php - основной файл с кодом.

Чтобы плагин WP-Recall увидел наше дополнение на странице дополнений плагина в админке, и при включении дополнения мы получили его работу, необходимо следующее:

1. Без пробелов создать папку bot-weather-in-the-city по следующему пути:
ваш-сайт/wp-content/wp-recall/add-on/

Получится так:
ваш-сайт/wp-content/wp-recall/add-on/bot-weather-in-the-city/

2. В корне создать 2 файла в кодировке UTF-8 (без BOM) - info.txt и index.php

Дополнительно в корень дополнения вы можете положить иконку дополнения - для отображения ее в менеджере дополнений. Сделайте иконку icon.jpg размерами 50x70 пикселей и поместите ее в корне дополнения.


Содержимое файлов:

Файл info.txt:

Name: Bot Weather In The City;
Version: 1.0;
Support Core: 16.11.0;
Parent Addon: autobot-cabinet;
Description: По команде в чат выводит погоду в заданном городе;
Author: Владимир Дружаев (Otshelnik-Fm);
Author URI: https://otshelnik-fm.ru/;
Add-on URI: https://codeseller.ru/products/bot-weather-in-the-city/;

стоит пояснить некоторые строки:
3-я строка - версию указываем именно эту - именно с этой версии в плагине WP-Recall появился необходимый фильтр rcl_chat_before_form для верхней области (над формой ввода сообщения в чате). Есть еще rcl_chat_after_form - фильтр под формой ввода сообщения в чате.

4-я строка: Parent Addon: autobot-cabinet - тут мы указываем что это дополнение зависимо от допа Автобота (его slug и указываем).
Что произойдет: если у пользователя не активирован доп Автобот - то активировать наше дополнение он не сможет. Это очень хорошо - нам в коде не нужно делать проверки - активирован Автобот или нет. Мы же используем функции из автобота - а если не проверять - поймаем Fatal Error. В общем эта строка для дочерних дополнений позволяет писать еще меньше кода и проверок. Всего одна строчка - а сколько плюсов дает.

Остальные строки вам известны по прошлым урокам.

Файл index.php:

Логика:
1. выведем кнопку с нужными атрибутами для отправки команды
2. напишем перехватчик команд - поймаем нужную команду и запустим функцию
3. спарсим погоду с яндекса и чтоб не усложнять 4-й функцией - прям в ней и разложим нашу погоду как надо. Вернем все это дело во 2-ю функцию. Там проверим что ответ есть и отправим в базу данных

Шаг 1.

Первой функцией мы выведем кнопку под текстовым полем ввода сообщения в чате:

// выведем кнопку
function bwitc_add_button($out, $chat){
    if ( !is_user_logged_in() ) return $out; // гостю это не нужно
    
    if($chat['chat_status'] != 'general') return $out; // в личном чате нам кнопка не нужна

    $arg = [
        'icon'=>'fa-thermometer-half',
        'text'=>'В Саратове',
        'command'=>'weather_in_city',
    ];
    $out .= autobot_add_button($arg); // функция автобота - вернет готовую кнопку с html и атрибутами

    return $out;
}
add_filter('rcl_chat_after_form', 'bwitc_add_button', 19, 2);

- мы проверили что это не гость. Чат WP-Recall не работает с гостями. И что это не переписка в ЛК. Вывели кнопку функцией autobot_add_button и передали в неё нужные аргументы (описание аргументов дано в начале этой записи).

Можете поменять фильтр на rcl_chat_before_form - выведет нам кнопку над текстовым полем ввода.
А наш rcl_chat_after_form - под текстовом полем выводит кнопку

Уже сейчас можно проверить всю магию:
- по клику на кнопке сообщение уходит. Теперь нам надо поймать эту команду (второй функцией) и передать управление в третью функцию - именно она сделает запрос к погодному сервису и вернет нам погоду.

Шаг 2:

Нам надо поймать команду, до того как она запишется в базу данных. На этом этапе в дополнении RCL-Chat срабатывает фильтр rcl_pre_insert_chat_message

(задание на дом - найдите этот фильтр в плагине WP-Recall - посмотрите что он принимает, какие аргументы. Посмотрите где он стоит. Возможно что-то будет вам не понятно - но всегда старайтесь смотреть фильтры, экшены, сами функции и классы в исходном коде - часто это заменяет любую документацию. Это очень полезное качество - пытаться вникнуть в чужой код. Когда вы научитесь читать чужой код - вам не нужно будет описание функций - быстренько нашли нужное и прочитали в исходниках. Можете написать в комментариях - что вы увидели и где нашли вызов инициализацию этого фильтра)

// поймаем команду
function bwitc_catch_chat_message($message){
/* $message:
  Array(
    [chat_id] => 145,
    [user_id] => 1,                         // кто писал
    [message_content] => !weather_in_city,
    [message_time] => 2018-03-15 20:42:58,
    [private_key] => 133,                   // кому писал. 0 - если общий чат
    [message_status] => 0,                  // не прочитан
  )*/

    if($message['message_content'] == '!weather_in_city'){          // эту команду мы ждем. Это она!
        $message['message_content'] = 'Занято. Попробуйте позже';   // дефолт. (он нужен если 3-я функция нам false вернет)
        $message['user_id'] = AUTOBOT_ID;                           // константа. Хранит в себе идентификатор автобота.
        $message['message_time'] = date("Y-m-d H:i:s", current_time('timestamp') - 5); // отнимаем 5 секунд как небольшой фикс при двойном получении в чате

        $resp = bwitc_get_weather(); // запустим запрос к внешнему сайту
        if($resp){                   // успешный ответ. Выводим
            $str = str_replace('<br>', "\n", $resp);
            $message['message_content'] = $str;
        }

    }

    return $message;
}
add_filter('rcl_pre_insert_chat_message', 'bwitc_catch_chat_message');

- все комментарии в коде.

На 16-й строке я небольшой фикс сделал - время отнимается от запроса на 5 секунд (на запрос к яндексу). Такая корректировка подбирается экспериментально. Дело в том что при отправке команды в чат приходит тут же ответ и при проверке новых сообщений еще один раз. Это связано как-то с активностию проверок в чате (в настройках чата опция - "Задержка между запросами" 15 секунд). Чатом не предполагалось что я в него так буду лезть и делать внешние запросы - поэтому я сделал такой хак - время от 5-ти до 15-ти секунд выставляйте.

Шаг 3.

Собственно сам запрос к сервису яндекса. На 3-й строке выбирается город. По ссылке смотрите свой город и вписывайте нужный.

Если код ответа 200 - мы начнем парсить ответ. Если ответ иной - то это может быть либо временный бан, либо недоступный сервис. Увы, с погодой найти сервис погоды, который бы без регистрации и указания api-ключа давал бы данные я не нашел. Поэтому в этом уроке просто использовал Яндекс - я не знаю что там с лицензиями на такое использование. В образовательных целях думаю можно. Яша добрый ))

Код 3-й функции:

// удаленный запрос и формирование данных
function bwitc_get_weather(){
    $sity = 11146;              // Саратов region="11146". Смотри в https://pogoda.yandex.ru/static/cities.xml

    $resp = wp_remote_get('https://export.yandex.ru/bar/reginfo.xml?region='.$sity);

    if(wp_remote_retrieve_response_code($resp) != '200') return false; // не 200-й ответ. Или забанили или сервис недоступен

    $body = wp_remote_retrieve_body($resp);
    $xml = new SimpleXMLElement($body);     // все данные у нас в переменной в xml формате. Теперь собрать осталось

    $out = 'Погода: '.$xml->weather->day->title.'<br>';         // город
    $out .= 'Рассвет '.$xml->weather->day->sun_rise.'<br>';
    $out .= 'Закат '.$xml->weather->day->sunset.'<br>';
    $out .= 'Световой день: '.date( "H:i", strtotime($xml->weather->day->sunset) - strtotime($xml->weather->day->sun_rise) ).'<br>';

    foreach($xml->weather->day->day_part as $day){ // утро-день-ночь
        if( isset($day->weather_type) ){
            $out .= 'Сейчас:<br>';
        } else {
            $out .= $day->attributes()->{'type'}.':<br>';
        }
        
        if( isset($day->weather_type) ) $out .= '&nbsp;&nbsp;'.$day->weather_type.'<br>';
        if( isset($day->wind_speed) ) $out .= '&nbsp;&nbsp;Скорость ветра: ' . $day->wind_speed . ' м/с <br>';
        if( isset($day->wind_direction) ) $out .= '&nbsp;&nbsp;Направление: ' . $day->wind_direction . '<br>';
        if( isset($day->dampness) ) $out .= '&nbsp;&nbsp;Влажность: ' . $day->dampness . '%<br>';
        if( isset($day->pressure) ) $out .= '&nbsp;&nbsp;Давление: ' . $day->pressure . ' мм рт. ст.<br>';
        if( isset($day->temperature) ) $out .= '&nbsp;&nbsp;Температура: ' . $day->temperature . '°C<br>';
        if( isset($day->temperature_from) ) $out .= '&nbsp;&nbsp;Температура от: ' . $day->temperature_from . ' до: '. $day->temperature_to . '°C<br>';
    }

    return $out;
}

- на 10-й строке мы работаем с библиотекой SimpleXML - поэтому на вашем хостинге она должна быть включена (как правило включена). Если выбило fatal error - и указывает на эту строку - просите хостеров ее включить. Есть она не просит.

с 12-й строки мы начинаем собирать наши данные. Перед 12-й строкой распечатайте (print_r или var_dump или моим плагином Otshelnik-Fm Kint) переменную $xml - и посмотрите что в ней и как устроено. Тогда процесс сборки данных вам будет понятен.

Запускаем:


- результат достигнут.

Всё. 

Надеюсь этот урок был вам полезен. Мы чуток усложняемся - надеюсь вы повторяете эти уроки и всё было понятно. Если интерес к теме подобных самоучителей будет - такие уроки будут выходить, каждый раз усложняясь.

Исходник здесь.

p.s. сказать "спасибо" за мои руководства в этой группе, вы можете купив один из этих допов чисто за символическую сумму.

4

Автор публикации

не в сети 1 неделя

Вова (Otshelnik-Fm)

4 508
Живой, бодрый, полон идей!
Комментарии: 2252Публикации: 250Регистрация: 27-01-2013Продаж/Покупок: 0/0