WordPress – стандарты кодирования плагинов // WordPress

Увлекшись написанием плагинов для WordPress’а составил правила хорошего тона…
Соглашение по именованию
С чего начинается плагин – с имени :), следовательно давайте вырабатаем правила именования плагинов:
- Не используем тупых префиксов вида wp_ иль wp- – мы и так знаем что файлы в каталоге http://wordpress.org/extend/plugins/ предназначены для wordpress’a
- Если хотите выделить Ваш плагин – добавьте оригинальный префикс/постфикс (я использую префикс (a) – правда не знаю насколько сие информативно)
- Все имена классов и функций должны содержать имя Вашего плагина – дабы избежать конфликтов
Всегда создавайте директорию с плагином, даже если он состоит из одного файла, возможно в дальнейшем Вы захотите расширить функционал, и вот уже одним файлом не обойтись, и создадите директорию – а это может ввести в ступор пользователей…
readme.txt
Обязательным для каждого плагина есть наличие файла readme.txt, см. описание синтаксиса http://daringfireball.net/projects/markdown/syntax. Проверить Ваше творение можно используя валидатор.
Если Вы по каким-то причинам не заливаете свой плагин в репозиторий wordpress’a – то в любом случае создайте данный файл – многие скажут спасибо.
Заголовок
Это обязательный элемент плагина, не надо в нем сильно извращаться:
/* Plugin Name: Name Of The Plugin Plugin URI: http://URI_Of_Page_Describing_Plugin_and_Updates Description: A brief description of the Plugin. Version: The Plugin's Version Number, e.g.: 1.0 Author: Name Of The Plugin Author Author URI: http://URI_Of_The_Plugin_Author */
Стандарты кодирования
Полноценных стандартов от разработчиков я не видел – по этой причине использую стандарты Zend Framework’a, чего и Вам советую. (в примерах я не буду использовать коментарии для PHP Documentator’а – дабы сократить листинг сорцов).
И еще – наш плагин не должен вызывать ошибок (даже уровня Notice), так что при разработке включите отображение ошибок:
error_reporting(E_ALL);
Динамическая подгрузка файлов
Подгружать сразу весь плагин, затем повесить все атцать хуков и ничего не сделать – такое поведение плагинов встречается часто, давайте будем умнее, для начала желательно убрать весь функционал по классам и файлам, и уже в функциях подгружать необходимые файлы:
// добавим фильтр контента add_filter('the_content', array('%PluginName%', 'the_content'), 1000); class %PluginName% { var $some_variable; /** * filter fo the_content * * @return void */ function the_content($content) { include_once 'class/Content.php'; $Content = new %PluginName%_Content(); return $Content->parseContent($content); } }
Так же желательно вешать хуки отдельно для каждого состояния – см. список:
if (is_admin()) { // хуки для админки } else { // хуки для фронт-енда } // и так далее ...
Можно даже так:
if (is_admin()) { include_once '%PluginName%_admin.php'; } else { include_once '%PluginName%_front.php'; } // и так далее ...
Переменные и пространство имен
Поскольку пространство имен в PHP еще не реализовано (имеются ввиду стабильные версии), то с данной задачей нам поможет справиться статический класс объединяющий в себе все функции для хуков:
add_action('%hook_name%', array('%PluginName%', '%hook_name%')); class %PluginName% { var $some_variable; /** * some function description * * @return void */ function %hook_name%() { // ... } }
Или же обычный класс:
// создаем сущность нашего класса $PluginName = new %PluginName%(); add_action('%hook_name%', array($PluginName, '%hook_name%')); class %PluginName% { var $some_variable; /** * some function description * * @return void */ function %hook_name%() { // ... } } // удаляем переменную за ненадобностью unset($PluginName);
При использование таблицы options (это функции add_option, update_option, delete_option) следует так же использовать префикс из имени плагина, таким образом мы будем эмулировать namespace наших опций (по какой причине до этого не додумались разработчики я не знаю)…
Следуя данным советам мы избежим конфликтов с другими плагинами…
Установка плагина
Для инициализации системы есть хук register_activation_hook, используя его Вы сможете внести необходимые измения в БД (создать таблицы, внести изменения в options и т.д.). Поверьте – пользователь не всегда читаем readme.txt где будет написано, что необходимо после инициализации обязательно сохранить настройки плагина дабы значения по умолчанию были сохранены в БД…
Настройки плагина
Давайте не будет ломать красивую админку WordPress’a – настройки плагина должны быть расположены в соответствующем меню – Settings » %Plugin Name%.
Так же советую вынести страницу с настройками в отдельный файл с информативным названием (к примеру %PluginName%_options.php либо %PluginName%_settings.php):
if (is_admin()) { add_action('admin_menu', array('%PluginName%', 'adminMenu')); } class %PluginName% { function adminMenu() { if (function_exists('add_options_page')) { add_options_page('%PluginName%','%PluginName%', 'manage_options', '%PluginName%/%PluginName%_options.php') ; } } }
Чтобы всё было красиво – используйте стили прописанные в wp-admin/wp-admin.css – за такой подход Вам скажут спасибо…
Деактивация плагина
Если Вы при установке плагина вносите какие-либо изменения в БД или на файловой системе – то желательно подчистить сие после отключения плагина, в этом Вам поможет хук register_deactivation_hook.
Кастомизация
Добавляем CSS и JavaScript используя следующую конструкцию:
// регистрируем наш CSS файл wp_register_style('%PluginName%', get_option('siteurl') . '/wp-content/plugins/%PluginName%/%PluginName%.css'); // либо wp_enqueue_style('%PluginName%', get_option('siteurl') . '/wp-content/plugins/%PluginName%/%PluginName%.css'); // регистрируем наш JS файл (с указанием зависимостей) wp_register_script( '%PluginName%', get_option('siteurl') . '/wp-content/plugins/%PluginName%/%PluginName%.js', array('jquery')); // либо wp_enqueue_script( '%PluginName%', get_option('siteurl') . '/wp-content/plugins/%PluginName%/%PluginName%.js', array('jquery'));
Этот способ сработает отлично в том случае если данные методы будут находиться в хуке на wp_head либо admin_head, иначе вам самим надо будет вызвать метод wp_print_styles или wp_print_scripts, и передать им имя скрипта для вывода…
Так же не забываем о конфликтах, как их обойти почитайте в статье How to load JavaScript in WordPress plugins
Если Ваш плагин имеет некое графическое оформление – и оное обычно изменяют под конкретную тему – то желательно сделать проверку на наличие CSS файла для нашего плагина в директории текущей темы:
if (file_exists(TEMPLATEPATH.'/%PluginName%.css')) { wp_register_style('%PluginName%', get_bloginfo('template_directory') . '/%PluginName%.css'); } else { wp_register_style('%PluginName%', get_option('siteurl') . '/wp-content/plugins/%PluginName%/%PluginName%.css'); }
При создании CSS будьте очень внимательны, Ваш CSS файл не должен ломать текущий дизайн, так что опять – используйте либо префиксы, либо жесткую привязку:
.%PluginName%-sidebar { /*...*/ } #%PluginName% { /*...*/ } #%PluginName% > div { /*...*/ }
Не стоит так же забывать о том, что на внешний вид Вашего плагина может влиять CSS файл текущей темы – так что советую подчистить marging’и, padding’и и border’ы…
Вот такими нехитрыми приемами мы облегчим жизнь себе и дизайнерам…
Мультиязычность
Не планируете делать мультиязычность, но тогда дайте возможность другим помочь Вам, подготовьте плагин к переводу, для этого достаточно будет создать файл локализация содержащий лишь Ваш язык, да использовать следующие функции для вывода текста:
__('String', '%PluginName%'); _e('String', '%PluginName%'); _c('String', '%PluginName%'); __ngettext('String', 'Strings', $c, '%PluginName%')
Файлы перевода желательно так же помещать в отдельную директории language – дабы не засорять корневой каталог плагина…
Более подробную информацию смотрите на странице I18n for WordPress Developers
Документация
Если от пользователя требуется внести изменения в текущую тему – то желательно описать данный процес очень подробно – а не как обычно: “Вот этот код выведет то что Вы хотите”.
Кстати “вот этот код”, не должен вызывать ошибок если Ваш плагин будет отключен, так что не забываем обрамлять вызовы функций следующей конструкцией:
if (function_exists('%FunctionName%')) { %FunctionName%(); }
Помните – конечный потребитель зачастую не программист, и ему необходимо всё разжевать и в рот положить…
Совместимость
К сожалению WordPress позиционирует себя как система с поддержкой PHP4, так что если Вы используете PHP5, то лучше заранее сообщить об этом пользователю на этапе включения плагина, либо создайте файл для обеспечения совместимости (если вы используете лишь какие-либо специфичные функции):
// подключаем в файле плагина if (version_compare(phpversion(), '5.1.0', '<')) { require_once '%PluginName%_compatibility.php' } // что может быть в файле if (!function_exists('array_diff_key')) { function array_diff_key() { $args = func_get_args(); return array_flip(call_user_func_array('array_diff', array_map('array_flip',$args))); } }
Дабы не изобретать велосипедов – советую посмотреть на пакет PEAR PHP_Compact.
Вполне вероятно Вам может так же понадобиться поддержка старых версий WordPress’a:
// подключаем в файле плагина if (version_compare(get_bloginfo('version'), '2.6.0', '<')) { require_once '%PluginName%_compatibility.php' }
Выводы
Подведу итого.
Директория плагина может выглядеть следующим образом:
\plugin-name |--\languages |--\library |--\javascript |--\css |-- plugin-name.php |-- plugin-name_admin.php |-- plugin-name_front.php |-- plugin-name_settings.php |-- plugin-name_compatibility.php `-- readme.txt
- префикс %PluginName% не обязателен, и при большом количестве файлов даже избыточен
- languages – все переводы будут лежать тут
- library – директория для сторонних библиотек
- javascript и css – содержат javascript и css файлы для вашего плагина
- readme.txt – обязательно
- функционал разнесен по нескольким файлам (admin.php, front.php, single.php и т.д.)
- обеспечена совместимость версий (compatibility.php)
P.S. Если у Вас есть что добавить, либо есть ссылка на полезные ресурсы по теме – милости прошу в комментарии…
При подготовке материала были использованы следующие ресурсы: