Как создать свой плагин WordPress с нуля: структура, хуки и активация

Как создать свой плагин WordPress с нуля: структура, хуки и активация

Кратко: плагин WordPress — это папка в wp-content/plugins с PHP-файлом, в шапке которого есть заголовок Plugin Name: по нему система находит плагин и показывает его в админке. Минимальный плагин — один файл, полноценный — несколько папок, класс и страница настроек. Дальше код подключается к движку через хуки add_action и add_filter, а включение и выключение сопровождают функции активации и деактивации. Ниже — весь путь с нуля: структура, код, безопасность и проверка.

Как устроен плагин WordPress: папка, файл, заголовок

Плагин — это обычный набор файлов, который расширяет возможности WordPress, не трогая ядро и тему. Все плагины живут в одной директории — wp-content/plugins. Чтобы WordPress увидел новый плагин, достаточно создать там папку и положить в неё PHP-файл с особым комментарием-заголовком: в нём указывают название, версию, автора и лицензию.

Никакой регистрации, компиляции и сборки не нужно. Когда вы открываете раздел «Плагины» в админке, WordPress сканирует директорию, читает заголовки файлов и строит список. Отсюда главное правило: если файл с корректной шапкой лежит в wp-content/plugins, плагин уже существует — его осталось активировать.

<?php
/**
 * Plugin Name: My First Plugin
 * Description: Учебный плагин: добавляет пометку в подвале сайта.
 * Version: 1.0.0
 * Author: Ваше имя
 * License: GPL-2.0-or-later
 * Text Domain: my-first-plugin
 */

Сохраните этот код в файл my-first-plugin.php внутри папки wp-content/plugins/my-first-plugin — и плагин появится в списке. Активировать его можно и без админки, из командной строки: одна команда WP-CLI заменяет несколько кликов. Основные команды собраны в гайде про WP-CLI для новичков.

wp plugin activate my-first-plugin

Структура плагина: какие файлы и папки завести сразу

Один файл хорош для пробы, но у растущего плагина быстро появляются свои части: код для админки, стили, переводы, служебные функции. Разложить их по папкам стоит с самого начала — через полгода вы скажете себе спасибо. Типовая структура выглядит так.

my-first-plugin/
  my-first-plugin.php — главный файл с заголовком
  includes/ — классы и функции
  admin/ — код административной части
  assets/ — CSS, JS и изображения
  languages/ — файлы переводов
  readme.txt — описание и история версий
  uninstall.php — очистка при удалении

Таблица подскажет, что где хранить и что действительно обязательно.

Элемент Зачем нужен Обязателен
Главный PHP-файл Заголовок плагина и точка входа, подключает остальные файлы Да
includes/ Классы, функции и интеграции — всё, что не относится к админке напрямую По мере роста
admin/ Страницы настроек, свои колонки, уведомления в админке Если есть настройки
assets/ Скрипты и стили, подключаются через wp_enqueue Если есть интерфейс
languages/ Файлы .po и .mo для переводов Для распространения
readme.txt Описание и история изменений для каталога WordPress.org Для публикации
uninstall.php Удаление опций и данных при удалении плагина Рекомендуется

Имя главного файла обычно повторяет имя папки: my-first-plugin/my-first-plugin.php. Тот же слаг используется как text domain — идентификатор для переводов. И сразу приучайте себя к префиксам: у всех функций плагина должно быть уникальное начало, например myfp_, иначе конфликт с чужим кодом почти неизбежен.

Несколько правил гигиены, которые сэкономят время:

  • имена папок и файлов — только латиница, цифры и дефисы;
  • префикс один для всего плагина, и он не должен совпадать с именами темы;
  • версию храните в одном месте — в заголовке и константе;
  • не смешивайте в одном файле админку и фронтенд.

Если раньше вы держали доработки в functions.php темы, есть смысл перенести функциональность в плагин: он не привязан к шаблону и переживает его обновление. Что уместно оставлять в теме, рассказано в гайде про полезные сниппеты для functions.php.

Точка входа: константы и защита от прямого доступа

PHP-файлы плагина теоретически можно открыть напрямую, минуя WordPress. Поэтому первым делом любой файл плагина проверяет константу ядра: если ABSPATH не определена, работа прекращается. Это правило номер один и для главного файла, и для каждого файла в includes.

<?php
if (!defined('ABSPATH')) {
    exit;
}

define('MYFP_VERSION', '1.0.0');

add_action('wp_footer', function () {
    echo '<p class="myfp-note">Работает My First Plugin</p>';
});

