WP_Query - filtrare o direttamente?

2 gen 2016, 05:01:18
Visualizzazioni: 13.5K
Voti: 5

Il numero dei miei file, template, script, query ecc. sta diventando elevato e ho bisogno di un buon sistema per gestire tutto.

Ho cercato di mantenere tutto organizzato:

  • Nessun tag <script> nei template
  • CSS inline solo quando si tratta di variabili PHP che possono essere modificate dinamicamente dalle opzioni di amministrazione
  • File unici grandi per JS e CSS per minimizzare le richieste

Ora è il momento di organizzare le mie query perché ne ho almeno 10 e continuano ad aumentare.

  1. Prima opzione: usare add_filter() personalizzato per ogni query

    • Non devo cercare le query perché sono tutte in un unico file o directory
    • Se devo modificarla, devo farlo solo in un posto, non in tutti i diversi template
  2. Seconda opzione: scrivere tutte le query direttamente nei template come si fa di solito

    • Praticamente ogni punto è il contrario della prima opzione

Domanda:

L'uso di filtri per gli argomenti delle query ha degli svantaggi? Prestazioni? Altro?


Esempio:

  1. Modalità usuale:

    $args = array(
            'post_type'         => 'my-post',
            'posts_per_page'    => 8,
            'orderby'           => 'rand', 
        );
    
    }
    
    $results = new WP_Query( $args );
    
  2. Con filtro:

    //In un file -> facile da trovare e modificare
    add_filter( 'some_args', 'some_search_args' );
    
    function some_search_args( $search_args ) {
        $search_args['post_type'] = 'property';
        $search_args['posts_per_page'] = 8;
        $search_args['orderby'] = 'rand';
    
        //Tutti i tipi di logica e codice condizionale qui
        
        return $search_args;
    }
    
    
    //E
    
    
    //Basta includere così in qualsiasi template e tutte le volte che vuoi
    //Per modificare la query, basterà cambiare il codice sopra
    $search_args = array();
    $search_args = apply_filters( 'some_args', $search_args );
    
    $results = new WP_Query( $search_args );
    
0
Tutte le risposte alla domanda 1
4

Devi considerare diverse cose qui e sembra che tu sia interessato a migliorare le prestazioni di una query. La prima e più importante domanda che devi porti è:

Ho bisogno di una query personalizzata?

