Perché il loop non è vuoto su alcuni 404?


10

Mi sono imbattuto in uno strano problema.

Supponi di accedere a un URL casuale, con tre o più livelli di profondità:

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

Quindi lo is_404()è true. Fin qui tutto bene. Ma per qualche motivo vengono interrogati gli ultimi post.

$wp_query->request

è

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

Che poi ovviamente fa have_posts()ritorno truee così via. Qualcuno può spiegare questo?

Quello che ho scoperto finora:

La ragione per cui entra in gioco solo a tre o più livelli di profondità è che prima di allora WP cerca post e allegati che in qualche modo si traducono in qualche altro comportamento.

Sembra che anche se WP riconosce la richiesta come 404 a un certo punto, recupera i post più recenti. Con l'aiuto di @kaiser e @GM ho rintracciato questo da qualche parte da /wp-includes/class-wp.php:608


Se non aggiungi il codice della pagina sarà difficile aiutarti
— Tomás Cot

3
Questo non è specifico per il mio codice. Si comporta in questo modo su una nuova installazione con tutti i temi predefiniti.
— Kraftner,

puoi nominare almeno un tema, nel mio tema personalizzato non funziona? stai usando parametri specifici? hai cambiato le lumache? quale versione di WP stai usando?
— Tomás Cot

Davvero qualsiasi. Ma prova Twenty Eleven se vuoi.
— Kraftner,

Mi dispiace per tutta la domanda, pensavo che i post fossero in mostra.
— Tomás Cot

Risposte:


9

Potresti essere sorpreso, ma non c'è niente di strano lì.

Prima di tutto chiariamo che in WordPress quando si visita un URL frontend si attiva una query. Sempre.

Quella query è solo uno standard WP_Query, proprio come quelli eseguiti tramite:

$query = new WP_Query( $args );

C'è solo una differenza: le $argsvariabili sono generate da WordPress usando il WP::parse_request()metodo. Quello che fa questo metodo è solo guardare l'URL e le regole di riscrittura e convertire l'URL in una matrice di argomenti.

Ma cosa succede quando quel metodo non è in grado di farlo perché l'URL non è valido? La query args è solo una matrice come questa:

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

(Fonte qui e qui ).

In tal modo l'array viene passato a WP_Query.

Ora prova a fare:

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

Sei sorpreso che la query sia esattamente quella in OP? Non sono.

Così,

  1. parse_request() crea un array con una chiave di errore
  2. Quell'array viene passato a WP_Query, che lo esegue
  3. handle_404()che viene eseguito dopo la query, osserva il 'error'parametro e si imposta is_404()su true

Quindi, have_post()e is_404()non sono correlati. Il problema è che WP_Querynon esiste un sistema per cortocircuitare la query quando qualcosa va storto, quindi una volta che l'oggetto è stato creato, passa alcuni argomenti e la query verrà eseguita ...

Modificare:

Esistono 2 modi per superare questo problema:

  • Crea un 404.phpmodello; WordPress lo caricherà su 404 URL e lì non dovrai controllarehave_posts()
  • Forza $wp_querydi essere vuoto su 404, qualcosa del tipo:

    add_action( 'wp', function() {
        global $wp_query;
        if ( $wp_query->is_404() ) {
            $wp_query->init();
            $wp_query->is_404 = true; // init() reset 404 too
        }
    } );

4
Vorrei aggiungere che la ragione per cui ciò non accade in genere è che 404 di solito è il risultato di una query . Ma in questo caso è il risultato di una regola di riscrittura senza pari ( $wp->matched_rule), ma la query sta ancora eseguendo i movimenti perché non presta attenzione a questo.
— Rarst

+1. Sì, la query non lo presta attenzione e con il codice corrente non può prestare attenzione, perché non c'è modo di fermarlo. Ad esempio, quando viene richiesta una tassonomia non valida, WordPress viene impostato WHERE 1=0in sql perché non può arrestare la query, quindi forzare una query che non restituisca nulla ... @Rarst
— gmazzap

Va bene ora capisco. Quindi la vera domanda che rimane è perché diavolo WP_Query assume una query predefinita per ottenere post quando non si passano argomenti ragionevoli quando semplicemente restituendo nulla avrebbe molto più senso?
— Kraftner,

2
@kraftner come detto WordPress non può evitare l'esecuzione della query, e quando non ci sono argomenti resonable ci sono 2 scelte: eseguire una query che sicuramente non restituisce nulla (come quando viene richiesta una tassonomia non valida, vedere il commento sopra) o eseguire la query predefinita . Perché in questo caso WP sceglie quest'ultimo è un Q che dovrebbe essere chiesto agli sviluppatori principali :)
— gmazzap

@ TomásCot Certo, ma se fallisce, vorrei che fallisse davvero e non restituisse qualcosa di totalmente indipendente. Ad ogni modo, le cose si sono chiarite ora e devo solo fare un is_404()controllo aggiuntivo .
— Kraftner,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.