Константа версии пригодится для условной загрузки ресурсов: по ней браузер получает свежие файлы после обновления плагина. Обратите внимание: код начинает выполняться не сразу, а в момент, когда WordPress доходит до нужного хука. Вставлять вывод прямо в файл нельзя — к моменту его подключения страница ещё не сформирована.

Если вы сомневаетесь, где место коду — в плагине, теме или must-use расширении — сравнение ниже.

Место Переживает смену темы Можно выключить Когда выбирать
functions.php основной темы Нет Нет Никогда для функциональности: правки пропадут при обновлении
functions.php дочерней темы Да Нет Правки оформления и шаблонов
Обычный плагин Да Да Функциональность, шорткоды, интеграции
mu-plugin (must-use) Да Нет Служебный код, который должен работать всегда

Как безопасно править саму тему, чтобы обновления её не затирали, мы рассказывали в статье про дочернюю тему WordPress.

Хуки: как плагин встраивается в работу движка

Плагин не вызывается сам по себе — он «подписывается» на события WordPress. За подписку отвечают две функции: add_action добавляет своё действие в точку срабатывания, а add_filter пропускает через обработчик данные и ждёт их обратно изменёнными. Первый аргумент — имя хука, второй — функция-обработчик, третий — приоритет: чем меньше число, тем раньше выполнится код.

Хук Когда срабатывает Типичное применение
init После загрузки ядра, до вывода страницы Регистрация типов записей, шорткодов, переводов
admin_menu При построении меню админки Страницы настроек плагина
admin_enqueue_scripts При выводе страниц админки Стили и скрипты для настроек
wp_enqueue_scripts При выводе сайта Подключение CSS и JS фронтенда
the_content При выводе содержимого записи Пометки, кнопки, врезки в текст
register_activation_hook Один раз при активации плагина Опции по умолчанию, таблицы, правила ссылок
register_deactivation_hook При деактивации плагина Снятие запланированных задач

Классический пример — пометка после текста записи. Фильтр the_content получает готовый HTML и возвращает его же, дополненным.

add_filter('the_content', function ($content) {
    if (is_singular('post')) {
        $content .= '<p class="myfp-note">Материал проверен редакцией.</p>';
    }
    return $content;
});

Хуки умеют не только добавлять, но и убирать чужое поведение: подписку снимает remove_action с тем же приоритетом. Так, вывод версии WordPress из шапки сайта отключается одной строкой.

remove_action('wp_head', 'wp_generator');

Заучивать список хуков не нужно: нужную точку ищут в документации или в коде ядра по шаблону do_action и apply_filters. Как устроены действия и фильтры, подробно разобрано в статье про хуки WordPress: actions и filters.

Активация и деактивация: что выполняется один раз

У плагина есть жизненный цикл: установка, активация, работа, деактивация, удаление. Активация — единственный момент, когда код выполняется гарантированно один раз. Здесь создают опции по умолчанию, вспомогательные таблицы и роли, сбрасывают правила ссылок. Подписка на событие — register_activation_hook, в колбэк приходит путь к главному файлу плагина.

register_activation_hook(__FILE__, function () {
    if (false === get_option('myfp_welcome_text')) {
        update_option('myfp_welcome_text', 'Спасибо за визит!');
    }
    flush_rewrite_rules();
});

Сброс правил ссылок нужен всем, кто регистрирует свои типы записей или адреса: без flush_rewrite_rules новые страницы будут отдавать 404, пока кто-нибудь вручную не пересохранит настройки постоянных ссылок.

Деактивация — это не удаление: плагин выключают временно, и данные должны уцелеть. Здесь корректно снять запланированные задачи и очистить временное, ничего не стирая из базы.

register_deactivation_hook(__FILE__, function () {
    wp_clear_scheduled_hook('myfp_daily_sync');
});

А вот удаление — повод прибраться по-настоящему. Файл uninstall.php в корне плагина WordPress выполнит только при удалении через админку; в нём удаляют опции, таблицы и права, которые больше не нужны.

<?php
if (!defined('WP_UNINSTALL_PLUGIN')) {
    exit;
}

delete_option('myfp_welcome_text');

И главное правило производительности: тяжёлые операции — создание таблиц, массовые запросы, проверка окружения — выполняются при активации, а не при каждом открытии страницы. Для повторяющихся задач используйте планировщик wp-cron.

От функций к классу: как организовать растущий плагин

Пока в плагине пять строк, функции с префиксом — нормальный вариант. Когда их десятки, на помощь приходит класс: он собирает связанные функции вместе и сам подписывает их на хуки в конструкторе.

class MyFP_Plugin {
    public function __construct() {
        add_action('init', array($this, 'register_shortcodes'));
        add_filter('the_content', array($this, 'append_note'));
    }

