Справочник: редиректы
Что здесь. Редирект — правило сайта «откуда → куда», а не свойство страницы: с любого пути сайта на любой путь этого сайта или на адрес другого домена. Страница-заглушка по старому адресу не нужна, правило ловит путь и без неё. Правила заводятся вручную, импортом CSV или сами — когда опубликованная страница меняет адрес или удаляется. В дашборде это «Инструменты → Редиректы». Каждая ручка, поле и код отказа сверены с кодом и прогнаны на тестовом сайте.
Адреса. Ручки сайта: https://onpress.pro/api/v2/site/{siteId}/redirects…, права — администратор сайта или суперадмин сети. В примерах op_XXXX — ваш токен, SITE_ID — внешний идентификатор сайта. Как выбирается сайт и в какой форме приходят отказы — доступ.
Правило работает, пока существует. У правила только from и to: ни включателя, ни выбора кода, ни заметки, ни счётчика. Заведённое правило срабатывает всегда, остановить редирект — удалить правило. Ответ всегда постоянный, 301: поиск переносит старый адрес на новый. Срабатывание ничего не пишет в базу — переходы видно в логах сервера и в аналитике.
Когда срабатывает. Правило отвечает раньше всего остального: раньше сборки страницы, её статической копии и кэша. Если по адресу правила опубликована страница, правило её перекрывает — статическая копия снимается в том же запросе, кэш сайта сбрасывается, и новая копия по этому адресу не появится, пока правило есть. Удалили правило или сменили его from — страница снова отвечает 200 и снова получает копию. Исключение — загруженное статическое приложение: его файлы отдаются раньше любого правила, и по его адресу редирект не сработает (предупреждение static_app).
Правила
| Пункт | Ручка | Тело |
|---|---|---|
| Список правил | GET /redirects | — |
| Завести правило | POST /redirects | {"from": "/old/", "to": "/new/"} |
| Одно правило | GET /redirects/{id}PATCH /redirects/{id}DELETE /redirects/{id} | {"to": "/newer/"} |
Поля правила
| Поле | Тип | Что значит |
|---|---|---|
id | number | номер правила |
from | string | откуда: путь от корня сайта, по желанию с параметрами (/page/?id=5); /old/* — префикс |
to | string | куда: путь от корня (/new/, / — главная) или полный адрес https://… на любой домен |
match | string | exact — точный адрес, prefix — всё под префиксом |
auto | boolean | правило завела платформа при переносе или удалении страницы |
page_id | number или null | у автоправила — страница, чей адрес сменился или перестал отвечать; у ручного — null |
created_at, updated_at | string | UTC, ISO 8601 |
Как сравнивается адрес. Без учёта регистра и косой черты на конце: правило /Old-Page/ ловит и /old-page, и /old-page/. Кириллица в пути пишется буквами или в %D0%… — это одно и то же. from можно прислать полным адресом этого же сайта, он сведётся к пути; адрес другого домена — отказ. Решётка (#…) в from не принимается: браузер её на сервер не отправляет.
Параметры адреса. Правило без параметров ловит адрес с любыми параметрами и передаёт их дальше: /old/?a=1 уйдёт на /new/?a=1, если в to своих параметров нет. Исключение — рекламные метки (utm_*, gclid, fbclid, yclid и подобные): если других параметров в адресе нет, кэш сайта отбрасывает их раньше правила, и /old/?utm_source=x уйдёт на /new/; вместе с обычными параметрами передаются все. Правило с параметрами (/page/?id=5&b=2) ловит только этот набор, порядок не важен (?b=2&id=5 тоже), и параметры дальше не передаёт; /page/?id=5 без b это правило не поймает. Для одного пути правило с параметрами проверяется раньше правила без них.
Префикс. from, который кончается на /*, ловит всё под этим путём, включая сам путь. Звёздочка в to заменяется хвостом адреса: правило /old/* → /docs/* уводит /old/a/b/?x=1 на /docs/a/b/?x=1, а /old/ — на /docs/. Без звёздочки в to всё под префиксом уходит на один адрес. Звёздочка в to бывает только у префиксного правила. Точное правило важнее префиксного, длинный префикс важнее короткого. Префикс на весь сайт (/*), звёздочка в середине пути и префикс с параметрами не принимаются.
Что занято. Адреса самой платформы — /wp-admin/, /wp-json/, /wp-content/, /wp-includes/, служебные .php — правилом не перекрываются: такое from — отказ redirect_invalid.
Список правил
GET /redirects отдаёт все правила сайта, старые первыми, и текущее состояние автоправил полем auto_redirects.
| Параметр | Что делает |
|---|---|
search | подстрока в from или to |
curl -s "https://onpress.pro/api/v2/site/SITE_ID/redirects?search=legacy" \
-H "Authorization: Bearer op_XXXX"
{
"success": true,
"redirects": [
{
"id": 232,
"from": "/legacy/*",
"to": "/docs/*",
"match": "prefix",
"auto": false,
"page_id": null,
"created_at": "2026-10-03T18:42:53Z",
"updated_at": "2026-10-03T18:42:53Z"
}
],
"total": 1,
"auto_redirects": true
}
Завести правило
POST /redirects с полями from и to, оба обязательны. Других полей у правила нет:
"enabled": false— отказ400 redirect_invalid: выключенных правил не бывает, правило удаляют;codeне применяется:301проходит молча, с любым другим правило всё равно ставится с301, а вwarningsприходитcode_ignored;dry_run: true(в теле или?dry_run=1) проверяет правило целиком — петли, цепочки, живую страницу — и ничего не записывает; ответ200с правилом безid.
Ответ — 201 с правилом, списком предупреждений warnings и признаком applied (сайт принял новый набор правил). Если правило перекрыло опубликованную страницу, в ответе ещё static_removed — номера страниц, чья статическая копия снята.
curl -s -X POST "https://onpress.pro/api/v2/site/SITE_ID/redirects" \
-H "Authorization: Bearer op_XXXX" -H "Content-Type: application/json" \
-d '{"from": "/old/", "to": "/new/", "code": 302}'
{
"success": true,
"redirect": {
"id": 231,
"from": "/old/",
"to": "/new/",
"match": "exact",
"auto": false,
"page_id": null,
"created_at": "2026-10-03T18:42:52Z",
"updated_at": "2026-10-03T18:42:52Z"
},
"warnings": [
{ "code": "code_ignored", "message": "redirects are always 301; \"code\": 302 is ignored", "value": 302 }
],
"applied": true
}
Предупреждения правило не отменяют, оно записано:
| Код | Когда |
|---|---|
live_page | по from опубликована страница (page_id) или это главная; пока правило есть, посетители её не видят, её статическая копия снята |
chain | to ведёт на адрес другого правила — посетитель сделает лишний переход; chain — вся цепочка. Лучше сразу указать конечный адрес |
static_app | по адресу лежит загруженное приложение, его файлы отдаются раньше правила; url |
code_ignored | прислан code, отличный от 301; правило записано с 301, value |
apply_failed | правило сохранено, но сайт ещё не принял новый набор — сработает со следующей правкой или после POST /redirects/apply |
Отказы: 400 redirect_invalid (field, value; текст называет, что не так), 409 redirect_loop (chain), 409 redirect_exists (у этого from уже есть правило; id), 409 redirects_limit (больше 5000 правил на сайт).
{
"success": false,
"error": "redirect_exists",
"message": "\"from\": \"/old/\" already has a rule #231 (→ /new/); change it instead",
"field": "from",
"value": "/old/",
"id": 231
}
Петли проверяются по всем правилам сайта до записи. Отказ получает правило, которое уводит на свой же адрес (/a/ → /A), замыкает круг с другими правилами или префикс, который растёт с каждым переходом (/old/* → /old/sub/*):
{
"success": false,
"error": "redirect_loop",
"message": "\"/docs/\" → \"/old/\" makes a redirect loop: /docs/ → /old/ → /home-next/ → /docs/",
"field": "to",
"value": "/old/",
"chain": [
{ "id": null, "from": "/docs/", "to": "/old/" },
{ "id": 5, "from": "/old/", "to": "/home-next/" },
{ "id": 8, "from": "/home-next/", "to": "/docs/" }
]
}
Одно правило
GET /redirects/{id} — правило полем redirect. PATCH /redirects/{id} правит from, to или оба; проверки и предупреждения те же, что при заведении, dry_run тоже. Так же правится и автоправило — например, чтобы увести адрес удалённой страницы не на родителя, а на другую страницу; пометка auto и page_id при этом остаются. При смене from страница по старому адресу снова получает статическую копию.
curl -s -X PATCH "https://onpress.pro/api/v2/site/SITE_ID/redirects/242" \
-H "Authorization: Bearer op_XXXX" -H "Content-Type: application/json" \
-d '{"to": "/catalog/"}'
{
"success": true,
"redirect": {
"id": 242,
"from": "/catalog/old-page/",
"to": "/catalog/",
"match": "exact",
"auto": true,
"page_id": 7119,
"created_at": "2026-10-03T18:44:58Z",
"updated_at": "2026-10-03T18:45:20Z"
},
"warnings": [],
"applied": true
}
DELETE /redirects/{id} удаляет правило и возвращает страницу, которую оно перекрывало: она снова отвечает 200 и получает статическую копию. Ответ — {"success": true, "deleted": 242, "applied": true, "warnings": []}, с dry_run — {"success": true, "dry_run": true, "deleted": 242, "redirect": {…}} без удаления.
Отказы: 404 redirect_not_found, 400 nothing_to_update (нет ни from, ни to), 400 redirect_invalid (прислано "enabled": false), остальные — как при заведении.
Автоправила
| Пункт | Ручка | Тело |
|---|---|---|
| Включить или выключить | PUT /redirects/auto | {"enabled": false} |
| Текущее состояние | GET /redirects | поле auto_redirects |
Автоправило — обычное правило 301 с пометкой auto: true и номером страницы в page_id. Платформа заводит его сама, когда адрес опубликованной страницы перестаёт отвечать: страницу перенесли или удалили. Ставится по правилу на каждый адрес — на саму страницу и на каждого её опубликованного потомка, — а не префиксом, чтобы не перехватить страницы, которые позже появятся под старым путём. Дальше автоправило живёт как любое другое: его видно в списке, можно поправить to или удалить.
Перенос страницы
Сменился путь опубликованной страницы — слаг или родитель — и со старого пути на новый заводится правило 301, для неё и для каждого опубликованного потомка. Источник не важен: дашборд (правка пути в строке, «Перенести в каталог», вкладка «Markdown» в панели страницы), POST /pages/markdown с id, PATCH /docs/sidebar/items/{ref}, ручки первой версии или панель WordPress. Смена языка (POST /pages/language) правила не заводит — если адрес из-за неё сменился, заведите правило вручную.
Заодно с переносом:
- цепочки сворачиваются: правила, которые вели на старый путь, переводятся прямо на новый;
- адрес освобождается: правило с
from, равным новому пути страницы, удаляется — ручное тоже, — иначе оно спрятало бы страницу; - обратный перенос не даёт петли: вернули страницу на прежний адрес — правило прежний → новый удаляется по тому же правилу, а заводится новый → прежний;
- чужую страницу не прячет: если по старому пути уже отвечает другая опубликованная страница, правило не заводится.
curl -s -X POST "https://onpress.pro/api/v2/site/SITE_ID/pages/markdown" \
-H "Authorization: Bearer op_XXXX" -H "Content-Type: application/json" \
-d '{"markdown": "---\nid: PAGE_ID\nname: \"Каталог\"\nslug: \"catalog-new\"\nurl: \"/catalog-new/\"\nstatus: \"publish\"\n---\n\nТекст страницы."}'
{
"success": true,
"updated": true,
"id": 7117,
"url": "/catalog-new/",
"redirects_created": [
{ "id": 237, "from": "/catalog/", "to": "/catalog-new/" },
{ "id": 238, "from": "/catalog/kid/", "to": "/catalog-new/kid/" }
],
"auto_redirects": {
"moves": [
{ "id": 7117, "from": "/catalog/", "to": "/catalog-new/" },
{ "id": 7118, "from": "/catalog/kid/", "to": "/catalog-new/kid/" }
],
"created": 2,
"updated": 1,
"enabled": true
}
}
Здесь updated: 1 — одно правило, которое вело на /catalog/, переведено на /catalog-new/.
Удаление страницы
Опубликованная страница ушла в корзину или удалена насовсем — в дашборде (корзина в строке, «Удалить» у выбранных), через DELETE /pages/{ref} или в панели WordPress — и правило 301 ведёт с её пути на ближайшего опубликованного родителя. У страницы верхнего уровня цель — главная её языка: / у основного языка, /en/ — у языка с префиксом в адресе. Так же уводятся её опубликованные потомки: и удалённые вместе с ней (with_children), и оставшиеся под удалённой страницей, чей адрес перестал отвечать. Если страницу с живыми потомками удалили насовсем в панели WordPress, WordPress переносит потомков к её родителю, и правило ведёт на их новый путь. Правила, которые вели на путь удалённой страницы, переводятся на новую цель — цепочка сворачивается.
curl -s -X DELETE "https://onpress.pro/api/v2/site/SITE_ID/pages/7117?force=1&with_children=1" \
-H "Authorization: Bearer op_XXXX"
{
"success": true,
"mode": "delete",
"redirects_created": [
{ "id": 243, "from": "/catalog/kid/", "to": "/" },
{ "id": 244, "from": "/catalog/", "to": "/" }
],
"auto_redirects": { "moves": 2, "created": 2, "enabled": true }
}
Цель не подходит — поправьте её: PATCH /redirects/{id} с новым to, правило останется автоправилом.
Возврат из корзины
Страницу вернули из корзины (в панели WordPress — у API ручки возврата нет) — автоправила с её нынешнего пути удаляются, даже если их цель меняли вручную; с путей потомков тоже, если сами потомки не в корзине. Правила прежних переносов страницы ведут с других путей и остаются.
Что приходит в ответе
Ручки, через которые страницу переносят или удаляют, — POST /pages/markdown, PATCH /docs/sidebar/items/{ref}, DELETE /pages/{ref} и ручки первой версии, — отвечают двумя полями, если адрес сменился:
| Поле | Что значит |
|---|---|
redirects_created | правила, которые теперь ведут со старых адресов: [{id, from, to}] — новые и прежние правила с того же from, переведённые на новую цель |
auto_redirects.moves | сменившиеся адреса: в записи страницы — списком [{id, from, to}] (id — страница), в удалении и в первой версии — числом |
auto_redirects.created | сколько правил заведено |
auto_redirects.updated | в записи страницы: сколько прежних правил переведено на новую цель, включая свёрнутые цепочки |
auto_redirects.enabled | включены ли автоправила; false — адрес сменился, а правила не заведены (в записи страницы ещё disabled: true) |
Дашборд по этим полям показывает уведомление — подробно в разделе «В дашборде».
Выключатель
PUT /redirects/auto с {"enabled": false} выключает автоправила сайта целиком — и для переносов, и для удалений; true включает. По умолчанию включены. Ответ — {"success": true, "auto_redirects": false}. Пока выключено, адрес меняется без правила: redirects_created пустой, auto_redirects.enabled — false. Заведённые раньше автоправила выключатель не трогает.
Отказы: 400 redirect_invalid, если enabled не передан или не да/нет. Этот отказ приходит в общей форме ошибки — {"code": "redirect_invalid", "message": "…", "data": {"status": 400, "field": "enabled"}}.
Импорт и применение
| Пункт | Ручка | Тело |
|---|---|---|
| Импорт CSV или JSON | POST /redirects/import | {"csv": "from,to\n/a/,/b/", "dry_run": true} |
| Применить заново | POST /redirects/apply | — |
Импорт CSV или JSON
Тело — csv строкой или redirects списком [{from, to}]. В CSV колонки from,to; файл старого вида from,to[,code][,enabled] тоже читается — код не применяется (у строки с кодом не 301 — предупреждение code_ignored), строка с enabled = 0 отклоняется, лишние колонки пропускаются. Разделитель — запятая или точка с запятой, строка заголовка (from,to,…) необязательна, пустые строки и строки с # пропускаются.
on_conflict решает, что делать с from, у которого уже есть правило: skip (по умолчанию) — оставить старое, replace — переписать его строкой импорта. dry_run: true (в теле или ?dry_run=1) проверяет каждую строку и ничего не пишет — так удобно смотреть, что получится, перед настоящим импортом. До 5000 строк за раз. Строки с ошибкой не мешают остальным; записанные строки ложатся одной транзакцией.
curl -s -X POST "https://onpress.pro/api/v2/site/SITE_ID/redirects/import?dry_run=1" \
-H "Authorization: Bearer op_XXXX" -H "Content-Type: application/json" \
-d '{"csv": "from,to\n/imp-a/,/docs/\n/imp-b/*,https://example.com/*\n/old/,/x/\n/bad,ftp://x\n/imp-c/,/docs/,302\n/imp-d/,/docs/,301,0"}'
{
"success": true,
"dry_run": true,
"created": 3,
"updated": 0,
"skipped": 1,
"failed": 2,
"rows": [
{ "line": 2, "from": "/imp-a/", "to": "/docs/", "status": "created" },
{ "line": 3, "from": "/imp-b/*", "to": "https://example.com/*", "status": "created" },
{ "line": 4, "from": "/old/", "to": "/x/", "status": "skipped", "id": 231, "reason": "exists" },
{ "line": 5, "from": "/bad", "to": "ftp://x", "status": "failed",
"error": { "code": "redirect_invalid", "message": "\"to\": \"ftp://x\" is neither a path from the root (\"/new/\") nor an http(s) URL" } },
{ "line": 6, "from": "/imp-c/", "to": "/docs/", "status": "created",
"warnings": [ { "code": "code_ignored", "message": "redirects are always 301; \"code\": \"302\" is ignored", "value": "302" } ] },
{ "line": 7, "from": "/imp-d/", "to": "/docs/", "status": "failed",
"error": { "code": "redirect_invalid", "message": "\"enabled\": rules have no on/off switch — a rule that exists always works; delete it to stop the redirect" } }
]
}
status строки — created, updated, skipped или failed (с error), у записанных — id, у строк с предупреждениями — warnings. Без dry_run в ответе ещё applied и общие warnings:
{
"success": true,
"dry_run": false,
"created": 1,
"updated": 1,
"skipped": 0,
"failed": 0,
"rows": [
{ "line": 1, "from": "/imp-a/", "to": "/docs/", "status": "created", "id": 234 },
{ "line": 2, "from": "/old/", "to": "/new/", "status": "updated", "id": 231 }
],
"applied": true,
"warnings": []
}
Отказы: 400 nothing_to_import (нет ни csv, ни redirects, или в них нет строк), 400 invalid_on_conflict, 409 redirects_limit.
Применить заново
POST /redirects/apply отдаёт сайту текущий набор правил и снимает статические копии по их адресам. Нужен только после предупреждения apply_failed; обычная правка делает это сама. Ответ: {"success": true, "applied": true, "rules": 5, "warnings": []}.
В дашборде
Инструменты → Редиректы — все правила сайта плотной таблицей «Откуда / Куда»: сверху итог «N редиректов», по умолчанию порядок по алфавиту адреса «Откуда», щелчок по заголовку колонки сортирует по ней. Автоправило помечено «авто», подсказка на пометке называет страницу. Действия в строке — значками при наведении, на телефоне видны всегда. Что можно сделать:
- добавить — кнопка «Добавить редирект» в шапке: поля «Откуда» и «Куда», код выбирать не нужно;
- поправить — клик по адресу в строке, сохраняется сразу; отказ или предупреждение встаёт текстом под строкой;
- удалить — корзина в строке, с подтверждением;
- открыть — адрес «Откуда» на домене сайта в новой вкладке; у префиксного правила кнопка неактивна;
- импорт из CSV — вставить строки или загрузить файл, «Проверить» показывает итог по каждой строке, «Применить» записывает; выбор «Пропустить» или «Заменить» для адресов, у которых правило уже есть;
- поиск по адресам;
- переключатель «Автоправила» — тот же, что
PUT /redirects/auto; на телефоне он стоит строкой над таблицей.
Уведомления. Перенесли или удалили опубликованную страницу в разделе «Страницы» — дашборд показывает, что заведено: «Создан редирект: /старый/ → /новый/» или «Создано N редиректов» со списком по кнопке «Показать список». Если автоправила выключены, приходит «Адрес изменился, редирект не создан (автоправила выключены)» или «Страница удалена, редирект не создан…». В каждом уведомлении есть кнопка «Открыть редиректы».
Как перенести старые адреса
Раньше старый адрес заводился страницей с полем redirect. Этого поля у страниц больше нет: PATCH /pages/{ref} с ним отвечает 400 redirect_field_removed, а ключ redirect во frontmatter публикации не записывается и даёт предупреждение. Старые адреса — правилами: одно правило на адрес или префикс на целый раздел, пачкой — импортом CSV.
{
"success": false,
"error": "redirect_field_removed",
"message": "pages no longer carry a \"redirect\" field; a redirect is a site rule: POST /site/{siteId}/redirects {from, to}",
"field": "redirect"
}