Смена структуры permalink в WordPress почти всегда оставляет хвост из старых адресов: часть уже в индексе, часть живёт в закладках, часть продолжает отдавать 200 OK через тему, кэш или сторонний роутинг. Если просто поменять настройки в админке и ничего больше не сделать, поисковики увидят дубли, а пользователи — 404, цепочки редиректов или страницы с устаревшими ссылками.
Ниже — рабочая схема, как закрыть старые URL без лишних побочных эффектов: сначала диагностика, потом редиректы, затем проверка результата и типовые ошибки, которые чаще всего ломают миграцию.
Что именно ломается после смены структуры URL
Проблема обычно не в самой настройке permalink, а в том, что старые адреса продолжают существовать в разных слоях:
- в поисковом индексе остаются старые URL;
- внутренние ссылки в контенте и меню могут вести на прежний формат;
- кэш отдаёт старую страницу или старый canonical;
- плагины SEO и редиректов конфликтуют между собой;
- часть старых адресов не имеет явного правила перенаправления и падает в 404.
Если структура менялась с /2024/05/slug/ на /slug/, или с вложенных категорий на короткий URL, без редиректов поисковик будет считать это разными страницами. В итоге часть веса остаётся на старых адресах, а новые не получают его сразу.
Диагностика: какие URL ещё живы и как они отвечают
Перед правкой правил полезно понять, что именно происходит с конкретным старым адресом. Нужны три проверки: код ответа, canonical и наличие редирект-цепочки.
Проверка через curl
curl -I https://example.com/2024/05/my-post/Смотрите на три сценария:
- 301/308 — редирект есть, это хорошо, но важно проверить, куда он ведёт;
- 200 OK — старый URL всё ещё отдаёт контент, значит редиректа нет;
- 404/410 — адрес закрыт, но нужно убедиться, что это не сломанный важный URL.
Проверка canonical и sitemap
Откройте старую страницу в браузере и посмотрите исходный код. Если там canonical указывает на старый адрес, поисковик получит противоречивый сигнал. В XML sitemap должны остаться только новые URL, иначе робот продолжит ходить по устаревшим адресам.
Что смотреть в логике сайта
Если у вас есть кэш-плагин, CDN или серверный кэш, очистите их до проверки. Иначе вы можете увидеть старый ответ не из WordPress, а из промежуточного слоя. На практике это самая частая причина ложной диагностики.
Пошаговое решение: как закрыть старые адреса без потери трафика
Надёжный вариант — настроить 301-редиректы со старых URL на новые и одновременно убедиться, что WordPress генерирует только актуальные ссылки. Если старая структура была предсказуемой, можно обойтись правилом в .htaccess или конфигурации Nginx. Если структура менялась точечно, удобнее использовать плагин редиректов или небольшой код в теме/му-плагине.
Вариант 1. Редирект на уровне сервера
Подходит, если старый и новый формат URL можно описать шаблоном. Пример для Apache: старые адреса с датой перенаправляются на короткий slug.
RewriteEngine On
RewriteRule ^[0-9]{4}/[0-9]{2}/([^/]+)/?$ /$1/ [R=301,L]Это рабочий пример только для простого случая, когда последний сегмент старого URL совпадает со slug новой записи. Если у вас категории, вложенные страницы или произвольные типы записей, правило нужно адаптировать под реальную структуру.
Вариант 2. Редирект через WordPress-код
Если нужно закрыть несколько старых шаблонов адресов, удобнее сделать это в mu-plugins или в отдельном небольшом плагине. Так правило не потеряется при смене темы.
<?php
/**
* Plugin Name: Old URL Redirects
*/
add_action('template_redirect', function () {
$request_uri = $_SERVER['REQUEST_URI'] ?? '';
if (preg_match('#^/[0-9]{4}/[0-9]{2}/([^/]+)/?$#', $request_uri, $matches)) {
$new_path = '/' . $matches[1] . '/';
wp_redirect(home_url($new_path), 301);
exit;
}
});Здесь важно не делать редирект на основе текущего запроса без проверки. Если правило слишком широкое, можно случайно отправить на новый URL не только старые записи, но и служебные страницы.
Вариант 3. Точечные редиректы для отдельных страниц
Если адресов немного, проще и безопаснее создать явные соответствия старый → новый. Это особенно полезно после ручной миграции контента.
<?php
add_action('template_redirect', function () {
$map = [
'/old-about/' => '/about/',
'/blog/old-guide/' => '/guide/',
];
$request_uri = trailingslashit(parse_url($_SERVER['REQUEST_URI'] ?? '/', PHP_URL_PATH));
if (isset($map[$request_uri])) {
wp_redirect(home_url($map[$request_uri]), 301);
exit;
}
});Для небольшого набора URL это надёжнее, чем пытаться угадать правило регуляркой.
Сравнение подходов: сервер, плагин или код
| Подход | Когда использовать | Плюсы | Минусы |
|---|---|---|---|
| Редирект в Nginx/Apache | Есть чёткий шаблон старых URL | Быстро, не зависит от WordPress | Нужен доступ к серверу, сложнее поддержка |
| Плагин редиректов | Нужно много точечных правил | Удобно править без кода | Дополнительная нагрузка, риск конфликтов |
| Код в mu-plugin | Нужна стабильная логика внутри проекта | Не зависит от темы, можно версионировать | Требует аккуратной разработки и тестов |
Как проверить, что решение сработало
После внедрения проверьте не только редирект, но и весь маршрут ответа.
- Старый URL должен отдавать
301и вести на новый адрес без промежуточных шагов. - Новый URL должен отдавать
200 OK. - Canonical на новой странице должен указывать на новый URL.
- В sitemap должны быть только актуальные адреса.
- Внутренние ссылки в меню, хлебных крошках и контенте должны вести сразу на новый формат.
Удобно проверить цепочку так:
curl -I -L https://example.com/2024/05/my-post/Если после -L видите несколько переходов, значит редиректов больше одного. Это не критично, но цепочки лучше убирать: они замедляют загрузку и размывают сигнал для поисковиков.
Частые ошибки и как их исправить
Редирект ведёт на главную
Обычно это происходит, когда правило не нашло соответствие и сайт подставил fallback. Исправление простое: не используйте общий редирект на главную для всех старых URL. Лучше отдавать 404, чем маскировать ошибку.
Старый URL всё ещё открывается с кодом 200
Значит, правило не сработало или его перехватывает кэш. Очистите серверный кэш, кэш плагина и CDN, затем проверьте ответ снова через curl -I.
Появилась цепочка 301 → 301 → 200
Это типичный след от нескольких плагинов редиректов или от старого правила в .htaccess. Уберите дублирующую логику и оставьте один источник правды.
Canonical остался старым
Проверьте SEO-плагин и шаблон темы. Иногда canonical собирается вручную в теме или переопределяется фильтром. Если редирект уже есть, а canonical нет, поисковик может дольше переобходить старый адрес.
После смены permalink сломались вложенные страницы
Это бывает, если правило слишком общее и не учитывает иерархию страниц. Для страниц и записей лучше писать отдельные шаблоны редиректов или использовать точечную карту соответствий.
Что делать с безопасностью и производительностью
Редиректы — это не только SEO-задача. Неправильная логика может создать лишнюю нагрузку на сайт и открыть путь к бесконечным переходам.
- Не делайте редирект на основе непроверенного
REQUEST_URIбез ограничений по шаблону. - Не храните десятки правил в теме, если сайт часто обновляется — вынесите их в
mu-plugin. - После миграции удалите старые правила, которые больше не нужны.
- Проверьте, что редиректы не ломают админку, REST API и служебные маршруты.
Если на сайте много дублей и старых адресов, полезно дополнительно пройтись по индексации и чистке технических хвостов. Для этого часто используют связку SEO-настроек и инструментов очистки, например Clearfy Pro, но только как дополнение к нормальной схеме редиректов, а не вместо неё.
Практический чек-лист перед публикацией изменений
- Составить список старых URL и новых соответствий.
- Выбрать один источник редиректов: сервер, плагин или mu-plugin.
- Проверить, что старые адреса отдают 301, а не 200.
- Очистить кэш сайта, CDN и браузера.
- Обновить внутренние ссылки в меню, контенте и блоках.
- Проверить canonical и sitemap.
- Прогнать несколько старых URL через
curl -I -L.
Если после этого старые страницы всё ещё появляются в индексе, проблема уже не в WordPress как таковом, а в скорости переобхода поисковиком. Тогда нужно дождаться переиндексации и следить, чтобы новые URL не создавали новых дублей.