Антон Шевчук // Web-разработчик

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

WordPress Logotype

Увлекшись написанием плагинов для WordPress’а составил правила хорошего тона…

Соглашение по именованию

С чего начинается плагин – с имени :), следовательно давайте вырабатаем правила именования плагинов:

  • Не используем тупых префиксов вида wp_ иль wp- – мы и так знаем что файлы в каталоге http://wordpress.org/extend/plugins/ предназначены для wordpress’a
  • Если хотите выделить Ваш плагин – добавьте оригинальный префикс/постфикс (я использую префикс (a) – правда не знаю насколько сие информативно)
  • Все имена классов и функций должны содержать имя Вашего плагина – дабы избежать конфликтов

Всегда создавайте директорию с плагином, даже если он состоит из одного файла, возможно в дальнейшем Вы захотите расширить функционал, и вот уже одним файлом не обойтись, и создадите директорию – а это может ввести в ступор пользователей…

readme.txt

Обязательным для каждого плагина есть наличие файла readme.txt, см. описание синтаксиса http://daringfireball.net/projects/markdown/syntax. Проверить Ваше творение можно используя валидатор.

Если Вы по каким-то причинам не заливаете свой плагин в репозиторий wordpress’a – то в любом случае создайте данный файл – многие скажут спасибо.

Заголовок

Это обязательный элемент плагина, не надо в нем сильно извращаться:

<?php
/*
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

Документация

Если от пользователя требуется внести изменения в текущую тему – то желательно описать данный процес очень подробно – а не как обычно: “Вот этот код выведет то что Вы хотите”.

Кстати “вот этот код”, не должен вызывать ошибок если Ваш плагин будет отключен, так что не забываем обрамлять вызовы функций следующей конструкцией:

<?php 
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. Если у Вас есть что добавить, либо есть ссылка на полезные ресурсы по теме – милости прошу в комментарии…

При подготовке материала были использованы следующие ресурсы:

© Антон Шевчук 2007-2017