В этом уроке мы напишем не просто дополнение для 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 .= ' '.$day->weather_type.'<br>'; if( isset($day->wind_speed) ) $out .= ' Скорость ветра: ' . $day->wind_speed . ' м/с <br>'; if( isset($day->wind_direction) ) $out .= ' Направление: ' . $day->wind_direction . '<br>'; if( isset($day->dampness) ) $out .= ' Влажность: ' . $day->dampness . '%<br>'; if( isset($day->pressure) ) $out .= ' Давление: ' . $day->pressure . ' мм рт. ст.<br>'; if( isset($day->temperature) ) $out .= ' Температура: ' . $day->temperature . '°C<br>'; if( isset($day->temperature_from) ) $out .= ' Температура от: ' . $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. сказать "спасибо" за мои руководства в этой группе, вы можете купив один из этих допов чисто за символическую сумму.
Хороший урок, кто захочет повторить - сможет оттолкнуться и пойти еще дальше, так что кто в теме или хочет в ней быть, начинайте вникать, однозначно будет полезно.
Очень много идей в этом направлении отсекается тем, что сообщения люди получают не в реальном времени, а через заданный промежуток времени, это сильно ограничивает варианты использования ботов. Я вот сразу вспомнил о irc-чатах и их ботов с развлекаловами, но опять же это все требует реалтайм чата. 🙁
ВП не поддерживает вебсокеты. Сами понимаете что Ajax и его ограничения. Но даже с 15 секундным таймаутом тоже достаточно хорошо можно пообщаться. NodeJs и прочие прелести может и придут в вордпресс
Я вспомнил времена DC++ хабов и решил перенести несколько идей в веб. Мне кажется вышло забавно. А вот нужно ли это - покажет время
Для общения то достаточно, я говорю про развлечение. Для IRC было много игр разных, но их можно писать только если чат реалтайм, вот поэтому и жалко что пока такой возможности нет.
Я не совсем понимаю о чем речь. Ну да - можно выставить скорость обновления чата и 10 секунд - а разница реал-тайм или с задержкой в 10 секунд? Хоть пример приведите что за игры были для реалтайма - я в ирке не сидел. Не довелось.
Андрей делал Шашки - вполне хватает. Понятно что супеконтра игру не сделать - но это не для чата игра. Хотя на html 5 есть игры - взять тот же bombermine - клон бомбермена.
На js можно игры пилить, синхронизируя их с rcl heartbeat каждые 15 секунд (опять же как пример Шашки так сделаны - там чат и ходы синхронизированы и ajax-нагрузки получаются не дают - т.к. по сути это обычный чат)
Это все для игрк на 2их подходит или где вариант ходить по очереди. Первой что пришло на ум по irc - там задавались вопросы и надо было дать ответ, кто первый дает ответ - тому очки и так вот играли в чате человек 30 одновременно, тогда это было интересно. С задержкой такое не получится сделать =/
Так это задает особую интригу. Напоминает игры на бирже - там тоже задержки есть. Помнится наподобие форексов - в зависимости от сайта свои тайминги. Думаю что и даже так можно придумать свои варианты.
Единственное что тут сейчас неудобно - когда сообщений много - скролл. Под это дело надо свой дизайн чата лепить - чтобы на полную ширину и в одну строку - отправитель (ник) и его сообщение. Чтобы не было аватарки сразу (по запросу - клику). Тогда мы получим компактный чат - где все видно далеко. Примерно так https://yadi.sk/i/yxvgBSic3TTCq9
Владимир, спасибо, очень полезно. Как время появится, попробую сделать в этом направлении...