Захопившись написанням плагінів для wordpress’а склав правила хорошого тону…

Угода щодо іменування

З чого починається плагін – з імені :), отже давайте вырабатаем правила іменування плагінів:

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

Завжди створюйте директорію з плагіном, навіть якщо він складається з одного файлу, можливо надалі Ви захочете розширити функціонал, і ось вже одним файлом не обійтися, і створите директорію – а це може ввести в ступор користувачів…

readme.txt

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

Якщо Ви з якихось причин не заливаєте свій плагін в репозиторій wordpress’a – то в будь-якому випадку створіть файл – багато скажуть спасибі.

Заголовок

Це обов’язковий елемент плагіна, не треба в ньому сильно перегинати палицю:

Стандарти кодування

Повноцінних стандартів від розробників я не бачив – за цієї причини використовую стандарти 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

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

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

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

Пам’ятайте – кінцевий споживач часто не програміст, і йому треба все розжувати і в рот покласти…

Сумісність

На жаль 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. Якщо у Вас є що додати або є посилання на корисні ресурси по темі – милості прошу в коментарі…

При підготовці матеріалу були використані наступні ресурси:

  • WordPress Developer Documentation
  • Suggestions For Standards Plugin
  • WordPress developer’s Toolbox