Supprimer la requête de la page d'accueil

8

J'ai une page d'accueil affichant le home.phpmodèle, contenant 2 barres latérales avec des widgets.

La requête principale tire toujours dans les 10 publications standard, mais comme je ne les affiche pas, j'aimerais éliminer complètement la requête effectuée dans la base de données. Si besoin est, une boucle de message vide fera comme je n'utilise pas la boucle principale dans mon home.phpmodèle.

Comment pourrais-je faire ça? Je pourrais utiliser pre_get_postspour minimiser et réduire la requête, mais cela me laisse encore une requête très rapide, comment puis-je l'éliminer complètement?

Tom J Nowell
la source
1
Cette question semble mériter d'être lue. Mais si vous me le demandiez, j'utiliserais mon propre modèle et le définirais comme page d'accueil statique à partir des paramètres, car même si cela serait possible, cela n'en vaut pas la peine. Une lecture plus intéressante ici . Soit tout cela, soit j'ai complètement raté le point de votre question.
N00b

Réponses:

7

Le posts_requestfiltre

En parcourant le, WP_Querynous trouvons cette partie d'intérêt:

if ( !$q['suppress_filters'] ) {
    /**
     * Filter the completed SQL query before sending.
     *
     * @since 2.0.0
     *
     * @param array    $request The complete SQL query.
     * @param WP_Query &$this   The WP_Query instance (passed by reference).
     */
      $this->request = apply_filters_ref_array( 'posts_request', 
          array( $this->request, &$this ) );
   }

   if ( 'ids' == $q['fields'] ) {
       $this->posts = $wpdb->get_col( $this->request );
       $this->posts = array_map( 'intval', $this->posts );
       $this->post_count = count( $this->posts );
       $this->set_found_posts( $q, $limits );
       return $this->posts;
   }

Nous pourrions essayer d'éliminer la demande d'accueil principale via le posts_requestfiltre. Voici un exemple:

add_filter( 'posts_request', function( $request, \WP_Query $q )
{
    // Target main home query
    if ( $q->is_home() && $q->is_main_query() )
    {
        // Our early exit
        $q->set( 'fields', 'ids' );

        // No request
        $request = '';
    }

    return $request;    

}, PHP_INT_MAX, 2 );

où nous forçons la 'fields' => 'ids'sortie anticipée.

Le posts_pre_queryfiltre (WP 4.6+)

Nous pourrions également utiliser le nouveau filtre posts_pre_querysrc disponible dans WordPress 4.6+

add_filter( 'posts_pre_query', function( $posts, \WP_Query $q )
{
    if( $q->is_home() && $q->is_main_query() )
    {
        $posts = [];
        $q->found_posts = 0;
    }
    return $posts;
}, 10, 2 );

Ce filtre permet d'ignorer les requêtes de base de données habituelles pour implémenter une injection de publications personnalisée à la place.

Je viens de tester cela et j'ai remarqué que cela n'empêchera pas les messages collants, contrairement à l' posts_requestapproche.

Consultez le ticket # 36687 pour plus d'informations et l' exemple par @boonebgorges.

Birgire
la source
Très similaire à ce que je viens d'écrire, mais je n'ai pas repéré la partie des champs ids, qui a fait tomber 2 autres requêtes, merci!
Tom J Nowell
1
ok génial, parfois il me vient à l'esprit à quel point ce serait bien d'avoir un moyen facile de sortir WP_Querytôt, par exemple à travers un argument comme 'skip_query' => trueou même à travers un filtre, mais je me rends compte à quel point cela pourrait facilement gâcher des sites sur Internet, donc plusieurs façons ;-) @TomJNowell
birgire
Il y a un filtre split_the_queryjuste en dessous des lignes, faites exactement la même chose mais je me demande qu'il ne réduit pas le nombre de requêtes!
Sumit
Excellente solution, même si j'ai raté 'fields' => 'ids', et je l'utilise beaucoup ;-)
Pieter Goosen
2

Voici une astuce intéressante que j'ai apprise de @birgire, nous pouvons arrêter la requête principale en ajoutant AND where 0=1à la WHEREclause de la requête SQL. Cela peut toujours entraîner une seule requête db, mais cela empêchera sûrement la requête principale d'interroger les publications

add_filter( 'posts_where', function ( $where, \WP_Query $q )
{
    if (    $q->is_home()
         && $q->is_main_query()
    ) {
        $where .= ' AND where 0 = 1';
    }

    return $where;
}, 10, 2 ); 

Vous pouvez également essayer de remplacer la WHEREclause parwhere 0 = 1

$where = ' where 0 = 1';

au lieu de

$where .= ' AND where 0 = 1';

Malheureusement, je n'ai pas le temps de tester quoi que ce soit, mais cela devrait être un bon point de départ

Pieter Goosen
la source
Cela semble être le plus proche possible de ce que j'ai demandé, ou du moins la requête la plus optimisée, je considérerai cela tout en recherchant si la requête elle-même peut être éradiquée
Tom J Nowell
+1 pour avoir partagé cette idée. Mais je l'ai testé et cela réduit le temps de 2 ms :)
Sumit
J'aimerais pouvoir me rappeler d'où je l'ai appris, mais c'est également utilisé par le noyau ;-) Je pense que ce serait bien d'ignorer les stickies $q->set( 'ignore_sticky_posts', true );au cas où.
birgire
@birgire Super endroit. Même avec ma solution, vous obtenez toujours des adhésifs de la requête principale ;-)
Pieter Goosen
2

Pour référence, avant: 45q, après: 42q

Le code est très similaire au code utilisé par @birgire

function _tomjn_home_cancel_query( $query, \WP_Query $q ) {
    if ( !$q->is_admin() && !$q->is_feed() && $q->is_home() && $q->is_main_query() ) {
        $query = false;
        $q->set( 'fields', 'ids' );
    }
    return $query;
}
add_filter( 'posts_request', '_tomjn_home_cancel_query', 100, 2 );
Tom J Nowell
la source