Pokud změníš strukturu trvalých odkazů ve WordPressu, přestane fungovat každá stará URL, dokud na ni něco neodpoví přesměrováním 301 na novou adresu. WordPress to v obecném případě neudělá: přesměruje jen to, co si umí odvodit sám, třeba změněný slug nebo adresu typu ?p=123, a na zbytek vrátí 404. Bezpečný postup je krátký. Exportuj seznam současných URL, změň strukturu, přidej jedno pravidlo, které převede starý vzor na nový, vyzkoušej ho pomocí curl -I a teprve potom mu věř. Zbytek článku se věnuje stavovým kódům, pravidlům pro .htaccess ve stylu Apache a pro nginx a několika příčinám, na které připadá téměř každá smyčka přesměrování.
Co je 301 a kdy použít něco jiného#
Přesměrování je běžná HTTP odpověď se stavovým kódem a hlavičkou Location. Prohlížeč nebo vyhledávací robot hlavičku přečte a vyžádá si novou adresu. Stavový kód mu říká, jak dlouho si odpověď pamatovat.
| Kód | Význam | Kdy ho použít |
|---|---|---|
301 | Trvale přesunuto | URL, která má nový domov nastálo |
302 | Nalezeno (dočasně) | Zkoušení pravidla, krátké kampaně |
307 | Dočasně, zachová metodu | POST, který musí zůstat POST |
308 | Trvale, zachová metodu | Přísné dvojče 301 |
Pro trvalé odkazy je správná odpověď 301. Říká vyhledávačům, aby váhu staré URL přenesly na novou, a prohlížeče ji ukládají do cache. Právě cache je nebezpečná půlka: špatné 301 zůstane v prohlížečích návštěvníků dávno poté, co opravíš server, a k těm prohlížečům se nedostaneš. Proto každé nové pravidlo nejdřív napiš jako 302, ověř ho a jedno slovo změň na 301, až je správné. Článek o přesměrování mezi www a doménou bez www říká totéž o přesměrování hostitele a všechno níže předpokládá, že víš, jak má tato vrstva fungovat.
301 také není věčný pronájem staré adresy. Pravidlo drž aspoň rok a ideálně tak dlouho, jak web existuje. Staré odkazy na cizích webech a v cizích záložkách nevyprší, jen proto že se tvůj vyhledávací index zaktualizoval.
Co WordPress přesměruje sám a co ne#
WordPress má dvě vestavěná chování, která vypadají jako přesměrování, a je dobré vědět, kde končí.
První je kanonické přesměrování (redirect_canonical()). Když si někdo vyžádá /?p=123 a příspěvek 123 má hezký trvalý odkaz, WordPress ho přes 301 pošle na ten hezký. Podle tvé struktury také přidá nebo odebere koncové lomítko a přesměruje na hostitele z volby home. Proto záleží na tom, která vrstva přesměrování vlastní, a proto je souboj dvou vrstev obvyklým začátkem smyčky.
Druhé je mechanismus starých slugů. Když v editoru změníš slug příspěvku, WordPress si předchozí slug uloží do metadat příspěvku (_wp_old_slug) a přesměruje z něj. Má také záložní řešení pro 404, které příspěvek hádá podle poslední části URL, takže /2023/04/my-post/ může někdy skončit na /my-post/ bez tvého pravidla.
Nestav na tom migraci. Hádání funguje jen při jedinečném slugu, jen u příspěvků a jen když se WordPress rozhodne to zkusit. Nepomůže u základu kategorií, změn hierarchie stránek, vlastních typů příspěvků, adres příloh ani všude tam, kde se změnil sám slug. Ber to jako bonus pro jednu zapomenutou URL, ne jako plán.
Než sáhneš na nastavení trvalých odkazů#
Trvalé odkazy najdeš v Settings, potom Permalinks. Na výběr je Plain (/?p=123), Day and name, Month and name, Numeric, Post name a Custom Structure. Všechny se skládají ze značek jako %year%, %monthnum%, %postname% a %category%. Post name (/%postname%/) je to, k čemu většina webů nakonec dojde: krátké, čitelné a bez dat, kvůli kterým dobrý článek působí starým dojmem.
Změna nastavení je okamžitá a týká se celého webu. Staré URL se nepřejmenují, jen se přestanou vytvářet, takže se předem připrav.
- Udělej zálohu. Soubory i databázi. Samotná změna trvalých odkazů se dotkne jen málo věcí, ale dál budeš upravovat
.htaccessnebo konfiguraci serveru a laťku pro kopii nastavuje článek o záloze, která se opravdu obnoví. - Zapiš si všechny současné URL. Tento seznam budeš po změně testovat. S WP-CLI:
$ wp post list --post_type=post,page --post_status=publish \ --fields=ID,post_name,url --format=csv > old-urls.csv$ wc -l old-urls.csv- Zkontroluj současnou strukturu, ať přesně víš, co nahrazuješ:
$ wp option get permalink_structure/%year%/%monthnum%/%postname%/- Zjisti, na kterých výsledcích vyhledávání záleží. Otevři Search Console nebo svou analytiku a poznamenej si deset až dvacet URL, které přivádějí návštěvnost. Právě ty vyzkoušej ručně.
Pokud nemáš přístup k shellu, což je na hostingu s panelem běžná situace, přeskoč WP-CLI a seznam exportuj pluginem nebo ho zkopíruj z mapy webu. Princip je stejný: starý seznam měj v souboru ještě před změnou, protože potom se už WordPressu nezeptáš, jaké staré URL byly.
Změna struktury#
Změnu proveď v Settings, potom Permalinks, vyber novou strukturu a ulož. S WP-CLI je to ekvivalentně:
$ wp rewrite structure '/%postname%/'$ wp rewrite flush$ wp rewrite list | headUložení stránky znovu vygeneruje pravidla přepisu. Na serveru, který čte .htaccess, se tím přepíše i blok WordPressu v tomto souboru, pokud je zapisovatelný. Pokud není, WordPress ti blok ukáže, abys ho vložil sám.
Jedno upozornění: pokud máš vlastní typ příspěvků nebo obchod WooCommerce, zkontroluj jejich základní nastavení zvlášť. Mají vlastní slugy a tvé celostránkové pravidlo je nesmí pohltit.
Pravidlo, které mapuje staré na nové#
Cílem je jedno pravidlo, které zachytí část, kterou chceš zachovat, a zahodí zbytek. Pro přechod z /2024/05/my-post/ na /my-post/ se vzor čte jako „čtyři číslice, lomítko, dvě číslice, lomítko, slug“.
Na serverech ve stylu Apache patří přesměrování do .htaccess nad blok # BEGIN WordPress, protože vlastní pravidlo WordPressu posílá všechno, co není soubor, do index.php, a jinak by se tam dostalo první:
<IfModule mod_rewrite.c>RewriteEngine OnRewriteRule ^[0-9]{4}/[0-9]{2}/([^/]+)/?$ /$1/ [R=302,L]</IfModule># BEGIN WordPress<IfModule mod_rewrite.c>RewriteEngine OnRewriteBase /RewriteRule ^index\.php$ - [L]RewriteCond %{REQUEST_FILENAME} !-fRewriteCond %{REQUEST_FILENAME} !-dRewriteRule . /index.php [L]</IfModule># END WordPressÚvodní lomítko ve vzoru chybí záměrně: v .htaccess vidí pravidlo cestu bez předpony adresáře. V hlavní konfiguraci serveru potřebuje stejné pravidlo na začátku ^/. Pravidlo drž ve tvaru RewriteRule. Míchání Redirect nebo RedirectMatch (jiný modul Apache) s RewriteRule v jednom souboru dává výsledky závislé na pořadí modulů, které lidi překvapují.
V nginx je stejná práce location s regulárním výrazem. Složené závorky vynucují uvozovky kolem vzoru:
location ~ "^/[0-9]{4}/[0-9]{2}/([^/]+)/?$" { return 302 /$1/;}Vlož ho do bloku server, vedle stávajícího location /, který obsahuje try_files $uri $uri/ /index.php?$args;. Regulární location se kontrolují dřív než obyčejná shoda předpony, takže vyhraje. Po ověření změň 302 na 301; v nginx dělá rewrite ... permanent; totéž co return 301, přičemž return je jednodušší a upřednostňovaná forma.
Žádné z těchto pravidel v uvedené podobě není úplné a o mezerách stojí za to vědět:
- Archivy podle data nejsou příspěvky.
/2024/05/nemá slug a neodpovídá, což je správně. Ale/2024/05/feed/má tvar příspěvku a bylo by přesměrováno na/feed/. Přidej výjimku profeed,pagea další vyhrazená slova svého webu, nebo je uveď jako první a zpracování zastav. - Stránky s rodiči. Stránka na
/services/hosting/nesedí na vzor s datem, takže se jí toto pravidlo nedotkne, a pokud měníš jen strukturu příspěvků, dál funguje. - Základy kategorií. Přesun
/category/news/na/news/je samostatné pravidlo a snadno se v něm chybuje, protože koliduje se slugy stránek. Než to uděláš, zkontroluj konflikty. - Řetězce dotazu. Obě pravidla výše při přesměrovaném požadavku zahodí řetězec dotazu, což je u přesunu trvalých odkazů téměř vždy to, co chceš. Pokud potřebuješ, aby parametry
?utm_přežily, řekni to výslovně:[R=301,L,QSA]v Apache;returnv nginx dotaz nepřipojí, dokud nepřidáš$is_args$args.
Mnoho jednotlivých URL: mapy a plugin Redirection#
Vzor funguje, když je změna systematická. Nefunguje, když se změnily samotné slugy nebo když jsi dvacet starých článků sloučil do pěti. To chce výslovný seznam, na řádek jednu starou a jednu novou cestu.
U seznamu několika desítek stačí obyčejná pravidla. U stovek je čisté řešení v nginx map: žije v bloku http a hledá se v konstantním čase.
map $request_uri $moved_to { default ""; /old-hosting-guide/ /guides/hosting/; /2023/11/vps-vs-shared/ /vps-vs-shared-hosting/;}server { # inside the existing server block if ($moved_to) { return 301 $moved_to; }}V nginx je if omezený a tohle je jedno z mála bezpečných použití, protože obsahuje jen return. V Apache existuje RewriteMap, ale smí se jen v hlavní konfiguraci serveru, nikdy v .htaccess. Na hostingu sdíleného typu se k ní nedostaneš, takže praktická volba je mnoho řádků RewriteRule nebo plugin.
Nejběžnější plugin je Redirection, který seznam ukládá do databáze, zaznamenává 404, abys našel zapomenuté URL, a umí importovat CSV. Běží uvnitř PHP, takže každý přesměrovaný požadavek stojí celé nahrání WordPressu, zatímco serverové pravidlo odpoví za mikrosekundy. Pro pár tisíc přesměrování je to přijatelné; u webu s velkou návštěvností plugin použij k nalezení URL a pravidla pak přesuň na server. Článek o rychlosti a cachování WordPressu vysvětluje, proč je plné nahrání WordPressu při každém požadavku ta drahá část.
.htaccess, nebo nginx: na čem jedeš?#
Záleží na tom, protože oba fungují jinak, a webový server svého hostingu bys neměl předpokládat.
- Apache čte
.htaccesspři každém požadavku v každém adresáři, kterým cesta prochází. Je to pomalejší než centrální konfigurace, ale pravidla se dají měnit bez restartu a může je upravovat plugin. Funguje to jen tehdy, když to server povolí (AllowOverride), což většina hostingů dělá. - LiteSpeed a OpenLiteSpeed čtou
.htaccesstaké, s kompatibilní syntaxí běžných direktiv. - nginx
.htaccessnemá. Pravidla žijí v konfiguraci serveru a změny vyžadují reload. Soubor.htaccessve složce WordPressu na serveru nginx nečte vůbec nic, a to je klasický důvod věty „moje přesměrování nic nedělá“.
Zjistíš to podle hlaviček odpovědi:
$ curl -sI https://example.com/ | grep -i '^server'server: nginxTuto hlavičku lze skrýt nebo změnit, takže chybějící nebo obecná hodnota odpovědí není. Další vodítko je správce souborů: pokud je v kořeni webu .htaccess, který WordPress přepsal při ukládání trvalých odkazů, něco ho čte. Pokud uložení trvalých odkazů vypíše zprávu, že WordPress nemohl aktualizovat .htaccess, jsi buď na serveru, který ho ignoruje, nebo je soubor jen pro čtení.
Panel RE:NODE ti tu nic neřekne a tento článek hádat nebude. Podívej se na skutečnou hlavičku Server svého webu a na to, co leží v kořeni tvých souborů ve správci souborů, a řiď se oddílem, který sedí. Pokud konfigurace webového serveru není tvoje k úpravám, odpověď zní: cesta přes .htaccess, pokud ho server čte; plugin Redirection, pokud ne; a požadavek na podporu, pokud potřebuješ serverové pravidlo, které sám napsat neumíš.
Smyčky přesměrování: příčiny podle pravděpodobnosti#
ERR_TOO_MANY_REDIRECTS v Chrome, „The page isn't redirecting properly“ ve Firefoxu. Smyčka znamená, že dvě věci se neshodnou na tom, jaká je kanonická URL, a každá posílá návštěvníka k verzi té druhé. Najdi neshodu a jednu stranu odstraň.
Nejdřív si prohlédni řetězec místo hádání. curl ve výchozím stavu nesleduje nic, tak mu řekni, ať sleduje, a omez počet skoků:
$ curl -sIL --max-redirs 8 https://example.com/some-post/ \ | grep -i -E '^(HTTP|location)'Čti řádky Location popořadě. Smyčka ukazuje dvě stejné adresy střídající se. Pak viděné porovnej s těmito příčinami.
HTTPS za proxy. Nejčastější příčina na moderním hostingu. TLS končí na reverzní proxy, která webovému serveru předává obyčejné HTTP. Pravidlo nebo plugin vidí http://, přesměruje na https://, proxy znovu odstraní TLS a cyklus se opakuje. Řešení je nechat WordPress věřit hlavičce, kterou proxy nastavuje, což v wp-config.php vypadá takto a vkládá se nad řádek, který říká, že už se nemá upravovat:
if ( isset( $_SERVER['HTTP_X_FORWARDED_PROTO'] ) && 'https' === $_SERVER['HTTP_X_FORWARDED_PROTO'] ) { $_SERVER['HTTPS'] = 'on';}Než se na to spolehneš, ověř, že tvoje proxy opravdu posílá X-Forwarded-Proto; na RE:NODE je slot proxy popsán tak, že předává adresu návštěvníka v X-Forwarded-For, takže hlavičku protokolu ověř, nepředpokládej ji. Článek o tom, co dělá reverzní proxy, tyto hlavičky vysvětluje, a text o HTTPS a Let's Encrypt popisuje, kde certifikát sedí.
Adresa webu se liší od pravidla. siteurl a home v databázi říkají http://example.com, zatímco serverové pravidlo vynucuje https://www.example.com. WordPress přesměrovává jedním směrem, server druhým. Podívej se, co je uloženo:
$ wp option get home$ wp option get siteurlPokud se do administrace nedostaneš, připni obě hodnoty v wp-config.php, které přepíšou hodnoty z databáze, dokud je nespravíš pořádně:
define( 'WP_HOME', 'https://example.com' );define( 'WP_SITEURL', 'https://example.com' );Souboj o koncové lomítko. WordPress přidává koncové lomítko k hezkým odkazům. Serverové pravidlo nebo plugin, který ho odstraňuje, pošle /post/ na /post a WordPress ho hned vrátí zpátky. Vyber si lomítko. Vlastní konvence WordPressu je ho ponechat, takže odstraň pravidlo, které ho ořezává.
Dvě vrstvy přesměrování. Bezpečnostní plugin, cachovací plugin, plugin pro přesměrování, soubor .htaccess a proxy hostingu mohou každý vynucovat HTTPS nebo kanonického hostitele. Jednotlivě mají pravdu, dohromady dělají smyčku. Vypínej je po jednom zvenku: přejmenuj wp-content/plugins/the-plugin přes správce souborů nebo spusť wp plugin deactivate --all a znovu je zapínej, dokud se smyčka nevrátí.
Pravidlo, které se trefí do vlastního cíle. Nejjednodušší smyčka ze všech, objevuje se v ručně psaných pravidlech: volný vzor jako ^(.*)$, který každou cestu přesměruje na trochu jinou cestu, se trefí do vlastního výstupu a spustí se znovu. Vzory kotvi pevně a dbej na to, aby výstup nemohl odpovídat vstupu. U pravidla pro data výše cíl /my-post/ neobsahuje číslice, takže znovu odpovídat nemůže.
Přesměrování v cache. Až odstraníš příčinu, prohlížeč dál přehrává uložené 301. Zkoušej v anonymním okně nebo přes curl, který cache nemá. Pokud zkoušíš pro skutečné návštěvníky, pamatuj, že i CDN nebo cache stránek před webem mohla přesměrování uložit, takže ji vyprázdni. Prázdná stránka nebo chyba 500 po úpravě .htaccess je jiný problém, který popisuje článek o bílé obrazovce a chybách 500 ve WordPressu.
Testování každého přesměrování#
Zkoušej přes curl -I, nikdy klikáním, protože curl ukáže stavový kód a cíl bez cache prohlížeče a bez automatických oprav. Spusť ho nad seznamem, který sis uložil před změnou:
$ while read -r path; do printf '%s -> ' "$path" curl -s -o /dev/null -w '%{http_code} %{redirect_url}\n' \ "https://example.com$path" done < old-paths.txtU každé staré URL chceš jedno 301 (při zkoušení 302) na novou URL a pak 200 na cíli. Cokoli se dvěma skoky stojí za opravu: první přesměrování posílá návštěvníky na URL, která sama přesměrovává, což plýtvá časem a rozmělňuje signál. Cokoli s 404 je URL, kterou tvé pravidlo minulo. Cokoli s 301 na úvodní stránku je lenivé pravidlo, které zahazuje smysl odkazu; každou starou stránku pošli jejímu skutečnému nástupci.
Až je výstup čistý, přepni 302 na 301, kde je potřeba, znovu načti server a seznam projdi ještě jednou.
Potom: odkazy, mapa webu a vyhledávání#
Přesměrování se starají o lidi, kteří přicházejí zvenčí. Všechno, co ovládáš, by se na ně mělo přestat spoléhat.
- Aktualizuj interní odkazy. Příspěvky, které na sebe odkazují celými starými URL, teď při každém kliknutí projdou přesměrováním. Nejdřív si prohlédni náhled:
wp search-replace 'example.com/2024/05/' 'example.com/' --dry-run, přečti počet a bez přepínače to spusť až po záloze. Nahrazování vzorů v serializovaných datech vždy veď přes WP-CLI, ne přes surové SQLUPDATE. Článek o přesunu WordPressu na nový hosting vysvětluje proč. - Znovu vygeneruj mapu webu, aby obsahovala jen nové URL, a odešli ji znovu v Search Console.
- Sleduj 404. Několik týdnů se dívej do logu webového serveru nebo do monitoru 404, jestli tam nejsou zapomenuté staré URL.
- Počítej s poklesem. Vyhledávačům trvá dny až týdny, než takový přesun zpracují. Dočasné kolísání, které se usadí, je normální; propad, který se nezotaví, je znamením pravidla, které přesměrovává na špatné místo.
Na RE:NODE má web s WordPressem na lince web stejný správce souborů a SFTP jako každý jiný tarif, což je všechno, co potřebuješ k úpravě .htaccess nebo wp-config.php a ke zkopírování zálohy před tím.
FAQ#
Poškodí změna trvalých odkazů moje pozice ve vyhledávání?
Ne, pokud každá stará URL odpoví jedním 301 na přímou náhradu. Počítej s krátkým kolísáním, než roboti web znovu zpracují. Pozice se ztrácejí, když staré URL vrací 404, vedou na úvodní stránku nebo procházejí několika skoky.
Mám při změně trvalých odkazů použít 301, nebo 302?
302 při zkoušení, protože špatné 301 zůstane v prohlížečích dlouho v cache, a potom 301 pro konečné pravidlo. Změna trvalých odkazů je trvalá, takže cílový stav je vždy 301.
Proč moje přesměrování v .htaccess nic nedělá?
Obvykle jedna ze tří věcí: server je nginx a .htaccess nečte, je vypnutý AllowOverride, nebo pravidlo stojí pod blokem WordPressu a nikdy se nespustí. Zkontroluj hlavičku Server přes curl -I a pravidlo přesuň nad # BEGIN WordPress.
Dá se přesměrovávat bez pluginu?
Ano, a u systematického vzoru bys to měl dělat. Serverové pravidlo odpoví dřív, než se spustí PHP. Pluginy dávají smysl, když máš stovky jednotlivých URL nebo chceš log 404, se kterým se dá pracovat.
Jak dlouho přesměrování držet?
Aspoň rok, ideálně neomezeně. Stojí skoro nic a externí odkazy a záložky na staré URL nezmizí, jakmile se vyhledávače zaktualizují.
Co znamená ERR_TOO_MANY_REDIRECTS?
Prohlížeč prošel víc přesměrování, než přijme, obvykle asi dvacet, protože dvě pravidla posílají návštěvníka tam a zpátky. Spusť curl -sIL --max-redirs 8 na dané URL, přečti řádky Location a odstraň jednu stranu neshody.