    public function register_shortcodes() {
        add_shortcode('myfp_greeting', array($this, 'render_greeting'));
    }

    public function append_note($content) {
        if (is_singular('post')) {
            $content .= '<p class="myfp-note">Материал проверен редакцией.</p>';
        }
        return $content;
    }

    public function render_greeting() {
        return '<p>Привет от My First Plugin!</p>';
    }
}

new MyFP_Plugin();

Обратите внимание на запись array($this, ‘method’): так WordPress понимает, что обработчиком должен стать метод объекта, а не отдельная функция. Главный файл при этом остаётся тонким — он только подключает файлы из includes через require_once и запускает класс. Современная альтернатива ручным подключениям — автозагрузка по стандарту PSR-4, но для первого плагина достаточно и списка require_once.

Если класс добавляет шорткод, как в примере, параметры и вывод подробно разобраны в гайде про создание своих шорткодов в WordPress. А стили и скрипты для интерфейса подключайте только штатно — через wp_enqueue_scripts и правильное подключение CSS и JS.

Страница настроек в админке: меню и Settings API

Хорошему плагину нужен интерфейс: место, где владелец сайта включает опции, не заглядывая в код. Страницы в админке добавляет хук admin_menu, а хранение и проверку значений берёт на себя Settings API — встроенный механизм, который сам обрабатывает сохранение формы и защищает её от подделки.

add_action('admin_menu', function () {
    add_options_page(
        'My First Plugin',
        'My First Plugin',
        'manage_options',
        'myfp-settings',
        'myfp_render_settings_page'
    );
});

add_action('admin_init', function () {
    register_setting('myfp_settings', 'myfp_welcome_text', array(
        'type' => 'string',
        'sanitize_callback' => 'sanitize_text_field',
    ));
});

Если плагин собран в класс, последним аргументом вместо имени функции передаётся массив с методом — array($this, ‘метод’). Функция вывода рисует обычную админскую форму: три вызова — settings_fields, do_settings_sections и submit_button — делают её полностью рабочей, сохранение и проверка уже внутри.

function myfp_render_settings_page() {
    ?>
    <div class="wrap">
        <h1>Настройки My First Plugin</h1>
        <form method="post" action="options.php">
            <?php
            settings_fields('myfp_settings');
            do_settings_sections('myfp_settings');
            submit_button();
            ?>
        </form>
    </div>
    <?php
}

Если настроек много, одной страницей не обойтись: add_menu_page создаёт верхний уровень меню, add_submenu_page — вложенные разделы. Для интерфейсов, которые сохраняются без перезагрузки страницы, пригодится техника из статьи про AJAX в WordPress и admin-ajax.

Безопасность плагина: четыре привычки, которые спасают

Плагин работает с пользовательскими данными, поэтому первое правило — никому не доверять на входе. Большинство проблем закрывают четыре привычки: проверка прав, nonce, очистка данных и экранирование вывода.

Права доступа. Любое действие в админке проверяйте через current_user_can: сохранять настройки может только роль с правом manage_options, редактировать записи — те, кому это разрешено. Подробнее о ролях — в статье про пользовательские роли и права доступа.

Nonce. Скрытое одноразовое число защищает формы от подделки запроса: wp_nonce_field добавляет его в разметку, wp_verify_nonce проверяет при обработке. У форм Settings API эта защита встроена, для собственных обработчиков nonce добавляют вручную.

Очистка входных данных. Всё, что пришло из $_POST, $_GET или $_REQUEST, пропускают через санитайзеры: sanitize_text_field для строк, absint для чисел, esc_url_raw для адресов.

Экранирование вывода. Перед печатью данных в HTML их прогоняют через esc_html, esc_attr или esc_url — тогда даже вредоносная строка из базы останется текстом и не выполнится как разметка.

if (!isset($_POST['myfp_nonce']) || !wp_verify_nonce($_POST['myfp_nonce'], 'myfp_save')) {
    wp_die('Проверка безопасности не пройдена.');
}
if (!current_user_can('manage_options')) {
    wp_die('Недостаточно прав.');
}
$value = sanitize_text_field(wp_unslash($_POST['myfp_value']));
update_option('myfp_welcome_text', $value);

Отдельная зона — запросы к базе: значения подставляйте в SQL только через метод prepare у объекта $wpdb, который экранирует параметры автоматически. Общие приёмы защиты сайта собраны в статье про безопасность WordPress для новичков.

Проверка и отладка: как убедиться, что плагин готов

