Pull to refresh

Wordpress — стандарты кодирования плагинов

Reading time8 min
Views4.7K
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 файл текущей темы — так что советую подчистить margin'ги, 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', '<')) {
  requery_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_Compat.

Вполне вероятно Вам может так же понадобиться поддержка старых версий Wordpress'a:
// подключаем в файле плагина
if (version_compare(get_bloginfo('version'), '2.6.0', '<')) {
  requery_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. Если у Вас есть что добавить, либо есть ссылка на полезные ресурсы по теме — милости прошу в комментарии…

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

Для подстветки синтаксиса кода использован ресурс highlight.hohli.com
Tags:
Hubs:
Total votes 72: ↑69 and ↓3+66
Comments16

Articles