Разработка собственных плагинов WordPress: структура, хуки и публикация лёгких плагинов
I. Когда стоит писать плагин самому
В WordPress любое нестандартное поведение подключается через хуки. От смены адреса отправителя письма до добавления произвольного поля — всё решается несколькими десятками строк PHP. Проблема в том, что многие первым делом идут искать плагин в каталоге.
Как решить, ставить плагин или писать самому: если задача — это «изменить одно фиксированное поведение», например сменить отправителя по умолчанию, добавить свой JS или изменить длину анонса, собственный плагин чище стороннего. Общий подход к выбору плагинов см. в Технологический стек для сайта на WordPress.
Контринтуитивный момент: чем длиннее становится functions.php, тем это не признак мастерства, а мина замедленного действия на случай смены темы. При обновлении или смене темы functions.php перезаписывается, и код пропадает. Правильно — перенести свою логику в отдельный плагин, а тему оставить только для внешнего вида.
В именовании тоже нужны правила. Имя каталога плагина — префикс плюс функция, например crater-inquiry-source, чтобы не совпасть с официальными плагинами. Имена функций тоже с префиксом, crater_register_source, чтобы не конфликтовать с функциями других плагинов.
Конфликт имён функций — самая частая фатальная ошибка в плагинах WordPress. Если два плагина объявили function register_source(), тот, что загрузился позже, даёт белый экран. Всем своим функциям нужно давать уникальный префикс.
| Масштаб задачи | Рекомендуемая форма | Число файлов |
|---|---|---|
| 1–3 небольших изменения | Однофайловый плагин | 1 php |
| 3–5 связанных функций | Однофайловый плагин + константы | 1 php |
| Больше 5 независимых функций | Плагин со структурой каталогов | Главный файл + includes + assets |
| Нужна страница настроек в админке | Плагин со структурой каталогов | Добавить admin-page.php |
II. Минимальная структура однофайлового плагина
Рабочему плагину WordPress достаточно одного php-файла с заголовочным комментарием в начале, который сообщает WP, что это плагин. Файл кладётся в wp-content/plugins/, и в админке он сразу появится.
Заголовочный комментарий плагина имеет фиксированный формат: Plugin Name, Description, Version, Author. Без этого комментария WP не распознает его как плагин.
Пример 1: меняем email отправителя по умолчанию — весь плагин умещается в 10 строк. Подключаем два фильтра, wp_mail_from и wp_mail_from_name, и меняем стандартный wordpress@ на noreply@example.com. Страница настроек не нужна.
Для старта лучше всего подходит плагин, построенный только на фильтрах. Ни базы данных, ни страниц в админке, ни задач по расписанию: если что-то сломается, отключаем плагин — и всё возвращается как было.
Если нужно хранить настройки, используйте штатную таблицу options в WordPress: одна запись — один массив, свою таблицу создавать не надо. Для простых настроек хватит get_option и update_option.
| Тип хука | Популярные хуки | Зачем нужен |
|---|---|---|
| Фильтр (filter) | wp_mail_from、the_content | Изменяет выводимый контент |
| Действие (action) | wp_head、admin_init | Вставляет код или выполняет действие |
| Действие в кабинете | admin_menu、admin_init | Добавляет страницу настроек, работает только в админке |
| Хуки фронтенда | wp_enqueue_scripts | Подключает CSS/JS, работает только на фронтенде |
Где вы подключаете хук — это ключ к производительности. admin_init срабатывает только при загрузке админки, wp_head — только при загрузке страниц фронтенда. Не вешайте логику, предназначенную для админки, на init: тогда она будет впустую выполняться при каждом запросе к сайту.
Свои CSS и JS подключайте через хук wp_enqueue_scripts, а не через echo прямо в wp_head. Из-за echo скрипты загрузятся повторно.
Пример 3: плагину нужно подгрузить скрипт валидации на странице с формой. Регистрируем его через wp_enqueue_script, указываем зависимость jquery, а пятый параметр ставим в true, чтобы скрипт загружался в подвале и не блокировал отрисовку первого экрана.
III. Активация, удаление и очистка данных
Если плагин создаёт таблицы в базе или записывает option, нужно предусмотреть активацию и удаление. При активации создаём таблицы, при удалении — удаляем, иначе после удаления плагина в базе останется мусор.
register_activation_hook срабатывает при включении плагина — здесь удобно создавать таблицы и записывать option по умолчанию. uninstall.php срабатывает при удалении плагина — здесь удобно чистить данные. Учтите: deactivate и uninstall — не одно и то же. При деактивации данные сохраняются, удаляются только при удалении.
Пример 2: плагин записывает источник заявки в свою таблицу. При активации создаём таблицу через dbDelta, при удалении делаем DROP TABLE. Если пользователь деактивирует и снова включит плагин, данные останутся; если удалит плагин — таблица тоже удалится.
| Срок жизни | Хук | Что делать |
|---|---|---|
| Включение плагина | register_activation_hook | Создать таблицы, записать option по умолчанию |
| Деактивация плагина | register_deactivation_hook | Убрать задачи по расписанию, данные не трогать |
| Удаление плагина | uninstall.php | Удалить таблицы и option |
| При каждой загрузке | plugins_loaded | Определить константы, подключить текстовый домен |
О безопасности: в собственном плагине любую обработку пользовательского ввода делайте через $wpdb->prepare, а не склеивайте SQL напрямую. Базовые настройки ролей пользователей и прав в админке смотрите в разделе Базовая безопасность WordPress. О совместимости версий PHP читайте в разделе Обновление версии PHP на отдельном сайте.
IV. Публикация и поддержка: приватный плагин не для официального каталога
Приватный плагин для одного клиентского сайта, публиковать на wordpress.org не нужно. Достаточно собрать zip и загрузить через админку или склонировать репозиторий прямо в wp-content/mu-plugins: MU-плагины включаются автоматически, и их нельзя случайно отключить.
Версионирование обязательно. Номер Version в заголовке плагина увеличивайте при каждом изменении, тогда в админке будет видно обновление. Не правьте файлы плагина на продакшене: сначала вносите изменения локально, потом загружайте.
Несколько собственных плагинов команды crater сделаны именно так, подробнее см.Технологический стек crater. Все они решают конкретные небольшие задачи, и в каждом не больше двух файлов.
| Способы публикации | Когда подходит | Плюсы | Риск |
|---|---|---|---|
| загрузка zip через админку | приватный плагин для клиента | клиент может отключить сам | можно случайно удалить |
| каталог mu-plugins | основная логика не должна отключаться | включён по умолчанию, случайно не отключить | обновление вручную |
| публикация на wordpress.org | публичный плагин общего назначения | автообновление | нужно пройти модерацию и написать документацию |
Не забывайте про версионирование. Увеличивайте Version в заголовке плагина при каждом изменении, только тогда в списке плагинов в админке появится отметка «есть обновление».
У приватных плагинов, которые вы поддерживаете сами, нет официального канала обновлений. Советуем вести их в git и разворачивать прямо на сервере через git pull. Не правьте файлы на продакшене.
FAQ: частые вопросы
Когда стоит написать свой плагин, а не ставить сторонний?
Можно ли просто написать код в functions.php темы?
Сколько строк кода нужно для минимального рабочего плагина WordPress?
Плагин создал таблицы в базе — удалять их при удалении плагина самому?
Нужно ли публиковать приватный плагин на wordpress.org?
Почему мой код плагина выполняется на фронтенде при каждом запросе?
В заключение
Ценность собственного плагина не в показной сложности, а в том, чтобы вернуть под свой контроль небольшую логику, которую вы отдали сторонним плагинам. Обновление чужого плагина может изменить поведение, а свой код всегда остаётся у вас.
Три шага на практике: перенесите пользовательскую логику из functions.php в однфайловый плагин; если создали таблицы, напишите очистку в uninstall; приватный плагин соберите в zip или положите в mu-plugins и не отправляйте в официальный каталог ради галочки.
Частый вопрос: стоит ли писать плагины на Composer и фреймворках? Для лёгкого плагина под один клиентский сайт — нет.
Фреймворк означает лишние десятки мегабайт в каталоге vendor и постоянную поддержку зависимостей при каждом обновлении. Если задача решается в 300 строк, фреймворк только создаёт проблемы.
Composer и пространства имён оправданы только тогда, когда плагин делают публичным продуктом, покрывают юнит-тестами и разрабатывают командой.
Ещё немного о безопасности: обрабатывая формы в админке, обязательно вызывайте check_admin_referer для проверки nonce — это защита от подделки межсайтовых запросов. Это стандартное действие для админских форм WordPress, и без него админский интерфейс остаётся открытым.
Выводя пользовательский ввод на страницу, используйте функции экранирования esc_html, esc_attr и не выводите напрямую через echo. Даже значения из настроек, которые вы сами задали в админке, при выводе на фронтенде нужно экранировать.
И напоследок о порядке освоения. Начиная писать плагин, возьмитесь за чистые фильтры вроде смены отправителя или длины анонса — без базы данных и без страниц в админке.
Пройдите один полный цикл «написал код, загрузил, включил, увидел результат» и только потом добавляйте функции. Если сразу взяться за плагин с таблицами и админскими страницами, легко запутаться в хуках и жизненном цикле.
Чем меньше плагин, тем лучше. Перед каждой новой функцией спрашивайте себя: можно ли решить это двадцатью строками на существующих хуках? Если да — не создавайте таблицу, не добавляйте страницу в админке.
Держать код плагина в пределах 300 строк — ответственность и перед собой, и перед клиентом. Если объём больше, скорее всего, пора взять готовый сторонний плагин.
И ещё раз: не сваливайте пользовательскую логику в functions.php темы. Перенесите её в отдельный плагин — тогда тему можно будет спокойно менять, а клиент сможет сам поддерживать сайт долгие годы.
Фраза, которую стоит запомнить: если задача решается хуком в 20 строк, не тащите сторонний плагин на 5000 строк — чем меньше кода, тем меньше точек отказа.
