Öffnet in einem neuen Tab

Warum leitet WordPress von alleine URLs um, wenn Permalinks aktiv sind?

Symptom

Wir hatten diesen Fall bei einer Kundenwebsite: Eine URL wie /gutscheine/ landete per 301 auf /xxx/gutscheine-fuer-gesangs-workshop/.

  1. Es war Kein Redirect-Plugin aktiv,
  2. in der .htaccess und der nginx-Konfiguration standen keine Redirects – nichts.
  3. Alle Plugins waren deaktivert
  4. die Weiterleitung blieb hartnäckig bestehen.

Stellt man die Permalinks auf „Einfach“, also in der Form example.test/?p=123 statt example.test/123/ passiert das Phänomen nicht.

Der HTTP-Header deutet klar auf WordPress als Verursacher hin:

curl -skI https://example.test/gutscheine/Code-Sprache: JavaScript (javascript)

liefert:

HTTP/2 301
location: https://example.test/singen-lernen-shop/gutscheine-fuer-gesangs-workshop/
x-redirect-by: WordPressCode-Sprache: HTTP (http)

x-redirect-by: WordPress bedeutet: Die Weiterleitung kommt direkt von WordPress.

Direkt abschalten hier…

Die Ursache: WordPress als “Wahrsager”

Man lernt bei WordPress nie aus…

Findet WordPress zu einer URL keinen Inhalt, entsteht ein 404 “Seite nicht gefunden” Fehler. Bevor dieser an den Browser ausgeliefert wird, gibt es noch den Aufruf der folgenden Funktion:

redirect_guess_404_permalink()

Diese Funktion sucht in der Datenbank nach einem veröffentlichten Beitrag, dessen Slug mit der Query Variablen beginnt.

Sinngemäß wird so etwas gemacht:

SELECT ID FROM wp_posts
WHERE post_name LIKE 'gutscheine%'
  AND post_status = 'publish'
  AND post_type IN (/* öffentliche Post-Types */);Code-Sprache: JavaScript (javascript)

Gibt es einen Treffer, leitet WordPress per 301 dorthin um. Der Slug gutscheine-fuer-gesangs-workshop beginnt mit gutscheine.

Die Weiterleitung wird nicht explizit gespeichert. WordPress berechnet sie bei jedem Seitenaufruf neu. Deshalb kann man sich hier dumm und dämlich suchen.

Der Guess Redirect funktioniert nur, wenn die Permalink Struktur anders als “Einfach” eingestellt ist (siehe oben). Die Rewrite-Regeln bei komplexen Permalinks machen aus /gutscheine/ die Abfrage-Variable “name=gutscheine” und diese wird dann in der Datenbankabfrage benutzt. Bei Einfach werden die Post-IDs benutzt und es gibt keine Abfrage-Variable.

Nicht deterministische Vorhersagen bei Weiterleitungen sind problematisch

Wahrscheinlichkeiten anstelle von exakten Abläufen sind in Zeiten von LLMs Normalität geworden, was aber nichts daran ändert, dass Weiterleitungen, die mal auftreten und mal nicht, und nirgendwo fest definiert sind, die Funktionsweise auf verschiedene Art und Weise beeinträchtigen.

Die Abfrage oben hat zum Beispiel keine Sortierung. Gibt es mehrere passende Beiträge, entscheidet die Datenbank, welcher zuerst kommt. Das bedeutet, im Laufe der Lebenszeit einer Website kann sich die Weiterleitung intern ändern, nämlich dann, wenn ein neuer noch ähnlichererer Beitrag erscheint, der weiter oben in der Sortierung steht.

Aus unserer Sicht ein typisches Beispiel von “Gut gemeint ist das Gegenteil von Gut”. Wenn ich mich in der URL vertippe möchte ich eine konkrete Fehlermeldung “404 Seite nicht gefunden” und keine Weiterleitung auf die nächstbeste Seite.

Wenn man das Ganze dann auch noch debuggen muss, wird es super nervig und in diesem Fall haben wir wirklich lange gebraucht, bis der Groschen gefallen war. :-/

Was es noch gibt: Den “Old-Slug-Redirect”

WordPress hat zum Thema interner Redirect einen zweiten, ähnlichen Mechanismus.

Ändert man den Slug eines Beitrags, speichert WordPress den alten in wp_postmeta unter _wp_old_slug und leitet die alte URL weiter. Dieser Redirect ist ebenfalls implizit, aber vergleicht wenigstens exakt, nicht per Teilstring. Prüfen lässt sich das Ganze so:

wp db query "SELECT post_id, meta_value FROM $(wp db prefix)postmeta WHERE meta_key = '_wp_old_slug' AND meta_value = 'gutscheine';"Code-Sprache: JavaScript (javascript)

Wenn Sie vor einem ähnlichem Problem stehen: Die Diagnose in drei Schritten

  1. Header prüfen. Steht dort x-redirect-by: WordPress, ist der Core verantwortlich. Wenn nicht, irgendein PlugIn oder es steht direkt in der .htaccess.
  2. Old-Slug ausschließen mit der Abfrage oben.
  3. Raten testweise abschalten (siehe unten) und erneut curl ausführen.
  4. Kommt jetzt ein 404, ist der Guess-Redirect bestätigt.

So schaltet man den Redirect-Wahrsager von WordPress ab:

<?php
add_filter('do_redirect_guess_404_permalink', '__return_false');Code-Sprache: HTML, XML (xml)

Oder, wenn man nur exakte Treffer erlauben möchte:

<?php
add_filter('strict_redirect_guess_404_permalink', '__return_true');Code-Sprache: HTML, XML (xml)