Перед установкой на боевой сайт плагин стоит прогнать через простой чек-лист. Сначала включите отладку: константы в wp-config.php покажут замечания PHP и предупреждения WordPress, которые в обычном режиме скрыты.

define('WP_DEBUG', true);
define('WP_DEBUG_LOG', true);
define('WP_DEBUG_DISPLAY', false);

С такой настройкой ошибки записываются в файл wp-content/debug.log, а не ломают вёрстку у посетителей. Как читать этот файл и находить виновника — по шагам в статье про WP_DEBUG и отладку WordPress.

Второй помощник — плагин Query Monitor: он показывает, сколько запросов к базе делает ваш код, какие хуки сработали и откуда пришла ошибка. Третий — официальный Plugin Check, который проверяет плагин по требованиям каталога WordPress.org: безопасность, экранирование, текстовые домены.

wp plugin install plugin-check --activate
wp plugin check my-first-plugin

Пройдитесь по чек-листу перед включением на рабочем сайте:

  • в debug.log нет предупреждений, связанных с плагином;
  • все входные данные очищаются, весь вывод экранируется;
  • у функций и классов — уникальные префиксы, конфликтов нет;
  • Plugin Check не выдаёт критичных замечаний;
  • есть свежий бэкап и копия сайта для экспериментов.

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

TimeWeb

Частые вопросы о создании плагина WordPress

С чего начать создание плагина WordPress?

Создайте в wp-content/plugins папку и положите в неё PHP-файл с заголовком Plugin Name — этого достаточно, чтобы плагин появился в админке. Затем добавьте проверку ABSPATH, определите префикс для функций и подпишите первую функцию на хук. Минимальный плагин — один файл; по мере роста его дополняют папками includes, admin и assets.

Чем плагин лучше кода в functions.php?

Код в плагине не привязан к теме: смена шаблона его не затронет, плагин включается и выключается из админки и переносится на другой сайт. Функциональность — типы записей, шорткоды, интеграции — принято выносить в плагин, а в functions.php дочерней темы оставлять только оформление.

Какие хуки нужно знать, чтобы написать плагин?

Для старта достаточно набора: init — регистрация возможностей, admin_menu — страницы в админке, admin_enqueue_scripts — ресурсы админки, the_content — правка вывода, wp_enqueue_scripts — ресурсы сайта, плюс хуки активации и деактивации. Остальные находятся по мере задач: ищите do_action и apply_filters в коде ядра и документации.

Что должно происходить при активации плагина?

Всё, что нужно сделать один раз: задать опции по умолчанию, при необходимости создать таблицы или роли, сохранить версию, сбросить правила ссылок через flush_rewrite_rules. Тяжёлые операции не должны выполняться на каждом запросе — для повторяющихся задач есть планировщик wp-cron.

Почему у функций плагина должен быть префикс?

PHP собирает все функции сайта в одно пространство имён, и короткое имя вроде get_data() почти наверняка столкнётся с темой или другим плагином — сайт упадёт с фатальной ошибкой. Уникальный префикс (например, myfp_) или классы решают проблему: риск конфликтов при обновлениях чужих расширений становится минимальным.

Как защитить формы и данные в плагине?

Проверяйте права через current_user_can, добавляйте в формы nonce и проверяйте его при обработке, очищайте входные данные санитайзерами (sanitize_text_field, absint) и экранируйте вывод (esc_html, esc_attr, esc_url). Для запросов к базе используйте метод prepare у объекта $wpdb — он экранирует подстановки автоматически.

Вывод

Свой плагин WordPress начинается с папки в wp-content/plugins и файла с заголовком Plugin Name — дальше добавляются структура, хуки, функции активации и деактивации, класс для порядка и страница настроек для удобства. Безопасность и отладка — не финальный штрих, а часть работы: nonce, очистка данных, экранирование и Plugin Check сопровождают плагин с первой версии.

Начните с маленького плагина под собственную задачу: пометка в записях, свой шорткод, простая настройка. Прогоните его через отладку, проверьте на копии сайта и только потом ставьте на рабочий проект. Так вы освоите механику WordPress без риска для боевого сайта.

А если нужен готовый плагин или доработка под задачи бизнеса — это к нам. Мы разрабатываем сайты и расширения на WordPress, интегрируем их с внешними сервисами и поддерживаем уже работающие проекты. Посмотрите услуги по разработке сайтов на WordPress, примеры выполненных проектов собраны в портфолио работ, а полезные материалы — в блоге о разработке сайтов. Нужна доработка существующего сайта? Можно заказать доработку сайта у программиста или описать задачу через форму обратной связи.

Clearfy

Поделиться:
Telegram ВКонтакте