WordPress .htaccess omleidingen: 301 goed geregeld
Een URL verplaatsen zonder posities te verliezen: welke .htaccess directive je in WordPress nodig hebt, waar de regels moeten staan en hoe je test zonder jezelf buiten te sluiten.
Gepubliceerd
Je verplaatst een URL en wilt dat de oude zijn posities behoudt? Dan heb je een 301 in .htaccess nodig, op een plek waar WordPress hem niet wist, geschreven met de juiste directive en gericht op precies de URL die WordPress werkelijk uitserveert. Gaat één van die drie dingen mis, dan krijg je een omleidingsketen, een lus, of een 500 die je buiten wp-admin sluit.
Eerst de keuze, dan de plaatsing, dan de test — in die volgorde.
Welke directive: Redirect, RedirectMatch of RewriteRule
Er zijn twee Apache-modules in het spel en die zijn niet uitwisselbaar.
Redirect (mod_alias) — één bekend pad naar één bestemming. Het eenvoudigste dat werkt:
Redirect 301 /old-page/ https://example.com/new-page/
Twee gedragingen om te kennen. Hij matcht op een padprefix, niet op een exacte tekst, dus /old-page/ vangt ook /old-page/anything/ op en plakt /anything/ achter de bestemming. En hij neemt de query string automatisch mee.
RedirectMatch (mod_alias) — één reguliere expressie die veel URLs dekt. Zo verplaats je een hele sectie:
RedirectMatch 301 ^/blog/(.*)$ https://example.com/articles/$1
De groep (.*) wordt $1 in de bestemming, dus /blog/hello-world/ komt uit op /articles/hello-world/. Let op de voorloopslash: patronen van mod_alias matchen het volledige URL-pad.
RewriteRule (mod_rewrite) — nodig zodra de omleiding afhangt van een voorwaarde: de hostnaam, het protocol, een query string, een user agent. Niets in mod_alias kan die testen.
RewriteEngine On
RewriteCond %{HTTP_HOST} ^example\.com$ [NC]
RewriteRule ^(.*)$ https://www.example.com/$1 [R=301,L]
In een .htaccess op mapniveau wordt de voorloopslash uit het patroon weggehaald — daarom staat hier ^(.*)$ en in het mod_alias-voorbeeld ^/blog/. Dat door elkaar halen is veruit de meest voorkomende reden dat een gekopieerde regel stilletjes niets doet.
Kies standaard voor mod_alias. Grijp alleen naar RewriteRule als je echt een voorwaarde nodig hebt. Minder reguliere expressies, minder manieren om het fout te doen.
Waar de regels moeten staan
Eigen omleidingen horen boven de regel # BEGIN WordPress. Niet erbinnen.
# --- 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
Daar zijn twee losstaande redenen voor:
- WordPress herschrijft zijn eigen blok. Opslaan onder Instellingen → Permalinks roept
flush_rewrite_rules()aan, dat alles tussen de markers weggooit en opnieuw genereert. Een regel die je ertussen hebt gezet verdwijnt zodra iemand dat scherm aanraakt — mogelijk maanden later, zonder dat iemand de twee gebeurtenissen aan elkaar koppelt. - De volgorde bepaalt wie wint. Het WordPress blok eindigt met een vangnet dat elk verzoek zonder bestaand bestand of map naar
index.phpstuurt. EenRewriteRuledie daarna staat wordt nooit uitgevoerd.
Eén eerlijke complicatie: mod_alias en mod_rewrite draaien niet werkelijk in bestandsvolgorde. Apache verwerkt mod_alias tijdens de URL-vertaling en mod_rewrite op mapniveau pas later, tijdens de fixup-fase — een Redirect regel kan dus winnen van een RewriteRule die er in het bestand boven staat. Heb je beide nodig op overlappende paden, kies dan per pad één module en blijf daarbinnen. Een gevecht tussen mod_alias en mod_rewrite uitpluizen is dat uur niet waard.
Afsluitende slashes
De eigen canonieke omleiding van WordPress voegt aan de meeste permalinks een afsluitende slash toe. Dit dus:
Redirect 301 /old-page/ https://example.com/new-page
levert twee stappen op — jouw 301 naar de URL zonder slash, daarna de eigen 301 van WordPress die de slash toevoegt. Ketens geven ranking-signalen wel door, maar verspillen crawlbudget en kosten elke bezoeker een extra rondje.
Laad de bestemming eerst in een browser, kopieer de URL precies zoals die in de adresbalk tot rust komt, en gebruik die. Eindigt je permalinkstructuur op .html of juist zonder slash, richt je daar dan op. Er is hier geen universeel juist antwoord, alleen “match wat WordPress uitserveert”.
Testen zonder jezelf buiten te sluiten
.htaccess wordt bij elk verzoek gelezen. Een syntaxfout geeft een 500 voor de hele site, wp-admin inbegrepen, dus de weg terug moet klaarliggen voordat je hem nodig hebt.
Maak eerst een back-up van het bestand. Via SSH:
cp /path/to/wordpress/.htaccess /path/to/wordpress/.htaccess.bak
Geeft de site een 500, dan hernoem je het kapotte bestand terug en is de site meteen weer in de lucht. Houd in een ander venster een SFTP-sessie open — helemaal opnieuw inloggen terwijl de site plat ligt, is het moment waarop de paniek begint. Let op: apachectl configtest leest .htaccess niet in, dus die meldt een gezonde configuratie terwijl je site dood is.
Test met curl, niet met een browser. Browsers cachen 301-antwoorden hard en tonen je maar al te graag het resultaat van gisteren:
curl -sI https://example.com/old-page/ | head -n 5
Let op twee dingen: de statusregel moet 301 melden, en de Location: header moet exact de eind-URL zijn. Wil je de hele keten zien, volg hem dan:
curl -sIL https://example.com/old-page/ | grep -E '^(HTTP|Location)'
Meer dan één regel HTTP/1.1 301 betekent dat je een keten hebt gebouwd. Meer dan ongeveer vijf betekent dat je een lus hebt gebouwd, en curl stopt en zegt het je.
Gebruik een 302 zolang je twijfelt. Een 302 wordt niet op dezelfde manier gecachet, dus een fout draai je in seconden terug. Zet hem op 301 zodra curl de bestemming toont die je bedoelde. Het kost niets en heeft meer sites gered dan welke andere gewoonte in dit artikel ook.
Lijkt een regel helemaal niets te doen, controleer dan eerst of Apache het bestand überhaupt leest. AllowOverride None op de map laat Apache .htaccess volledig negeren, en nginx negeert het sowieso — bekijk de Server: header met curl -I voordat je reguliere expressies gaat uitpluizen. Om het blok samen te stellen met de juiste syntax voor jouw Apache-versie en installatiepad gebruik je de WordPress .htaccess generator.
Wanneer je .htaccess juist niet moet gebruiken
Voor een handvol omleidingen die redacteuren zelf moeten beheren is een omleidingsplugin die de regels in de database bewaart het betere gereedschap: het overleeft een verhuizing naar een andere host en vereist geen SSH. De keerzijde is reëel — php moet opstarten om de omleiding te serveren, en dat is trager dan Apache die direct antwoordt.
Gebruik .htaccess voor structurele, permanente verhuizingen: een domeinwijziging, het hernoemen van een sectie, https of www afdwingen. Gebruik een plugin voor losse redactionele omleidingen. Allebei tegelijk mag prima, zolang je weet welke laag welke URL bezit — want een omleiding die op twee plekken staat is een bug die op een slechte middag wacht.
FAQ
Vragen
Waar horen eigen omleidingen in het WordPress .htaccess bestand?
Boven de regel # BEGIN WordPress, nooit tussen de markers. WordPress genereert alles binnen die markers opnieuw zodra iemand het scherm Permalinks opslaat, dus een regel die je ertussen zet verdwijnt zonder waarschuwing. De plaatsing bepaalt ook de volgorde: het WordPress blok eindigt met een vangnetregel die alle overige verzoeken naar index.php stuurt.
Moet ik Redirect, RedirectMatch of RewriteRule gebruiken voor een 301?
Gebruik Redirect voor één bekend pad, RedirectMatch als één patroon veel URLs dekt, en RewriteRule als de omleiding afhangt van een voorwaarde zoals hostnaam, protocol of query string. Redirect en RedirectMatch komen uit mod_alias en zijn eenvoudiger. RewriteRule komt uit mod_rewrite en is de enige die voorwaarden kan testen.
Waarom veroorzaakt mijn .htaccess omleiding een omleidingslus?
Meestal voldoet de bestemming nog steeds aan de regel die de bezoeker erheen stuurde, waardoor die regel eindeloos opnieuw afgaat. De andere veelvoorkomende oorzaak is https afdwingen achter een load balancer of CDN, waarbij de server bij elk verzoek gewoon http ziet terwijl de bezoeker allang beveiligd surft. Test in dat geval de header X-Forwarded-Proto.
Maakt een afsluitende slash uit bij een WordPress omleiding?
Ja. De canonieke omleiding van WordPress voegt aan de meeste permalinks een afsluitende slash toe, dus een 301 naar een URL zonder slash levert twee stappen op in plaats van één. Geketende omleidingen geven ranking-signalen nog steeds door, maar verspillen crawlbudget en vertragen de bezoeker. Richt je op exact de eind-URL die WordPress uitserveert, inclusief de slash.
Hoe test ik een .htaccess omleiding zonder mijn site te slopen?
Draai curl tegen de oude URL zodat alleen de headers worden opgehaald, en lees de statuscode en de Location-header voordat je een browser vertrouwt. Browsers cachen 301-antwoorden agressief en tonen je een verouderd resultaat. Bewaar eerst een kopie van het werkende bestand, want een syntaxfout in .htaccess geeft een 500 op elke pagina, ook op wp-admin.
Waarom gaf mijn hele site een 500-fout na het toevoegen van een omleiding?
Eén foutieve directive in .htaccess legt elke URL onder die map plat, inclusief de beheeromgeving. Veelvoorkomende oorzaken zijn een niet-gesloten IfModule blok, een ontbrekende regel RewriteEngine On, of de toegangssyntax van Apache 2.2 en 2.4 door elkaar in één bestand. Verwijder het laatst toegevoegde blok en herlaad om dat te bevestigen.