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 файл текущей темы — так что советую подчистить 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
    Поделиться публикацией
    AdBlock похитил этот баннер, но баннеры не зубы — отрастут

    Подробнее
    Реклама

    Комментарии 16

      +1
      хм. осталось только сесть и написать плагин.
        +2
        Спасибо :) как раз работаю над плагином. В некоторых случаях документации WP недостаточно.
        Хотя часть информации, написанной вами, присутствует в документации WP.
          +1
          Прошу прощения за небольшой оффтоп, вы случайно не знаете по какой причине недоступен сайт mywordpress.ru? Уже два дня пытаюсь зайти и не загружается.
            0
            Информативненько. Благодарчик как говорится.

            Хорошо если каждый разработчик плагинов прочтет стандарты.
              0
              Я совсем недавно разбирался с написанием плагина к PixelPost, там та еще заморочка. А эту статейку сохраню до лучших времен
                +1
                Каверзный вопрос — а есть ли плагины, написанные в 100% соответствии с этими правилами? ;) Ну, кроме ваших…
                  0
                  Не, Вадим, каверзные вопросы звучат примерно так: «А у вас...»? :-))
                  +1
                  Говорите, что используете стандарты ZF, а в примерах код отформатирован не по ним (как минимум определения классов и функций).
                    +1
                    Специально не форматировал в соответствии с ZF — дабы не навязывать их — ибо какие стандарты кодирования выбирать — это тема отдельного холивара (тем более в WP данные стандарты не используются)…
                    0
                    Хорошие рекомендации. Респект.
                      –1
                      PHP Compact?
                        +2
                        Так как сам с WP знаком очень поверхностно — пару раз заходил в админку, не более, было бы неплохо привести модуль-пустышку со всеми этими функциями, который выводит строчку типа «hello world» но имет и интерфейс ввода этого текста в адмике в настройках, и создает/удаляет табличку, где будет храниться эта строча. В общем пример правильного модуля, что-бы его можно было использовать как шаблон. Если у вас есть что-то похожее, был бы благодарен, так как давно хотел сесть и разобраться с вордпрессом, но без опыта сложно понять для чего все эти хуки, фильтры и т.д. У вас в принципе все это и так кусками представлено, если бы собрали, то цены бы вашему труду не было бы :)
                        Но даже и без этого, спасибо за статью, даже загорелся на выходных таки сесть и понять что к чему в этой CMS-ке
                          0
                          Попробуйте посмотреть как устроен любой более-менее популярный плагин и вопросы сразу отпадут. Код не сложный для чтения, благо структура вордпресса достаточно продуманна )
                            0
                            Обычно хорошо продуманные плагины оочень накручены и отделить логику работы от формата взаимодействия непосредственно с CMS может потребовать времени, а когда есть готовый модуль, по сути состоящий из представленных выше кусков с небольшими комментами, то это бы дало хороший толчок именно к правильному подходу написания модулей конкретно для вордпресса.

                            И даже если таких шаблонов нет, подскажи какой модуль стоит взять для изучения? Какой и более-менее популярных плагинов, на твой взгляд достаточно качественно и правильно написан?

                      Только полноправные пользователи могут оставлять комментарии. Войдите, пожалуйста.

                      Самое читаемое