Ho scritto un post approfondito su questo argomento tempo fa che dovresti consultare. Se dopo aver letto il mio post nel link hai risposto sì alla domanda precedente, allora devi considerare quanto segue quando crei query personalizzate:

  • Evita (quando possibile) operazioni complesse di orderby come l'ordinamento per valori meta. SQL non è il migliore nell'ordinamento e PHP a volte è più veloce. Preferisco usort() per ordinamenti complessi per risparmiare risorse. Anche l'ordinamento casuale è molto dispendioso in termini di risorse.

  • Evita (quando possibile) di costruire query complesse con meta query e tax query pesantemente annidate, specialmente con molti operatori OR. Queste sono piuttosto impegnative per le risorse.

  • Evita (quando possibile) di utilizzare operatori LIKE nel tuo SQL generato. Anche questi sono costosi.

  • Usa i transienti (e le cache) per memorizzare query costose. Per query casuali, non puoi farlo, quindi dovrai esaminare altri metodi per affrontare questo problema.

  • Evita sempre il tipico ciclo foreach in cui ottieni un elenco di termini e poi esegui una query personalizzata per ogni singolo termine, sono davvero costosi. Piuttosto, interroga tutti i post una volta sola e poi usa usort() per ordinare i risultati.

  • Crea una query in base a ciò che ti serve. La maggior parte delle volte abbiamo solo bisogno di interrogare i post per ottenere i loro ID da passare a un'altra funzione. In casi come questi, interroga solo gli ID dei post. Questo fa davvero risparmiare molte risorse. Basta aggiungere 'fields'=>'ids', ai tuoi argomenti della query.

  • Per velocizzare query non paginate, usa get_posts() o semplicemente passa 'no_found_rows'=>true a WP_Query (questo è esattamente ciò che fa `get_posts). Questo salta il processo di paginazione e fa risparmiare molte risorse su database grandi.

Questo è solo inteso come una sorta di linea guida per velocizzare la query. Ci sono ancora altre cose per velocizzare le query.

L'uso di filtri per gli argomenti della query ha degli svantaggi? Prestazioni? Qualcos'altro?

Non vedo perché potrebbero esserci problemi. Se stai creando un tema commerciale, lo stai facendo sicuramente nel modo giusto. Rendere qualcosa filtrabile rende la vita molto più facile agli autori di child theme. Potrebbe costare un millesimo di millesimo di millesimo di secondo, ma è sicuramente tempo ben speso. È come la sanificazione. La sanificazione costa tempo e risorse (sebbene sia molto, molto poco), ma spendere un millisecondo in più su qualcosa può salvare il tuo sito dall'essere hackerato e distrutto.

IMHO, dovresti esaminare altri modi per velocizzare una query senza compromettere usabilità e manutenibilità. L'opzione 2 è sicuramente qualcosa che dovresti fare per temi commerciali.

IDEA (Potrebbe essere un po' eccessiva ;-))

Puoi anche usare pre_get_posts per filtrare la tua query personalizzata e renderla filtrabile. È semplice come impostare il tuo parametro personalizzato nella tua query e poi usare quel parametro per indirizzare la tua query.

Nel seguente esempio, useremo un parametro personalizzato query_no a cui assegneremo valori numerici.

Le Query

$q1 = new WP_Query( ['query_no' => 1] );    
$q2 = new WP_Query( ['query_no' => 2] );    
$q3 = new WP_Query( ['query_no' => 3] );    

pre_get_posts

add_action( 'pre_get_posts', function( $q ) 
{
    if ( $q->get( 'query_no' ) == 1 ) {
        $q->set( 'posts_per_page', -1 );
        // Aggiungi qualsiasi altro argomento extra da impostare
    }

    if ( $q->get( 'query_no' ) == 2 ) {
        $q->set( 'post_type', ['post', 'page'] );
        // Aggiungi qualsiasi altro argomento extra da impostare
    }

    if ( $q->get( 'query_no' ) == 3 ) {
        $q->set( 'post_status', 'trash' );
        // Aggiungi qualsiasi altro argomento extra da impostare
    }
} );

L'utente ora può aggiungere argomenti aggiuntivi o modificare quelli passati.

add_action( 'pre_get_posts', function( $q ) 
{
    if ( $q->get( 'query_no' ) == 2 ) {
        // Aggiungiamo un altro post type
        $post_types = $q->get( 'post_type' );
        $post_types = array_merge( $post_types, ['my_post_type'] );

        $q->set( 'post_type'     , $post_types );
        $q->set( 'posts_per_page', -1          );
        // Aggiungi qualsiasi altro argomento extra da impostare
    }

}, 
11 // Assicurati che questo venga eseguito dopo l'azione predefinita
); 
2 gen 2016 09:02:11
Commenti

Cosa ne pensi dei transient quando i risultati delle query sono gli stessi? Esempio banale ma comunque: la query viene fatta via ajax -> imposta un transient -> e quando l'utente spamma il bottone senza cambiare i campi di input (ho impostato una protezione anti-spam per i pulsanti ajax ma comunque..) -> ottieni i risultati dai transient? Lo chiedo perché la mia query enorme è legata a una mappa e lo zoom/panning richiama un'altra query esattamente identica perché mostrare es. 100 000 marcatori uccide ogni browser.

N00b N00b
2 gen 2016 12:56:22

Dai un'occhiata ai post collegati sotto usort(). Io creo nomi di transient unici prendendo gli argomenti, poi uso md5() per creare una chiave unica da aggiungere al nome del transient. In questo modo, se gli argomenti della query cambiano, viene creato un transient unico. Qualsiasi altra chiamata successiva con gli stessi argomenti semplicemente carica i risultati dal transient.

Pieter Goosen Pieter Goosen
2 gen 2016 13:46:27

Scusa, devo essere cieco perché non l'avevo visto prima.. Grazie per la risposta molto dettagliata.

N00b N00b
2 gen 2016 13:49:47

Nessun problema, stiamo ancora sentendo gli effetti postumi del nuovo anno, ahahahah. Buon divertimento ;-)

Pieter Goosen Pieter Goosen
2 gen 2016 13:50:47