Делаем плагины для WordPress. Часть 1
Оглавление
Введение
Описание будущего плагина
Структура плагинов
Фильтры, actions и Shortcodes
Информация о плагине
Shortcodes
Плагин в стиле ООП
Комментарии
Введение
WordPress - один из самых распространенных движков для ведения блогов. В подобных системах важную роль играет расширяемость движка, поэтому и возможности WordPress могут значительно наращиваться за счет плагинов, которые довольно легко подключаются и настраиваются.
В этой статье, которая будет состоять из нескольких частей, мы будем учиться делать свои собственные плагины. Так как WordPress написан на языке PHP, то и плагины для него также пишутся в основном на PHP, но для некоторых моментов может понадобиться еще и JavaScript.
При написании плагина очень помогают две вещи - документация, которая расположена здесь, и чужие плагины. Документация к WordPress очень неплохая и с большим количеством примеров, но, к сожалению, не всегда понятно что в ней искать, поэтому неплохо иметь под рукой готовые плагины, которые имеют возможности, близкие к тем, что вы собираетесь делать. Эти плагины могут подтолкнуть к тому какие ключевые слова или функции искать в документации. Хотя с чужими плагинами тоже надо быть осторожными, иногда там попадаются такие выкрутасы, которых можно было бы избежать. Правда, часто эти выкрутасы автор плагина вынужден делать, чтобы сохранить совместимость с более старыми версиями WordPress. Вообще, глядя на последние версии WordPress, надо сказать, что программирование плагинов постепенно упрощается, добавляются новые полезные функции, которые могут существенно сократить код, правда, при их использовании придется пожертвовать совместимостью со старыми версиями движка.
Описание будущего плагина
Так как тема написания плагинов для WordPress довольно большая, и все аспекты программирования мы все-равно не охватим, то будем разбираться с плагинописанием на примере создания конкретного плагина. Поэтому для начала опишем, что этот плагин должен будет делать.
Если вы периодически бываете на сайте Живого Журнала (далее будем называть его просто ЖЖ), то наверняка видели, что при ссылке на пользователя или сообщество около текста ссылки ставятся вот такие значки:
для сообществ
В ЖЖ это делается с помощью специального тега <lj user="username"> и <lj comm="community">, a уже сервер ЖЖ формирует соответствующий HTML.
Иногда в своем блоге хочется сослаться на ЖЖ-пользователя, оформив ссылку таким же образом. Именно для этого и будет предназначен наш будущий плагин. Кратко перечислим основные требования к нему. Плагин должен будет:
- преобразовывать запись вида [ljuser]username[/ljuser] в соответствующий код HTML для оформления ссылки на пользователя;
- преобразовывать запись вида [ljcomm]community[/ljcomm] в соответствующий код HTML для оформления ссылки на сообщество;
- иметь на панели инструментов редактора кнопки для вставки когда [ljuser][/ljuser] и [ljcomm][/ljcomm];
- иметь свою страницу настроек и давать возможность для смены ссылки на картинки перед именем пользователя или сообщества;
- поддерживать локализацию и иметь две языковые версии: английскую и русскую.
В первой части статьи мы реализуем первые два пункта.
При создании плагина мы будем использовать две сравнительно новых возможностей, одна из которых появилась в WordPress 2.5, а другая в WordPress 2.6. Но наш плагин будет работать в обоих версиях WordPress (но не ниже 2.5).
Структура плагинов
Напомню, что плагины располагаются в директории /wp-content/plugins, причем, если плагин состоит только лишь из одного php-файла, то он может находиться непосредственно в этой директории, но лучше создать свою поддиректорию и располагаться в ней. WordPress сам находит плагины из директории plugins, поэтому установка плагинов сводится к копированию его в эту директорию и активации его в панели администрирования.
Начнем делать наш плагин. В первую очередь для него нужно придумать название, причем оно должно быть уникальным среди плагинов. Чтобы убедиться, что плагина с таким именем, не существует, можно воспользоваться поиском плагинов на сайте WordPress - http://wordpress.org/extend/plugins/. Кроме того было бы не вредно поискать плагин с таким названием в гугле, потому что не все авторы выкладывают свое творение на сайт wordpress.org.
Старайтесь придумывать такие имена для плагинов, чтобы по их названию можно было бы понять что они делают. Наш плагин будет называться ljusers (lj - от слова livejournal), поиск по плагинам на wordpress.org ничего дал, поэтому можем использовать это название с чистой совестью. :)
Теперь заходим в директорию /wp-content/plugins и создаем в ней поддиректорию с именем нашего плагина - ljusers, а в ней создаем файл ljusers.php. Если вы будете писать комментарии в исходнике плагина на русском языке, то тогда кодировка этого файла должна быть UTF-8, поэтому заранее приготовьте редактор, который умеет работать с файлами в такой кодировке. Я, например, использую SciTe. С другой стороны, если вы будете выкладывать ваш плагин на сайт wordpress.org, то желательно все комментарии писать на английском языке, вдруг кто-то захочет посмотреть как он работает или подправить его под свои нужды.
Информация о плагине
После того как файл создан, в самом его начале необходимо написать специальный комментарий, в котором будет указано название плагина, его версия, разработчики и т.п. Например, на данном этапе ljusers.php может выглядеть так:
/*
Plugin Name: LJUsers
Plugin URI: http://jenyay.net
Description: Insert Livejournal users from editor
Version: 1.0.0
Author: Jenyay
Author URI: http://jenyay.net
*/
?>
После этого можно считать, что наш первый плагин для WordPress написан. Да он ничего не делает, но зато он уже появится в списке плагинов. И его можно даже активировать.
Разумеется, мы на этом не остановимся и согласно требованиям к плагинам на сайте wordpress.org допишем хотя бы еще лицензию. В основном для плагинов используют лицензию GPL или совместимую с ней. Теперь код нашего плагина будет выглядеть вот так:
/*
Plugin Name: LJUsers
Plugin URI: http://jenyay.net
Description: Insert Livejournal users from editor
Version: 1.0.0
Author: Jenyay
Author URI: http://jenyay.net
*/
/* Copyright 2008 Jenyay (email : jenyay.ilin {at} gmail.com)
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
?>
Фильтры, actions и Shortcodes
Прежде чем добавлять какую-то функциональность к плагину надо разобраться с архитектурой плагинов в WordPress. В основном работа плагинов сводится к реагированию на особые события, которые возникают в движке WordPress. При загрузке плагин сообщает на какие события он будет реагировать и указывает функции-обработчик, которые будут вызываться при наступлении этого события. События бывают двух типов: действия (Actions) и фильтры (Filters).
Надо сказать, что для простоты объяснения это я их называю событиями, на самом деле в документации действия и фильтры не объединяют каким-то одним словом, а говорят просто, что плагин устанавливает хук (hook) на такой-то фильтр или action. Под словом хук как раз и понимается функция-обработчик.
Именно действия по сути ближе всего к понятию событие в том виде, как это понимают при программировании других систем, они довольно разнообразны, поэтому как-то кратко их охарактеризовать довольно тяжело.
Зато фильтры вызываются в более конкретных ситуациях, а именно при работе с текстом, редактировании, формировании HTML-страницы и т.п. В нашем плагине мы будем использовать именно фильтры.
Shortcodes
В WordPress 2.5 кроме действий и фильтров появился новый тип хуков, так называемые shortcodes, которые позволяет легко преобразовывать теги вида [tagname] и [tagname]tagtext[/tagname] в HTML таким образом как мы захотим. Именно shortcodes мы и будем использовать в нашем плагине для формирования HTML.
Добавим первую функциональность к нашему плагину, а именно сделаем так, что, если в тексте сообщения встречается конструкция [ljuser]username[/ljuser] или [ljcomm]community[/ljcomm], то в окончательно сформированной странице на месте этих shortcodes будет стоять соответствующий HTML для ссылки на пользователя ЖЖ или сообщества. Прежде чем начнем писать, код рассмотрим общую структуру shortcodes.
Здесь под строкой shortcode_name понимается имя обрабатываемого shortcode, то есть в нашем случае вместо shortcode_name будет стоять ljuser или ljcomm.
После имени shortcode_name могут быть (а могут и не быть) перечислены атрибуты, а между [shortcode_name ...] и [/shortcode_name] располагается так называемый контент. Контента тоже может не быть, тогда закрывающийся shortcode [/shortcode_name] также можно опустить, в этом случае shortcode будет выглядеть следующим образом:
Чтобы сообщить WordPress, что мы будем обрабатывать какой-нибудь shortcode, необходимо вызвать функцию add_shortcode(), объявление которой выглядит следующим образом:
В качестве первого параметра мы указываем имя нашего shortcode, а в качестве второго - имя функции, которая будет вызываться, когда в тексте встретиться этот shortcode. Функция, которая будет вызвана, передается в add_shortcode() аналогично тому, как она передается в стандартную PHP-функцию call_user_func(), то есть можно передавать массив, содержащий ссылку на класс и имя функции внутри него. В дальнейшем мы это также будем использовать, но кроме того вы можете почитать про передачу функций здесь.
Функция, которая будет вызвана для обработки shortcode должна иметь два принимаемых параметра: первый параметр - массив атрибутов, второй - контент между открывающимся и закрывающимся shortcode. В качестве возвращаемого значения функция-обработчик должна вернуть код HTML, соответствующий shortcode.
Надо предупредить, что имена функций должны быть тоже уникальными, поэтому лучше всего их начинать с названия плагина, а после символа подчеркивания "_" писать остальное название, которое будет описывать действие функции.
Напишем функцию для обработки shortcode с именем ljuser и добавим ее в качестве обработчика:
{
return "<b><span style='white-space: nowrap; display: inline !important;'><a href='http://$content.livejournal.com/profile'><img src='http://p-stat.livejournal.com/img/userinfo.gif' alt='[info]' width='17' height='17' style='vertical-align: bottom; border: 0; padding-right: 1px;vertical-align:middle; margin-left: 0; margin-top: 0; margin-right: 0; margin-bottom: 0;' /></a><a href='http://$content.livejournal.com/'><b>$content</b></a></span></b>";
}
add_shortcode('ljuser', 'ljusers_user_shortcode');
Этот код нужно добавить после комментария с лицензией, но до закрывающихся символов ?>
Как видите, все довольно просто. Мы вызываем функцию add_shortcode(), в которую передаем имя нашего shortcode - 'ljuser' , а в качестве второго параметра передаем имя функции для обработки - 'ljusers_user_shortcode' .
Сама функция ljusers_user_shortcode() выглядит запутанной, но по сути это одна строка с HTML для вывода ссылок и картинки с нужными стилями, в середине которой три раза используется переменная $content. Атрибуты мы использовать не будем. Полученную строку HTML функция должна вернуть с помощью ключевого слова return.
Если налогично записать обработчик shortcode для 'ljcomm' , то полностью код плагина будет выгядеть так:
/*
Plugin Name: LJUsers
Plugin URI: http://jenyay.net
Description: Insert Livejournal users from editor
Version: 1.0.0
Author: Jenyay
Author URI: http://jenyay.net
*/
/* Copyright 2008 Jenyay (email : jenyay.ilin@gmail.com)
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
function ljusers_user_shortcode ($atts, $content = null)
{
return "<b><span style='white-space: nowrap; display: inline !important;'><a href='http://$content.livejournal.com/profile'><img src='http://p-stat.livejournal.com/img/userinfo.gif' alt='[info]' width='17' height='17' style='vertical-align: bottom; border: 0; padding-right: 1px;vertical-align:middle; margin-left: 0; margin-top: 0; margin-right: 0; margin-bottom: 0;' /></a><a href='http://$content.livejournal.com/'><b>$content</b></a></span></b>";
}
function ljusers_community_shortcode ($atts, $content = null)
{
return "<b><span style='white-space: nowrap;'><a href='http://community.livejournal.com/$content/profile'><img src='http://www.livejournal.com/img/community.gif' alt='[info]' width='17' height='17' style='vertical-align: middle; border: 0; padding-right: 1px; margin-left: 0; margin-top: 0; margin-right: 0; margin-bottom: 0;' /></a><a href='http://community.livejournal.com/$content'><b>$content</b></a></span></b>";
}
add_shortcode('ljuser', 'ljusers_user_shortcode');
add_shortcode('ljcomm', 'ljusers_community_shortcode');
?>
Скачать архив с таким плагином можно здесь.
Все, этот плагин уже полностью работоспособен. Теперь можно активировать плагин через панель администрирования (если вы этого еще не сделали после создания заголовка плагина) и попробовать его работоспособность. Надо сказать, что во время отладки плагина после очередного изменения его кода, не обязательно плагин деактивировать и активировать, достаточно просто обновить страницу. Хотя не исключено, что могут быть плагины, для которых может понадобиться новая активация. Ниже вы видите пару скриншотов: текст, набранный в редакторе (не важно где его набирать в визуальном ли режиме редактора или в режиме HTML):
и результат сформированной страницы:
Вот теперь у нас есть довольно полезный плагин, но мы на этом не остановимся.
Плагин в стиле ООП
Помните про то, что имена функций в плагине должны быть уникальными? А ведь плагин может называться довольно длинно, из-за чего имя функции может выглядеть монстроидально. Чтобы облегчить себе задачу создания уникальных имен, можно сделать наш плагин в объектно-ориентированном стиле, то есть все функции разместить в одном (или нескольких) классах с уникальными именами, а уж внутри класса функции можно называть как угодно. Перепишем наш плагин в стиле ООП.
Начнем с функций-обработчиков (думаю, что не стоит дальше писать начальный комментарий с информацией о плагине и лицензии):
{
function ljusers_user_shortcode ($atts, $content = null)
{
return "<b><span style='white-space: nowrap; display: inline !important;'><a href='http://$content.livejournal.com/profile'><img src='http://p-stat.livejournal.com/img/userinfo.gif' alt='[info]' width='17' height='17' style='vertical-align: bottom; border: 0; padding-right: 1px;vertical-align:middle; margin-left: 0; margin-top: 0; margin-right: 0; margin-bottom: 0;' /></a><a href='http://$content.livejournal.com/'><b>$content</b></a></span></b>";
}
function ljusers_community_shortcode ($atts, $content = null)
{
return "<b><span style='white-space: nowrap;'><a href='http://community.livejournal.com/$content/profile'><img src='http://www.livejournal.com/img/community.gif' alt='[info]' width='17' height='17' style='vertical-align: middle; border: 0; padding-right: 1px; margin-left: 0; margin-top: 0; margin-right: 0; margin-bottom: 0;' /></a><a href='http://community.livejournal.com/$content'><b>$content</b></a></span></b>";
}
}
Как видите, здесь ничего не изменилось по сравнению со старым исходником кроме того, что функции ljusers_user_shortcode() и ljusers_community_shortcode() стали располагаться внутри класса ljusers.
А где же мы будем регистрировать обработчики shortcode? В принципе, мы могли бы это делать снаружи класса, объявив предварителькно функции ljusers_user_shortcode() и ljusers_community_shortcode() статическими, но мне больше нравится объявлять обработчики в конструкторе, для чего немного дополним класс ljusers:
{
function ljusers()
{
add_shortcode('ljuser', array (&$this, 'ljusers_user_shortcode') );
add_shortcode('ljcomm', array (&$this, 'ljusers_community_shortcode') );
}
...
}
Обратите внимание на то как мы теперь указываем на добавляемые функции, например:
Да, выглядит немного пострашнее, но зато теперь мы можем прятать функции внутри нашего класса и не заботиться об уникальности их имен. Далее логично было бы переименовать функции ljusers_user_shortcode() и ljusers_community_shortcode() во что-то более короткое, например, убрать префиксljusers_.
Осталось теперь только каким-то образом вызвать конструктор нашего класса. Но здесь все просто, просто создаем переменную с экземпляром класса ljusers:
И не помешает сделать еще одно небольшое изменение, а именно проверку того, что функция add_shortcode() существует. Напомню, что эта функция появилась только в WordPress 2.5, поэтому, если этой функции нет, то на таком старом WordPress наш плагин работать не будет. Сделаем так, чтобы содержимое конструктора выполнялось только если function_exists ('add_shortcode') == true.
И снова плагин полностью работоспособен. Следующий исходник - это наш новый плагин (без начального комментария). В нем уже содержатся переименованные функции user_shortcode() и community_shortcode():
class ljusers
{
function ljusers()
{
if (function_exists ('add_shortcode') )
{
add_shortcode('ljuser', array (&$this, 'user_shortcode') );
add_shortcode('ljcomm', array (&$this, 'community_shortcode') );
}
}
function user_shortcode ($atts, $content = null)
{
return "<b><span style='white-space: nowrap; display: inline !important;'><a href='http://$content.livejournal.com/profile'><img src='http://p-stat.livejournal.com/img/userinfo.gif' alt='[info]' width='17' height='17' style='vertical-align: bottom; border: 0; padding-right: 1px;vertical-align:middle; margin-left: 0; margin-top: 0; margin-right: 0; margin-bottom: 0;' /></a><a href='http://$content.livejournal.com/'><b>$content</b></a></span></b>";
}
function community_shortcode ($atts, $content = null)
{
return "<b><span style='white-space: nowrap;'><a href='http://community.livejournal.com/$content/profile'><img src='http://www.livejournal.com/img/community.gif' alt='[info]' width='17' height='17' style='vertical-align: middle; border: 0; padding-right: 1px; margin-left: 0; margin-top: 0; margin-right: 0; margin-bottom: 0;' /></a><a href='http://community.livejournal.com/$content'><b>$content</b></a></span></b>";
}
}
$ljusers = new ljusers();
?>
Скачать эту версию плагина можно отсюда
На этом первая часть статьи заканчивается, во второй части мы добавим кнопки в визуальный редактор, которые будут добавлять текст [ljuser][/ljuser] и [ljcomm][/ljcomm].
Буду рад вашим комментариям. Продолжение следует...
Делаем плагины для WordPress. Часть 2
Вы можете подписаться на новости сайта через RSS, Группу Вконтакте или Канал в Telegram.