Przekierowania htaccess w WordPress: 301 zrobione poprawnie
Przenieś adres URL bez utraty pozycji: która dyrektywa .htaccess w WordPress jest właściwa, gdzie muszą stać reguły i jak je przetestować, nie odcinając sobie dostępu.
Opublikowano
Przenosisz adres URL i chcesz, żeby stary zachował swoje pozycje? Potrzebujesz przekierowania 301 w pliku .htaccess — umieszczonego tam, gdzie WordPress go nie skasuje, napisanego właściwą dyrektywą i wskazującego dokładnie ten adres, który WordPress faktycznie serwuje. Pomyl się w którymkolwiek z tych trzech punktów, a dostaniesz łańcuch przekierowań, pętlę albo błąd 500, który odetnie ci dostęp do wp-admin.
Najpierw decyzja, potem miejsce, potem test — w tej kolejności.
Która dyrektywa: Redirect, RedirectMatch czy RewriteRule
W grze są dwa moduły Apache i nie są wymienne.
Redirect (mod_alias) — jedna znana ścieżka do jednego celu. Najprostsze rozwiązanie, które działa:
Redirect 301 /old-page/ https://example.com/new-page/
Dwie rzeczy warto znać. Dyrektywa dopasowuje prefiks ścieżki, a nie dokładny ciąg znaków, więc /old-page/ łapie także /old-page/anything/ i dokleja /anything/ do adresu docelowego. Przenosi też automatycznie ciąg zapytania.
RedirectMatch (mod_alias) — jedno wyrażenie regularne obejmujące wiele adresów. Tak przenosi się całą sekcję:
RedirectMatch 301 ^/blog/(.*)$ https://example.com/articles/$1
Grupa przechwytująca (.*) staje się $1 w adresie docelowym, więc /blog/hello-world/ ląduje na /articles/hello-world/. Zwróć uwagę na początkowy ukośnik: wzorce mod_alias dopasowują pełną ścieżkę adresu URL.
RewriteRule (mod_rewrite) — konieczna, gdy przekierowanie zależy od warunku: nazwy hosta, protokołu, ciągu zapytania, klienta użytkownika. Nic w mod_alias nie potrafi tego sprawdzić.
RewriteEngine On
RewriteCond %{HTTP_HOST} ^example\.com$ [NC]
RewriteRule ^(.*)$ https://www.example.com/$1 [R=301,L]
We wzorcu w pliku .htaccess działającym na poziomie katalogu początkowy ukośnik jest usuwany — dlatego mamy tu ^(.*)$, a w przykładzie z mod_alias ^/blog/. Pomylenie tych dwóch rzeczy to zdecydowanie najczęstszy powód, dla którego wklejona reguła po cichu nic nie robi.
Domyślnie sięgaj po mod_alias. Po RewriteRule sięgaj tylko wtedy, gdy naprawdę potrzebujesz warunku. Mniej wyrażeń regularnych, mniej sposobów na pomyłkę.
Gdzie muszą stać reguły
Własne przekierowania należą powyżej linii # BEGIN WordPress. Nie w jej wnętrzu.
# --- custom redirects ---
Redirect 301 /old-page/ https://example.com/new-page/
RedirectMatch 301 ^/blog/(.*)$ https://example.com/articles/$1
# BEGIN WordPress
# The directives (lines) between "BEGIN WordPress" and "END WordPress" are
# dynamically generated, and should only be modified via WordPress filters.
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteRule .* - [E=HTTP_AUTHORIZATION:%{HTTP:Authorization}]
RewriteBase /
RewriteRule ^index\.php$ - [L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule . /index.php [L]
</IfModule>
# END WordPress
Są ku temu dwa niezależne powody:
- WordPress nadpisuje swój własny blok. Zapisanie w Ustawienia → Bezpośrednie odnośniki wywołuje
flush_rewrite_rules(), które kasuje wszystko pomiędzy znacznikami i generuje to od nowa. Reguła, którą tam wstawiłeś, zniknie, gdy ktoś następnym razem dotknie tego ekranu — być może miesiące później, i nikt nie połączy tych dwóch zdarzeń. - O wyniku decyduje kolejność. Blok WordPress kończy się regułą zbiorczą, która kieruje każde żądanie niebędące plikiem ani katalogiem do
index.php. RegułaRewriteRuleumieszczona po niej nigdy się nie wykona.
Jedna uczciwa komplikacja: mod_alias i mod_rewrite w rzeczywistości nie działają w kolejności zapisu w pliku. Apache przetwarza mod_alias podczas tłumaczenia adresu URL, a katalogowy mod_rewrite dopiero później, w fazie fixup — linia Redirect może więc wygrać z regułą RewriteRule umieszczoną wyżej w pliku. Jeśli okaże się, że potrzebujesz obu na nakładających się ścieżkach, wybierz dla danej ścieżki jeden moduł i przy nim zostań. Debugowanie starcia mod_alias z mod_rewrite nie jest warte tej godziny.
Ukośniki na końcu adresu
Własne przekierowanie kanoniczne WordPress dodaje ukośnik na końcu większości bezpośrednich odnośników. Czyli to:
Redirect 301 /old-page/ https://example.com/new-page
daje dwa skoki — twoje przekierowanie 301 na adres bez ukośnika, a potem własne 301 WordPressa, które ukośnik dokłada. Łańcuchy nadal przekazują sygnały rankingowe, ale marnują budżet indeksowania i dokładają jedno okrążenie każdemu odwiedzającemu.
Najpierw otwórz adres docelowy w przeglądarce, skopiuj adres dokładnie w takiej postaci, w jakiej ustabilizuje się w pasku adresu, i użyj właśnie jego. Jeśli twoja struktura odnośników kończy się na .html albo nie ma ukośnika na końcu, dopasuj się do tego. Nie ma tu uniwersalnie poprawnej odpowiedzi, jest tylko zasada: „trafiaj w to, co serwuje WordPress”.
Testowanie bez odcinania sobie dostępu
Plik .htaccess jest czytany przy każdym żądaniu. Błąd składni zwraca kod 500 dla całej witryny, wp-admin włącznie, więc droga powrotna musi istnieć, zanim będzie ci potrzebna.
Najpierw zrób kopię pliku. Przez SSH:
cp /path/to/wordpress/.htaccess /path/to/wordpress/.htaccess.bak
Jeśli witryna zwróci 500, wystarczy przywrócić nazwę uszkodzonego pliku i witryna natychmiast wraca. Trzymaj w drugim oknie otwartą sesję SFTP — logowanie od zera przy leżącej witrynie to moment, w którym zaczyna się panika. Pamiętaj też, że apachectl configtest nie analizuje pliku .htaccess, więc zgłosi zdrową konfigurację, podczas gdy twoja witryna jest martwa.
Testuj curlem, nie przeglądarką. Przeglądarki mocno buforują odpowiedzi 301 i chętnie pokażą ci wynik sprzed doby:
curl -sI https://example.com/old-page/ | head -n 5
Sprawdź dwie rzeczy: w linii statusu ma być 301, a nagłówek Location: ma zawierać dokładny adres docelowy. Żeby zobaczyć cały łańcuch, podążaj za nim:
curl -sIL https://example.com/old-page/ | grep -E '^(HTTP|Location)'
Więcej niż jedna linia HTTP/1.1 301 oznacza, że zbudowałeś łańcuch. Więcej niż około pięciu oznacza, że zbudowałeś pętlę — curl zatrzyma się i ci to powie.
Póki nie masz pewności, używaj kodu 302. Odpowiedź 302 nie jest buforowana w ten sam sposób, więc pomyłkę cofniesz w kilka sekund. Przełącz na 301, gdy curl pokaże cel, o który ci chodziło. Nic to nie kosztuje, a uratowało więcej witryn niż jakikolwiek inny nawyk z tego artykułu.
Jeśli reguła sprawia wrażenie, jakby w ogóle nic nie robiła, sprawdź najpierw, czy Apache w ogóle czyta ten plik. AllowOverride None na katalogu sprawia, że Apache całkowicie ignoruje .htaccess, a nginx ignoruje go zawsze — zajrzyj do nagłówka Server: przy pomocy curl -I, zanim zaczniesz debugować wyrażenia regularne. Aby złożyć blok z właściwą składnią dla twojej wersji Apache i ścieżki instalacji, skorzystaj z generatora .htaccess dla WordPress.
Kiedy nie używać .htaccess w ogóle
Dla garstki przekierowań, którymi redaktorzy mają zarządzać sami, lepszym narzędziem jest wtyczka trzymająca reguły w bazie danych: przetrwa zmianę hostingu i nie wymaga dostępu SSH. Kompromis jest realny — php musi się uruchomić, żeby obsłużyć przekierowanie, a to wolniej, niż gdy odpowiada bezpośrednio Apache.
Używaj .htaccess do zmian strukturalnych i trwałych: zmiany domeny, przemianowania sekcji, wymuszenia https lub www. Wtyczki używaj do pojedynczych przekierowań redakcyjnych. Jedno i drugie naraz jest w porządku, dopóki wiesz, która warstwa odpowiada za który adres — bo przekierowanie zdefiniowane w dwóch miejscach to błąd, który czeka na zły dzień.
FAQ
Pytania
Gdzie w pliku .htaccess WordPress umieszczać własne przekierowania?
Powyżej linii # BEGIN WordPress, nigdy pomiędzy znacznikami. WordPress regeneruje wszystko wewnątrz tych znaczników za każdym razem, gdy ktoś zapisze ekran Bezpośrednie odnośniki, więc reguła umieszczona w środku znika bez ostrzeżenia. Miejsce decyduje też o kolejności: blok WordPress kończy się regułą zbiorczą, która kieruje wszystkie niedopasowane żądania do index.php.
Użyć Redirect, RedirectMatch czy RewriteRule do przekierowania 301?
Redirect do pojedynczej znanej ścieżki, RedirectMatch gdy jeden wzorzec obejmuje wiele adresów URL, a RewriteRule gdy przekierowanie zależy od warunku, takiego jak nazwa hosta, protokół czy ciąg zapytania. Redirect i RedirectMatch pochodzą z mod_alias i są prostsze. RewriteRule pochodzi z mod_rewrite i jako jedyna potrafi sprawdzać warunki.
Dlaczego moje przekierowanie w .htaccess tworzy pętlę?
Zwykle adres docelowy nadal pasuje do reguły, która wysłała tam odwiedzającego, więc reguła uruchamia się w nieskończoność. Druga częsta przyczyna to wymuszanie https za load balancerem lub siecią CDN, gdzie serwer widzi zwykłe http przy każdym żądaniu, choć odwiedzający jest już na połączeniu szyfrowanym. Sprawdzaj wtedy nagłówek X-Forwarded-Proto.
Czy ukośnik na końcu ma znaczenie w przekierowaniu WordPress?
Tak. Przekierowanie kanoniczne WordPress dodaje ukośnik na końcu większości bezpośrednich odnośników, więc wskazanie przekierowaniem 301 adresu bez ukośnika daje dwa skoki zamiast jednego. Łańcuchy przekierowań nadal przekazują sygnały rankingowe, ale marnują budżet indeksowania i spowalniają odwiedzającego. Trafiaj w dokładny adres docelowy, który serwuje WordPress, razem z ukośnikiem.
Jak przetestować przekierowanie w .htaccess bez psucia witryny?
Uruchom curl z flagą pobierającą same nagłówki na starym adresie i odczytaj kod statusu oraz nagłówek Location, zanim zaufasz przeglądarce. Przeglądarki agresywnie buforują odpowiedzi 301 i pokażą ci nieaktualny wynik. Najpierw zachowaj kopię działającego pliku, bo błąd składni w .htaccess zwraca kod 500 na każdej stronie, łącznie z wp-admin.
Dlaczego cała witryna zwróciła błąd 500 po dodaniu przekierowania?
Jedna błędna dyrektywa w .htaccess kładzie każdy adres URL w tym katalogu, razem z panelem administracyjnym. Typowe przyczyny to niezamknięty blok IfModule, brakująca linia RewriteEngine On albo składnia dostępu z Apache 2.2 i 2.4 pomieszana w jednym pliku. Usuń ostatnio dodany blok i przeładuj stronę, żeby to potwierdzić.