Разработка собственных плагинов WordPress: структура, хуки и публикация лёгких плагинов

Для многих «мелких доработок» на своём сайте вообще не нужно ставить сторонние плагины — хватит одного файла до 300 строк. Критерий простой: если задача затрагивает больше пяти независимых функций, тогда стоит разбивать на структуру каталогов, иначе достаточно одного php-файла с заголовочным комментарием плагина.

自研轻量插件:结构、钩子与发布Lightweight custom plugin: structure, hooks, ship 能用20行钩子解决的事,别装一个5000行的第三方插件Solve it in 20 hook lines instead of a 5000-line plugin 1 主文件1 Main file 插件头注释 + 常量定义Header comment + constants 单文件插件不超过300行Single file under 300 lines 2 钩子2 Hooks add_action / add_filteradd_action / add_filter 后台钩子别挂在前台请求上No admin hooks on frontend 3 激活卸载3 Activate / deactivate register_activation_hookregister_activation_hook 卸载钩子清理自己的表Uninstall hook cleans up 发布方式Shipping 私有插件不上wordpress.orgPrivate plugins skip wp.org 打zip上传 或git拉到mu-pluginsZip upload or mu-plugins 红线Red lines 别改主题functions.phpDo not edit theme functions.php 别在前台直接写SQL不过滤Never run raw SQL unescaped 判定:需求>5个独立功能才拆插件目录,否则单文件插件足够Decision: 5+ features justify a folder, else single file 反直觉:functions.php越写越长不是熟练,是在给下次换主题埋雷Counterintuitive: long functions.php kills the next theme swap 把自定义逻辑从主题搬进插件,主题才能放心换Move logic out of theme into plugins
Структура файлов, места подключения хуков и способы публикации лёгких плагинов WordPress

Разработка собственных плагинов WordPress: структура, хуки и публикация лёгких плагинов

Сначала вывод: Для многих «мелких доработок» на своём сайте вообще не нужно ставить сторонние плагины — хватит одного файла до 300 строк. Критерий простой: если задача затрагивает больше пяти независимых функций, тогда стоит разбивать на структуру каталогов, иначе достаточно одного php-файла с заголовочным комментарием плагина. Контринтуитивный момент: складывать код в functions.php темы кажется проще, но при смене темы вся эта логика исчезнет.

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: частые вопросы

Когда стоит написать свой плагин, а не ставить сторонний?
Если нужно изменить всего пару фиксированных вещей — например, адрес отправителя, добавить свой JS или изменить длину анонса, — чище написать однфайловый плагин строк на 300. Разбивать на структуру каталогов стоит, только если функций больше пяти или нужна страница настроек в админке. А для сложных форм, SEO и других типовых задач ставьте готовый плагин.
Можно ли просто написать код в functions.php темы?
Нет. functions.php привязан к теме: при её обновлении или смене весь ваш код пропадёт. Именно поэтому логику выносят в отдельный плагин. Плагин не зависит от темы, и при смене темы код продолжает работать. Если написать в functions.php ради экономии времени, при следующей смене темы всё придётся переписывать.
Сколько строк кода нужно для минимального рабочего плагина WordPress?
Однфайловому плагину достаточно одного php-файла с комментарием-заголовком (Plugin Name, Description, Version) и нужных хуков add_action или add_filter. Для смены адреса отправителя хватит 10 строк. Положите файл в каталог wp-content/plugins/ — и он появится в админке, где его можно включить.
Плагин создал таблицы в базе — удалять их при удалении плагина самому?
Да. Создайте в каталоге плагина uninstall.php и напишите там DROP TABLE и delete_option. register_activation_hook отвечает за создание таблиц при включении, uninstall.php — за очистку данных при удалении. Учтите: deactivate только отключает плагин и данные не удаляет, а uninstall удаляет — не путайте эти два действия.
Нужно ли публиковать приватный плагин на wordpress.org?
Не нужно. Для отдельного клиентского сайта достаточно собрать приватный плагин в zip, загрузить его через админку или положить в каталог wp-content/mu-plugins. MU-плагины включены по умолчанию и их нельзя случайно отключить, поэтому они подходят для основной бизнес-логики. В каталог wordpress.org отправляют только универсальные публичные плагины, которыми должны пользоваться другие.
Почему мой код плагина выполняется на фронтенде при каждом запросе?
Скорее всего, вы повесили админскую логику на глобальные хуки вроде init или plugins_loaded. Код только для админки должен висеть на admin_init или admin_menu — они срабатывают лишь внутри wp-admin. Для подключения CSS/JS на фронтенде используйте wp_enqueue_scripts и не выводите теги напрямую через echo внутри хука.

В заключение

Ценность собственного плагина не в показной сложности, а в том, чтобы вернуть под свой контроль небольшую логику, которую вы отдали сторонним плагинам. Обновление чужого плагина может изменить поведение, а свой код всегда остаётся у вас.

Три шага на практике: перенесите пользовательскую логику из 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 строк — чем меньше кода, тем меньше точек отказа.

crater
crater Эксперт Crater

Официальный аккаунт организации · crater Crater

环形山 (Crater) — компания, которая помогает выходить на зарубежные рынки: разработка сайтов на WordPress, Google SEO и комплексный рост в GEO. Мы работаем с умными устройствами, промышленным оборудованием, SaaS и новой энергетикой.

Возможности продуктаБелая книга по методологииОтраслевые отчёты
965篇分享
78статей в базе знаний