У WordPress-сайта нет одного «файла настроек». Поведение сайта складывается из пяти слоёв, которые лежат в разных местах, читаются в разном порядке и переопределяют друг друга. Отсюда самая частая жалоба администратора — «я поставил лимит / включил кэш / сменил адрес, а сайт не изменился»: значение задали не в том слое, и более высокий слой перебил его молча. Разберём карту слоёв целиком — веб-сервер, PHP-движок, константы WordPress, опции в базе, тема и плагины, — научимся для любой настройки отвечать «где её правильный дом» и почему правило «один источник правды на настройку» спасает больше времени, чем сама настройка.
Часть I. Пять слоёв: карта того, где вообще «настраивается сайт»
Начнём с полного перечня. Запрос к странице WordPress проходит эти слои сверху вниз, и на каждом есть своя «кнопка настройки».
запрос браузера
│
▼
[1] Веб-сервер nginx.conf / .htaccess — маршрутизация, лимит тела запроса, кэш статики
│
▼
[2] PHP-движок php.ini + пул www.conf — память, время исполнения, лимиты загрузки
│
▼
[3] Константы WordPress wp-config.php — кредиты БД, адрес сайта, соли, отладка (читаются ДО БД)
│
▼
[4] Опции в базе таблица wp_options — название, часовой пояс, ЧПУ, «показывать N записей»
│
▼
[5] Тема и плагины functions.php, настройки — внешний вид и поведение поверх ядра
│
▼
отдача страницы
Что лежит в каждом слое (по порядку значимости для администратора):
| Слой | Файл / место | Типичные настройки | Кто читает |
|---|---|---|---|
| [1] Веб-сервер | nginx.conf, .htaccess | маршрутизация (permalinks), лимит тела запроса, gzip, кэш статики | nginx/Apache |
| [2] PHP | php.ini, пул www.conf | memory_limit, upload_max_filesize, max_execution_time, Opcache | PHP-FPM |
| [3] wp-config | wp-config.php | DB_* креды, WP_HOME/WP_SITEURL, соли, WP_DEBUG | WordPress-ядро |
| [4] База | wp_options (через админку) | siteurl/home, gmt_offset, permalink_structure, posts_per_page | WordPress-ядро |
| [5] Тема/плагины | functions.php, экраны настроек | цвета, шрифты, поведение плагинов, кэш-плагины | код темы/плагина |
Практический вывод уже здесь: когда кто-то говорит «настроить лимит загрузки файла», это не одна кнопка. Лимит живёт в слое [2] (PHP не примет тело больше upload_max_filesize), но его же частично диктует слой [1] (nginx не пропустит тело больше client_max_body_size). Поставить только в одном месте — и половина лимита не применится. Про «правильный дом» — Часть III.
Отдельный слой, который сюда не вошёл, но всегда рядом — кэш (операторный Opcache, объект-кэш, страничный кэш плагина). Это не настройка, а копия результата настроек: классическая причина «поменял, а не видно» — кэш отдал старый HTML/старые опции. Его учитываем в Части V.
Часть II. Порядок переопределения: кто кого бьёт
Слои читаются не «все вместе», а с приоритетом. Три правила переопределения, которые закрывают большинство «почему не работает».
1. Внутри PHP: пул бьёт php.ini, а admin_value не перебить кодом
У настроек PHP есть скоуп (где законно менять). Практично запомнить три уровня:
; /etc/php/8.2/fpm/php.ini — базовый слой, для всех пулов
memory_limit = 256M
; /etc/php/8.2/fpm/pool.d/www.conf — слой пула, точечный на сайт
php_admin_value[memory_limit] = 512M ; вбито наглухо: ни ini_set(), ни .htaccess не перебьют
php_value[upload_max_filesize] = 32M ; мягкий: плагин может переопределить через ini_set()
php_flag[display_errors] = off ; то же для булевых (on/off, не 1/0)
Приоритет: php_admin_value (пул) > php_value/.htaccess/.user.ini (мягкие) > ini_set() в рантайме > php.ini. Разница между admin и обычным — единственное, что важно помнить: admin_value админ ставит финально, плагин его не сдвинет. Углублённый разбор скоупов и Opcache — в PHP-FPM: движок под WordPress.
Ещё грабля: у PHP разные копии php.ini для CLI и для FPM. Настройки, заданные в /etc/php/8.2/cli/php.ini, не действуют на сайт, который крутится через …/fpm/php.ini. «Проверил в терминале — работает, на сайте — нет» — почти всегда это.
2. WordPress: константа из wp-config бьёт опцию из базы
WordPress читает адрес сайта так: если в wp-config.php объявлена WP_HOME/WP_SITEURL — она используется как есть и поле home/siteurl в базе игнорируется. Если константы нет — берётся значение из wp_options.
<?php
// wp-config.php — константы перекроют одноимённые опции в базе
define( 'WP_HOME', 'https://example.test' );
define( 'WP_SITEURL', 'https://example.test' );Отсюда ловушка миграции: поменяли адрес через wp search-replace в базе, а сайт всё равно отдаёт старый URL — потому что константа в wp-config перебила базу. Об обратном (база есть, а констант нет) и про замену URL при переезде — Миграция WordPress между серверами.
3. Плагины бьют тему, а админка бьёт код темы
Настройки плагина обычно живут в wp_options под своим ключом и переопределяют поведение темы, заданное в functions.php/Customizer. Практически: «сменил шрифт в теме, а он не поменялся» — потому что кэш-плагин или плагин-оптимизатор подставил свой CSS-ссылкой позже. Правило простое: чем «позже» слой в приоритете, тем громче его настройка — а кэш вообще ставит приоритеты на паузу.
Часть III. Правильный дом настройки: три частых случая целиком
Самая дорогая ошибка — положить настройку в один слой, когда она требует двух. Разберём три типовые.
Лимит загрузки медиафайла (требует трёх мест)
Чтобы прикрепить видео в 256 МБ, значение должно совпасть по всей цепочке прохождения запроса:
# [1] nginx.conf — сервер не пропустит тело запроса больше этого
client_max_body_size 256M;
; [2] php.ini (или php_value в пуле) — PHP не примет файл больше upload,
; и POST целиком больше post_max_size (post_max_size ≥ upload_max_filesize)
upload_max_filesize = 256M
post_max_size = 260M
max_execution_time = 300 ; большой файл дольше обрабатывается
max_input_time = 300
memory_limit = 512M ; на время обработки файл живёт в памяти
Если задать только PHP-лимит, а nginx оставить на дефолтных 1M — получите 413 Request Entity Too Large ещё до того, как PHP увидит запрос. Зададите nginx и PHP, но забудете memory_limit — упадёт на середине обработки. Это ровно тот случай, где «настроить лимит» — не одна кнопка. (Про то, где физически лежит конфиг nginx для WordPress — Nginx: веб-сервер и reverse proxy.)
Адрес сайта (база ИЛИ константа, не оба сразу)
Канонический дом адреса — поле home/siteurl в wp_options (админка → Настройки → Адрес WordPress). Константа в wp-config — это переопределение для особых случаев (жёстко зафиксировать адрес, не давая базе его сменить). Правила:
- держите адрес в одном месте: либо база (обычный случай), либо константы (когда нужен контроль); не дублируйте — при миграции/
search-replaceдубль даёт рассинхрон; - если решили жить в константах — помните, что
search-replaceпо базе на них не действует (база есть, но её игнорируют).
ЧПУ / маршрутизация пермалинков (слой [1] + слой [4])
Структура постоянных ссылок (/%postname%/) задаётся в админке (слой [4], permalink_structure), но реально работает только если слой [1] настроен переписать URL: для nginx — директива try_files, для Apache — правила .htaccess. Настроили админку, но не тронули веб-сервер → 404 на внутренних страницах. Это не баг WordPress, а провал между слоями [1] и [4].
Часть IV. Что реально принадлежит wp-config.php
Миф о «главном файле настроек» рождает больше всего случайных правок. Правда: wp-config.php читается ядром до подключения к базе и предназначен для ограниченного набора — того, без чего WordPress ещё не может ничего прочитать из базы. Всё остальное туда класть не надо.
Что законно живёт в wp-config.php:
<?php
// подключение к базе — без этого WP не стартует вообще
define( 'DB_NAME', 'wpdatabase' );
define( 'DB_USER', 'wpuser' );
define( 'DB_PASSWORD', 'СЮДА-НЕ-РЕАЛЬНЫЙ-ПАРОЛЬ' );
define( 'DB_HOST', 'localhost' );
// ключи и соли (уникальные «секреты» установки) — генерируются, не выдумываются
define( 'AUTH_KEY', '…' );
define( 'NONCE_SALT', '…' );
// адрес сайта как переопределение (см. Часть III)
define( 'WP_HOME', 'https://example.test' );
// поведение ядра
define( 'WP_DEBUG', false );
define( 'WP_DEBUG_LOG', true ); // писать ошибки в файл, а не на экран
define( 'DISALLOW_FILE_EDIT', true ); // запретить редактирование тем из админки
define( 'FS_METHOD', 'direct' ); // как ставить обновления (без FTP)Чего в wp-config.php не должно быть: часового пояса, «сколько записей на странице», названия сайта, структуры пермалинков, категорий, меню, плагинов. Это всё опции в базе (слой 4) — в wp-config им не место, и выдуманные там константы просто игнорируются ядром. Практический критерий: «можно ли это задать в админке?» — если да, дом этому в базе, а не в wp-config.
Отдельно — креды и соли. Креды БД — это секреты: в wp-config они лежат в открытом виде, и это компромисс WordPress-модели, о котором нужно знать (права файла, бэкапы, доступ в админку). Про то, как их защищают и что такое соли в широком смысле — Шифрование данных и хранение паролей. Здесь важнее другое: генератор конфига (см. Инструменты) ставит на место секретов плейсхолдеры — потому что никакой инструмент не знает ваши реальные пароли, и «безопасно сгенерированный wp-config» означает «проверь и подставь сам», а не «заливай как есть».
Часть V. Один источник правды — и роль кэша
Сводный принцип, из которого выросла вся статья: у каждой настройки должен быть ровно один «истинный» дом. Как только значение продублировано в двух слоях, они расходятся при первом же изменении одного из них — и вы получаете «баг без бага».
Типовые способы нарушить «один источник правды»:
- адрес сайта и в базе, и в
wp-config(Часть II, п.2) — при переезде поменяли базу, константа держит старое; - лимит PHP задан и в
php.ini, и в.user.ini, и в пуле — кто из них победил, никто не помнит (победилphp_admin_value, если он есть); - настройки кэш-плагина дублируют настройки темы (Часть II, п.3).
Правило применения: настройте значение там, где ему место, и убедитесь, что выше по приоритету нет переопределяющего слоя. Для этого существует трюкацкий, но надёжный инструмент — прочитать фактическое значение, а не то, которое вы «задали»:
# что реально действует у PHP-FPM (а не что в php.ini)
php-fpm8.2 -tt # или через админку WordPress → Инструменты → Информация о сайте
# адрес сайта: есть ли переопределяющая константа
grep -E "WP_HOME|WP_SITEURL" /var/www/example.test/wp-config.php
Кэш — отдельный нарушитель «один источник правды». Он не слой настройки, а копия результата. Поменяли опцию в базе → кэш-плагин отдаёт старый HTML, и кажется, что «не применилось». Порядок всегда: изменил настройку → сбросил соответствующий кэш → проверил. Без последнего шага вы диагностируете не конфиг, а кэш. (Где кэш живёт и как чистится — Кэширование; как понять, что «не дышит» именно слой — Диагностика: когда сервер «не дышит».)
Практика деплоя усиливает правило: wp-config.php на shared-хостинге между релизами нельзя перезаписывать кодом из репозитория — иначе новый выкат затрёт креды. Приём «shared-файлы, которые не едет при выкате», разобран в Деплой без боли.
Инструменты под задачу
Помнить, какой слой переопределяет какой, какие директивы реальные, а какие ядро проигнорирует, и где поставить безопасный дефолт вместо выдуманного пароля — это механика с высокой ценой ошибки (один незакрытый переопределяющий слой = час «отладки конфига»). Чтобы снять её, в codestack.space есть ИИ-генератор конфигураций. Вы описываете окружение словами («WordPress, PHP 8.2, MySQL на том же хосте, OPcache включён, стаджинг для отладки, лимит загрузки 64M»), выбираете формат (.env, wp-config.php, php.ini) и окружение (development / staging / production), — а он отдаёт связный конфиг-файл:
- только реальные директивы и константы (не выдуманные ключи, которые ядро проигнорировало бы);
- секреты всегда плейсхолдерами — с явным предупреждением «замените перед запуском», потому что модель не знает ваших паролей;
- безопасные значения по умолчанию (для production отладка и verbose выключены);
- группировку по смысловым секциям и чек-лист «что заменить перед запуском».
Попробуйте прямо здесь, на своём окружении:
Он не решает, в какой слой положить настройку (это Части I–IV) — он снимает ручную часть: не забыть директиву, не выдумать несуществующую константу, не оставить реальный пароль в файле, который уедет в git. Само решение «где правильный дом значения» остаётся за вами — см. Часть III и Часть V.
Чек-лист граблей
- Лимит загрузки задан только в PHP → nginx (`client_max_body_size`) режет раньше с `413`; лимит живёт в трёх местах сразу.
- `post_max_size` < `upload_max_filesize` → большой файл не пройдёт как POST целиком; первый обязан быть ≥ второго.
- Правки в `…/cli/php.ini`, а сайт на `…/fpm/php.ini` → «в терминале работает, на сайте нет»; у CLI и FPM разные копии конфига.
- Ждёте, что плагин не переопределит `php_value` → мягкий слой перебивается `ini_set()`; для финального слова админа нужен `php_admin_value`.
- Поменяли адрес через `search-replace`, а сайт отдаёт старый → константа `WP_HOME`/`WP_SITEURL` в `wp-config` перебила базу.
- Продублировали адрес в базе и в константах → рассинхрон при первой миграции; держите один источник.
- Задали структуру пермалинков в админке, не тронув веб-сервер → 404 внутри сайта; слой [4] без слоя [1] не работает.
- Написали в `wp-config` часовой пояс / «показывать N» / название сайта → ядро игнорирует; это опции в базе, а не константы.
- Вставили реальный пароль БД и закоммитили `wp-config` в git → креды утекли; генератор ставит плейсхолдер — подставляйте сами и не тащите в репозиторий.
- Поменяли настройку и не сбросили кэш → «не применилось»; проверили не конфиг, а кэш.
- Перезаписали `wp-config` при выкате из репозитория → затёрли креды; `wp-config` — shared-файл, не часть кода.
- Читаете php.ini, а не фактическое значение → диагноз «по исходнику» вместо «по факту»; спросите у системы, что реально действует.
👤 Зарегистрируйтесь, чтобы добавить материал в закладки.
