Инфраструктурный код не должен зависеть от капризов интерфейса или случайного клика в админке. https://seberd.ru/27698 статья написана ИИ на основе заметок из блокнота, что бы как то структурировать в документацию. Нейросеть взяла на себя рутину по расстановке заголовков и смысловых связок, но вся фактура, названия хуков и конкретные кейсы из продакшена остались нетронутыми.
Разработка на WordPress часто начинается с установки готовых решений из официального репозитория. По мере роста проекта и усложнения требований к безопасности и производительности стандартный подход перестаёт работать. Обычные плагины требуют активации, могут быть случайно отключены или скомпрометированы через уязвимости в графическом интерфейсе. На определённом этапе разработки возникает необходимость внедрить правила, которые применяются на уровне самого сервера и не могут быть изменены через административную панель. Для подобных задач существуют must-use решения.
Под MU-плагинами (Must-Use plugins) понимают специфический тип расширений для WordPress, которые располагаются в директории wp-content/mu-plugins. Ядро системы автоматически подхватывает и выполняет любой PHP-файл, находящийся в этой папке. Никакой активации через графический интерфейс не требуется. Код загружается всегда, независимо от состояния базы данных или настроек пользователя.
Подобный подход решает фундаментальную проблему разделения ответственности. Обычные плагины отвечают за функциональность, которую можно включать и выключать по желанию владельца сайта. Must-use модули отвечают за правила среды выполнения. Они формируют базовый уровень безопасности, определяют лимиты памяти, блокируют нежелательные эндпоинты и управляют кэшированием.
Отличие от обычных расширений кроется в механизме загрузки. Стандартные плагины инициализируются после загрузки ядра и темы. MU-модули выполняются на самом раннем этапе жизненного цикла WordPress, сразу после загрузки базовых констант и до инициализации темы. Разработчик получает возможность перехватывать запросы и модифицировать поведение системы до того, как к ней обратятся другие компоненты.
Чем mu-плагины отличаются от обычных и сетевых
Путаница часто возникает при сравнении must-use модулей с сетевыми плагинами в мультисайтовых сборках. Сетевое расширение можно активировать для всей сети или для отдельных сайтов. Администратор сети сохраняет контроль над его состоянием. Must-use решения не имеют понятия активации. Они работают глобально для всего экземпляра WordPress и не отображаются в стандартном списке плагинов.
Существует ещё один класс файлов, которые часто путают с MU-модулями. Речь идёт о drop-in файлах. Drop-in представляют собой заменяемые файлы ядра, такие как advanced-cache.php или db.php. Они полностью подменяют собой внутренние функции WordPress. Например, advanced-cache.php перехватывает механизм кэширования страниц. Must-use модули не подменяют функции ядра. Они просто добавляют свой код в процесс выполнения.
Drop-in файлы при обновлении WordPress могут быть затёрты или потерять совместимость с новой версией системы. MU-плагин остаётся нетронутым при обновлении ядра, что делает его идеальным местом для хранения кастомной логики, которая должна пережить миграцию на новый сервер или обновление CMS.
Какие задачи закрывают must-use решения
Область применения must-use архитектуры ограничивается инфраструктурными задачами. Сюда никогда не попадают пользовательские функции вроде вывода слайдеров или форм обратной связи.
Безопасность и скрытие следов. Блокировка вывода версии WordPress в мета-тегах и RSS-лентах. Отключение XML-RPC для предотвращения атак перебором паролей. Жёсткая фильтрация REST API, например, закрытие эндпоинта /wp/v2/users от анонимных пользователей. Все подобные задачи выполняются до того, как страница начнёт формироваться.
Управление средой выполнения. Принудительное задание лимитов памяти PHP, переопределение путей к временным файлам, настройка констант для объектного кэша. Объектный кэш позволяет сохранять результаты сложных запросов к базе данных в оперативной памяти, что критически важно для высоконагруженных проектов.
Жёсткие ограничения доступа. Скрытие административной панели от подписчиков, принудительный редирект на главную страницу при попытке прямого доступа к wp-admin. Блокировка поиска по базе данных внутри админки для ролей, не обладающих правами администратора.
Веб-сервер действительно обработает редирект или блокировку быстрее. Конфигурация Nginx привязана к конкретному хостингу и усложняет миграцию проекта. MU-плагин путешествует вместе с файлами сайта, гарантируя сохранение политик безопасности при переезде на новую инфраструктуру.

