Warum ist die Schleife bei einigen 404 nicht leer?

10

Ich bin auf ein seltsames Problem gestoßen.

Angenommen, Sie greifen auf eine zufällige URL zu, die drei oder mehr Ebenen tief ist:

http://example.com/a/b/c
http://example.com/a/b/c/d
...

Dann is_404()ist true. So weit, ist es gut. Aber aus irgendeinem Grund werden die letzten Beiträge abgefragt.

$wp_query->request

ist

SELECT SQL_CALC_FOUND_ROWS wp_posts.ID 
    FROM wp_posts 
    WHERE 1=1 
        AND wp_posts.post_type = 'post' 
        AND (
            wp_posts.post_status    = 'publish' 
            OR wp_posts.post_status = 'private'
            ) 
    ORDER BY wp_posts.post_date DESC 
    LIMIT 0, 5

Was dann natürlich have_posts()zurückkehrt trueund so weiter. Kann jemand das erklären?

Was ich bisher herausgefunden habe:

Der Grund, der nur in drei oder mehr Ebenen einsetzt, ist, dass WP zuvor nach Posts und Anhängen sucht, die irgendwie zu einem anderen Verhalten führen.

Es scheint, dass WP, obwohl es die Anfrage an einem Punkt als 404 erkennt, die neuesten Beiträge abruft. Mit Hilfe von @kaiser und @GM habe ich dies von /wp-includes/class-wp.php:608 aufgespürt

Kraftner
quelle
Wenn Sie den Code der Seite nicht hinzufügen, wird es schwierig sein, Ihnen zu helfen
Tomás Cot
3
Dies ist nicht spezifisch für meinen Code. Verhält sich wie folgt bei einer brandneuen Installation mit allen Standardthemen.
Kraftner
Können Sie mindestens ein Thema nennen, das in meinem benutzerdefinierten Thema nicht funktioniert? Verwenden Sie bestimmte Parameter? Hast du die Schnecken gewechselt? Welche Version von WP verwenden Sie?
Tomás Cot
Wirklich keine. Aber versuchen Sie es mit Twenty Eleven, wenn Sie möchten.
Kraftner
Entschuldigung für die ganze Frage, ich dachte, die Beiträge würden angezeigt.
Tomás Cot

Antworten:

9

Sie werden vielleicht überrascht sein, aber da ist nichts Seltsames.

Lassen Sie uns zunächst klarstellen, dass Sie in WordPress beim Besuch einer Frontend-URL eine Abfrage auslösen. Immer.

Diese Abfrage ist nur ein Standard WP_Query, genau wie die, die über Folgendes ausgeführt werden:

$query = new WP_Query( $args );

Es gibt nur einen Unterschied: Die $argsVariablen werden von WordPress mit der WP::parse_request()Methode generiert . Diese Methode überprüft lediglich die URL und die Umschreiberegeln und konvertiert die URL in ein Array von Argumenten.

Aber was passiert, wenn diese Methode dies nicht kann, weil die URL ungültig ist? Die Abfrage args ist nur ein Array wie folgt:

array( 'error' => '404' );

(Quelle hier und hier ).

Das Array wird also an übergeben WP_Query.

Versuchen Sie nun Folgendes zu tun:

$query = new WP_Query( array( 'error' => '404' ) );
var_dump( $query->request );

Sind Sie überrascht, dass die Abfrage genau die in OP ist? Ich bin nicht.

So,

  1. parse_request() Erstellt ein Array mit einem Fehlerschlüssel
  2. Dieses Array wird an übergeben WP_Query, das es nur ausführt
  3. handle_404()Das wird nach der Abfrage ausgeführt, betrachtet den 'error'Parameter und setzt is_404()auf true

Also, have_post()und is_404()sind nicht verwandt. Das Problem ist, dass WP_Queryes kein System gibt, das die Abfrage kurzschließt, wenn etwas schief geht. Wenn das Objekt erstellt wurde, übergeben Sie ihm einige Argumente und die Abfrage wird ausgeführt ...

Bearbeiten:

Es gibt zwei Möglichkeiten, um dieses Problem zu lösen:

  • Erstellen Sie eine 404.phpVorlage. WordPress lädt das auf 404 URLs und dort müssen Sie nicht suchenhave_posts()
  • Erzwinge $wp_query, auf 404 leer zu sein, so etwas wie:

    add_action( 'wp', function() {
        global $wp_query;
        if ( $wp_query->is_404() ) {
            $wp_query->init();
            $wp_query->is_404 = true; // init() reset 404 too
        }
    } );
gmazzap
quelle
4
Ich möchte hinzufügen , dass der Grund , dass dies nicht geschieht normalerweise ist , dass 404 ist in der Regel zur Folge der Abfrage . In diesem Fall ist dies jedoch das Ergebnis einer nicht übereinstimmenden Umschreiberegel ( $wp->matched_rule), aber die Abfrage durchläuft die Bewegungen immer noch, da sie dies nicht beachtet.
Erster
+1. Ja, die Abfrage beachtet sie nicht und mit dem aktuellen Code kann sie nicht beachtet werden, da es keine Möglichkeit gibt, sie zu stoppen. Wenn beispielsweise eine ungültige Taxonomie abgefragt wird, wird WordPress WHERE 1=0in SQL festgelegt, da die Abfrage nicht gestoppt werden kann. Erzwingen Sie daher eine Abfrage, die nichts zurückgibt ... @Rarst
gmazzap
Okay, jetzt verstehe ich es. Die eigentliche Frage bleibt also, warum zum Teufel WP_Query eine Standardabfrage zum Abrufen von Posts annimmt, wenn keine vernünftigen Argumente übergeben werden, wenn nur nichts zurückgegeben wird, was viel sinnvoller wäre.
Kraftner
2
@kraftner wie gesagt WordPress kann die Abfrageausführungen nicht vermeiden, und wenn es keine vernünftigen Argumente gibt, gibt es zwei Möglichkeiten: eine Abfrage ausführen, die sicher nichts zurückgibt (wie wenn eine ungültige Taxonomie abgefragt wird, siehe Kommentar oben) oder eine Standardabfrage ausführen . Warum in diesem Fall WP Letzteres wählt, ist ein Q, das an die Kernentwickler gerichtet werden sollte :)
gmazzap
@ TomásCot Sicher, aber wenn es fehlschlägt, möchte ich, dass es wirklich fehlschlägt und nichts völlig Unabhängiges zurückgibt. Wie auch immer, die Dinge haben sich jetzt geklärt und ich muss nur noch eine zusätzliche is_404()Überprüfung durchführen.
Kraftner