Свой плагин в WordPress: рабочие приёмы
Небольшой плагин для WordPress можно собрать без правок темы и опасных хакающих вставок. Разбираем структуру файлов, хуки, настройки, подключение ресурсов и ошибки, из-за которых расширение ломает сайт.

Если нужно добавить в WordPress поле в админке, кнопку на странице или автоматическую обработку записи, не вставляйте код в functions.php темы. Рабочий плагин отделяет логику от оформления, переживает смену темы и позволяет отключить функцию одним переключателем. Ниже — практический каркас для WordPress 6.x и PHP 8.1+: от одного файла до настроек, скриптов и безопасного вывода.
Сначала выберите границу плагина
Плагин не должен превращаться в склад случайных функций. Перед созданием каталога запишите одно предложение: «Этот плагин добавляет X и не отвечает за Y». Например, плагин может добавлять служебную пометку к записям, но не должен одновременно менять шаблон магазина, оптимизировать изображения и отправлять письма.
У WordPress есть несколько способов добавить поведение. Они решают разные задачи и по-разному влияют на поддержку проекта.
| Подход | Когда использовать | Цена решения |
|---|---|---|
| Один файл плагина | Небольшая функция без сложного интерфейса | Быстрый старт, но файл быстро разрастается |
| Плагин с классом | Несколько хуков, настройки, интеграции | Нужно следить за состоянием объекта и именами методов |
| Плагин с отдельными модулями | Большой проект с админкой и публичной частью | Лучше поддерживаемость, но больше файлов и правил сборки |
| Код в functions.php | Только временная проверка в дочерней теме | Функция исчезнет или изменится при смене темы |
Хук — точка, в которой WordPress передаёт управление вашему коду. Action запускает действие, а filter позволяет изменить значение и вернуть его обратно. Например, add_action() подходит для регистрации меню, а add_filter() — для изменения текста.
Хороший плагин можно отключить без белого экрана, а его основную функцию — найти по одному имени, а не по десяткам безымянных фрагментов.
Минимальный каркас: один файл и один хук
Создайте каталог wp-content/plugins/site-notice и файл site-notice.php. Заголовок в комментарии нужен WordPress, чтобы показать расширение на странице «Плагины». Пример рассчитан на WordPress 6.x и PHP 8.1+.
<?php
/**
* Plugin Name: Site Notice
* Description: Добавляет служебную пометку к содержимому записи.
* Version: 1.0.0
* Requires at least: 6.0
* Requires PHP: 8.1
*/
defined( 'ABSPATH' ) || exit;
function site_notice_append_text( string $content ): string {
if ( ! is_singular( 'post' ) || ! in_the_loop() || ! is_main_query() ) {
return $content;
}
$notice = '<p class="site-notice">' . esc_html__( 'Материал подготовлен редакцией.', 'site-notice' ) . '</p>';
return $content . $notice;
}
add_filter( 'the_content', 'site_notice_append_text' );
В этом примере проверка стоит внутри обработчика, а не только при регистрации фильтра. Так код не добавит пометку в анонсы, виджеты и вторичные циклы записей. Функция возвращает строку всегда: это обязательное правило для фильтра.
Что проверить после активации
- В каталоге есть файл с тем же именем, что и в инструкции.
- В админке на странице «Плагины» появился Site Notice.
- После активации обычная запись содержит пометку в конце.
- Главная страница и список записей не получили повторяющийся текст.
Не смешивайте логику и вывод
На маленьком проекте одна функция допустима. Когда появляются настройки или несколько хуков, разделите ответственность: одна часть получает значение, другая проверяет контекст, третья выводит HTML. Это не формальность. Такой код проще отключить, протестировать и перенести на другой сайт.
Для публичного вывода используйте экранирование в момент вывода, а не при сохранении. HTML-атрибуты, обычный текст и URL требуют разных функций.
esc_html()— текст внутри HTML.esc_attr()— значение HTML-атрибута.esc_url()— URL, который выводится на странице.wp_kses_post()— ограниченный HTML, если редактору разрешены базовые теги.
Для внутренних имён добавляйте уникальный префикс: site_notice_. Не называйте функцию просто render() или settings(): другой плагин может объявить такую же функцию, и сайт завершится ошибкой о повторном объявлении.
Настройки: сохраняйте только нужное
Настройки лучше хранить в одной опции с понятным ключом. Ниже — фрагмент для страницы настроек. Он использует стандартные API WordPress 6.x: регистрацию настройки, секцию и поле формы.
<?php
function site_notice_register_settings(): void {
register_setting(
'site_notice_options_group',
'site_notice_options',
array(
'type' => 'array',
'sanitize_callback' => 'site_notice_sanitize_options',
'default' => array(
'text' => '',
'enabled' => false,
),
)
);
add_settings_section(
'site_notice_main_section',
'Параметры пометки',
'__return_false',
'site-notice'
);
add_settings_field(
'site_notice_text',
'Текст',
'site_notice_text_field',
'site-notice',
'site_notice_main_section'
);
}
add_action( 'admin_init', 'site_notice_register_settings' );
function site_notice_sanitize_options( array $input ): array {
return array(
'text' => isset( $input['text'] ) ? sanitize_text_field( $input['text'] ) : '',
'enabled' => ! empty( $input['enabled'] ),
);
}
function site_notice_text_field(): void {
$options = get_option( 'site_notice_options', array() );
$text = isset( $options['text'] ) ? (string) $options['text'] : '';
$enabled = ! empty( $options['enabled'] );
?>
<input type="text" name="site_notice_options[text]" value="<?php echo esc_attr( $text ); ?>" class="regular-text">
<label>
<input type="checkbox" name="site_notice_options[enabled]" value="1" <?php checked( $enabled ); ?>>
Показывать пометку
</label>
<?php
}
Фрагмент не создаёт страницу меню сам по себе. Её можно добавить через add_menu_page() или встроить настройки в существующий раздел. В обработчике страницы должны быть settings_fields(), do_settings_sections() и кнопка сохранения.
<?php
function site_notice_settings_page(): void {
if ( ! current_user_can( 'manage_options' ) ) {
return;
}
?>
<div class="wrap">
<h1>Site Notice</h1>
<form action="options.php" method="post">
<?php
settings_fields( 'site_notice_options_group' );
do_settings_sections( 'site-notice' );
submit_button( 'Сохранить' );
?>
</form>
</div>
<?php
}
Проверка current_user_can() нужна даже на скрытой странице. Скрытое меню не является защитой. Для текстового поля используется sanitize_text_field(); если вы разрешаете HTML, замените санитизацию на подходящую для вашей разметки и ограничьте допустимые теги.
Подключайте CSS и JavaScript только там, где они нужны
Не добавляйте стили через строку в wp_head и не загружайте файл плагина на каждой странице админки. Регистрируйте ресурс через очередь WordPress и ограничивайте его условием. Для панели настроек проверяйте, что открыт именно ваш экран.
<?php
function site_notice_enqueue_admin_assets( string $hook_suffix ): void {
if ( 'settings_page_site-notice' !== $hook_suffix ) {
return;
}
wp_enqueue_style(
'site-notice-admin',
plugins_url( 'assets/admin.css', __FILE__ ),
array(),
'1.0.0'
);
}
add_action( 'admin_enqueue_scripts', 'site_notice_enqueue_admin_assets' );
Название экрана зависит от того, как вы зарегистрировали меню. После добавления страницы проверьте значение аргумента $hook_suffix через временный журнал или сопоставьте его с документацией WordPress. Не оставляйте отладочный вывод на рабочем сайте.
Что обычно ломается
Белый экран после активации
Чаще всего это синтаксическая ошибка PHP, повторное имя функции или вызов кода, доступного только в другой версии PHP. Включите журналирование в тестовой среде, проверьте последнюю изменённую строку и убедитесь, что файл начинается с корректного PHP-тега. Не показывайте текст ошибки посетителям.
Функция срабатывает дважды
Причина обычно в двойной регистрации одного обработчика или в том, что фильтр применяется и к основной записи, и к вторичному циклу. Добавьте условия вроде is_main_query() и in_the_loop(), а затем проверьте страницу записи, архив и виджет отдельно.
Настройка не сохраняется
Проверьте совпадение имени группы в register_setting() и settings_fields(). Затем проверьте права пользователя и имя поля в HTML. Если чекбокс выключен, браузер не отправляет его значение — поэтому код должен трактовать отсутствие ключа как false.
CSS или JavaScript грузится везде
Это не только лишний запрос. Скрипт может конфликтовать с редактором, таблицей или другим плагином. Ограничьте загрузку по экрану админки или по условию конкретного шаблона. Для публичной части используйте отдельный хук и отдельный идентификатор ресурса.
Когда один файл пора разделять
Разделение нужно не по числу строк, а по ответственности. Если в одном файле уже находятся обработчики записи, меню, настройки, REST-эндпоинт и подключение ресурсов, ошибка в одной части начинает влиять на остальные. Разнесите код хотя бы на файлы admin.php, public.php и settings.php, а общие константы оставьте в главном файле.
Класс полезен, когда нужно хранить общие зависимости и регистрировать несколько методов. Но класс сам по себе не делает код безопаснее: права, проверка входных данных, экранирование и контроль контекста всё равно остаются обязанностью разработчика.
Что делать дальше
Сначала установите плагин на копию сайта, а не на рабочий домен. Проверьте активацию, деактивацию, обновление WordPress и конфликт с активной темой. Затем добавьте резервное копирование базы и журналирование только для ошибок. В проде смотрите на время ответа страницы, PHP-ошибки и число запросов, которые добавляет расширение.
Если плагин хранит настройки, опишите формат опции и путь миграции до первого релиза. Если он меняет данные, продумайте деактивацию отдельно: отключение плагина не всегда должно удалять записи из базы. Инвалидация кеша и удаление данных при uninstall — отдельные темы; здесь важно не смешивать их с обычной логикой вывода.
Создатель презентаций: Структура и текст каждого слайда: заголовки-утверждения, одна мысль на слайд, заметки докладчику.
Спросить за 150 ₽Источники: Plugin Handbook — официальная документация WordPress, WordPress Code Reference
Частые вопросы
Можно ли писать плагин только в functions.php?
Какая версия WordPress нужна для этих примеров?
Что делать, если после активации появился белый экран?
Почему настройки сохраняются, но ничего не меняется на сайте?
Нужно ли удалять настройки при деактивации плагина?
Можно ли подключать CSS и JavaScript через wp_head?
Материал носит информационный характер и подготовлен редакцией «Агентуры». Он не является офертой, рекламой или индивидуальной консультацией. Упомянутые продукты, компании и торговые знаки принадлежат их правообладателям. Перед принятием решений, влекущих юридические или финансовые последствия, обратитесь к профильному специалисту.