Порядок загрузки и управление приоритетами
WordPress использует стандартную функцию чтения директории, которая возвращает файлы в алфавитном порядке. Именно в таком порядке ядро подключает MU-модули. Подобная особенность одновременно является и удобством, и скрытой ловушкой.
Разработчики используют числовые префиксы в именах файлов для управления порядком выполнения. Файл 00-security-core.php загрузится раньше, чем 10-rest-hardening.php. Разработчик получает возможность выстраивать зависимости между модулями без использования сложных механизмов автозагрузки.
Хук admin_init срабатывает после загрузки административной панели, но до отправки любого контента в браузер. Перехват запроса на этой стадии позволяет остановить неавторизованного пользователя до того, как он увидит интерфейс. Приоритет хука (hook priority) определяет порядок выполнения функций, привязанных к одному событию. Установка приоритета 1 гарантирует, что функция сработает раньше большинства стандартных обработчиков WordPress.
Алфавитная сортировка становится источником трудноуловимых ошибок. Если два файла вешают обработчики на один хук с одинаковым приоритетом и файл d*.php загружается раньше s*.php, а первый делает редирект с exit, второй никогда не выполнится. Именно подобный конфликт возникает между disable-home-pagination.php и pagination-hardening.php: первый безусловно редиректил главную с пагинацией и прерывал выполнение, второй с более умной логикой никогда не доходил до работы.
Что считается лучшей практикой: полный набор для production-сайта
Ниже приведён типовой состав mu-плагинов для серьёзного WordPress-проекта. Таблица составлена на основе реальной инфраструктуры образовательной платформы с 900+ материалами, собственным поиском и многоуровневой системой ролей.
|
Файл |
Категория |
Что делает |
Ключевые хуки |
|---|---|---|---|
|
|
Безопасность |
Скрывает версию WP из HTML, RSS, футера админки. Заменяет |
|
|
|
Безопасность |
Отключает XML-RPC полностью. Редиректит |
|
|
|
Безопасность |
Строгий CORS — только свой домен. Отключает sitemap авторов |
|
|
|
Безопасность / Кэш |
Запрещает кэширование чувствительных REST-маршрутов на уровне Nginx и CDN |
|
|
|
Безопасность |
Блокирует |
|
|
|
Безопасность |
Защищает |
|
|
|
Безопасность |
Отдаёт |
|
|
|
Безопасность |
Принуждает всех администраторов включить 2FA. Мягкий режим: баннер. Строгий: блокировка всей админки кроме профиля |
|
|
|
Безопасность / UX |
Реализует PRG-паттерн при сбое 2FA, очищает промежуточные куки, выводит понятное сообщение на русском, логирует события в JSON |
|
|
|
Доступ |
Единственный контроллер доступа к wp-admin. Подписчики получают редирект 302 на главную. Авторы получают строгий whitelist страниц. Страницы плагинов возвращают 403 |
|
|
|
Доступ / UX |
Редирект после входа и регистрации. Скрывает admin bar на фронте. Кнопка «← На сайт» в Gutenberg через React API с DOM-fallback |
|
|
|
Производительность |
Убирает из |
|
|
|
Производительность |
Файловый full-page cache для анонимов. Атомарная запись через |
|
|
|
Производительность |
Дифференцированные |
|
|
|
SEO / Производительность |
Редирект за пределы реального контента. |
|
|
|
Безопасность |
Повышает минимальную capability для MCP/Abilities с |
|
|
|
Поиск |
Интеграция Meilisearch вместо медленного |
|
|
|
Контент |
Автоматически назначает рубрики записям по заголовку. Защита от рекурсии через статический флаг. WP-CLI команда для массовой обработки |
|
|
|
Монетизация |
Условная загрузка скриптов РСЯ только там, где реклама разрешена. Инициализация через |
|
|
|
Дистрибуция |
RSS-лента под требования Яндекс Дзен: |
|
Итого двадцать файлов покрывают семь направлений: безопасность аутентификации, защита API, контроль доступа по ролям, производительность и кэш, SEO, поиск, дистрибуция контента. Каждый файл решает ровно одну задачу и не знает о существовании других.
Практика создания безопасных mu-модулей
Написание кода для must-use архитектуры требует особой дисциплины. Ошибка в обычном плагине может сломать его самого. Фатальная ошибка в MU-модуле обрушит весь сайт, сделав его недоступным даже для администратора.
Первое правило предполагает обязательную проверку константы ABSPATH. Эта константа определяется ядром WordPress. Проверка предотвращает прямой запуск файла через браузер, что исключает возможность выполнения произвольного кода злоумышленником.
Второе правило запрещает использование глобальных переменных. Глобальное пространство имён WordPress и без того переполнено. Весь код должен быть обёрнут в функции или анонимные замыкания. Имена функций должны содержать уникальный префикс проекта, иначе конфликт с другим плагином неизбежен.
Третье правило касается осторожности с exit внутри хуков. Каждый досрочный выход прерывает не только текущий запрос, но и все последующие обработчики, зарегистрированные на тот же хук. Особенно опасно подобное поведение в template_redirect: если два файла вешают обработчики на priority 1, тот что загрузится первым (алфавитно) заблокирует второй навсегда.
Четвёртое правило требует не изобретать контроль доступа в нескольких местах. Один файл должен быть единственным источником правды для каждой политики. Если и seberd-user-redirect.php, и hide-admin-pages.php независимо проверяют одно и то же на admin_init с одинаковым приоритетом, они неизбежно разойдутся в логике и создадут ошибки, которые невозможно воспроизвести стабильно.
Ошибки при внедрении must-use архитектуры
Главная ошибка заключается в попытке поместить в mu-plugins код, требующий пользовательского интерфейса. Must-use модули не имеют страницы настроек в админке. Если логика требует изменения параметров через интерфейс, необходимо создавать обычный плагин, который будет читать константы, заданные MU-модулем.
Вторая ошибка касается обновлений. WordPress не умеет обновлять MU-модули. Они не проверяются на наличие новых версий в официальном репозитории. Для решения подобной задачи используется Git-репозиторий с деплоем по SSH: при внесении изменений скрипт загружает новые файлы в mu-plugins и очищает кэш.
Третья ошибка связана с игнорированием алфавитного порядка при именовании файлов. Файл disable-home-pagination.php загружается раньше pagination-hardening.php и полностью блокирует его работу, потому что делает wp_redirect + exit первым. Разработчик видит что оба файла существуют и думает что оба работают. Фактически работает только первый, второй никогда не выполняется для нужного условия. Числовые префиксы (00-, 10-, 20-) решают подобную проблему явно.
Четвёртая ошибка связана с мультисайтовыми сетями. В режиме Multisite директория mu-plugins работает одинаково для всех сайтов в сети. Невозможно загрузить must-use модуль только для одного конкретного сайта. Для такой изоляции приходится использовать обычные сетевые плагины или создавать логику проверки blog_id внутри самого кода.
Как отлаживать mu-плагины без доступа к админке
Отсутствие интерфейса активации создаёт специфические сложности при отладке. Разработчик не может просто отключить модуль через админку, чтобы проверить, в нём ли проблема. Приходится использовать другие инструменты.
Первый способ предполагает временное переименование файла. Добавление префикса _disabled- к имени файла исключает его из загрузки. WordPress читает только файлы с расширением .php, поэтому подобный приём работает надёжно. Способ подходит для быстрой проверки гипотезы на продакшене.
Второй способ использует константу в wp-config.php. Разработчик добавляет define('SEBERD_DEBUG_MODE', true); и оборачивает спорный код в условную проверку. Подобный подход позволяет включать и выключать функциональность без изменения файловой структуры. Метод удобен для тестирования на staging-окружении.
Третий способ предполагает логирование в отдельный файл. Функция error_log() с указанием пути записывает события в /tmp/mu-plugins-debug.log. Разработчик получает возможность отслеживать порядок выполнения хуков, значения переменных и точки выхода из функций. Подобный подход незаменим при анализе конфликтов между модулями.
Почему обычные плагины не подходят для жёстких ограничений
Использование обычных плагинов для критической инфраструктуры создаёт иллюзию контроля. Администратор сайта может зайти в панель управления и нажать кнопку «Деактивировать». Если плагин отвечал за блокировку уязвимого REST-эндпоинта или скрытие версии системы, сайт мгновенно становится уязвимым.
В условиях, когда доступ к админке могут иметь редакторы или авторы, риск случайной деактивации возрастает. Must-use модули лишены подобного недостатка. Они не отображаются в списке плагинов с кнопками управления. Единственный способ отключить подобный код предполагает получение доступа к файловой системе сервера по SSH. Подобное решение создаёт необходимый барьер между операционным управлением контентом и инфраструктурной безопасностью.
Функция wp_die часто используется в must-use модулях для остановки выполнения скрипта при нарушении политик доступа. В отличие от простого редиректа, wp_die отдаёт корректный HTTP-статус (например, 403 Forbidden) и останавливает дальнейшую загрузку ресурсов. Подобное поведение экономит серверные ресурсы и чётко сигнализирует системам мониторинга о попытке несанкционированного доступа.
Инфраструктурный код должен быть невидимым для пользователя и недоступным для случайного изменения. Must-use плагины предоставляют именно такой уровень абстракции, превращая WordPress из движка для блогов в управляемую и защищённую платформу.
ссылка на оригинал статьи https://habr.com/ru/articles/1050128/