web-dev-qa-db-fra.com

Supprimer la requête de page d'accueil

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

La requête principale tire toujours dans les 10 posts standard, mais comme je ne les affiche pas, je voudrais éliminer complètement la requête à la base de données. Si besoin est, une boucle de publication vide fera l'affaire, car je n'utilise pas la boucle principale de mon modèle home.php.

Comment je ferais ça? Je pourrais utiliser pre_get_posts pour minimiser et réduire la requête, mais cela me laisse quand même avec une requête très rapide, comment puis-je l'éliminer complètement?

8
Tom J Nowell

Le filtre posts_request

En parcourant le WP_Query, nous trouvons cette partie intéressante:

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 principale à la maison via le filtre posts_request. 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 le 'fields' => 'ids' pour une sortie anticipée.

Le filtre posts_pre_query (WP 4.6+)

Nous pourrions aussi utiliser le nouveau posts_pre_querysrc filtre 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 posts personnalisée.

Je viens de tester cela et j'ai remarqué que cela n'empêcherait pas les posts collants, contrairement à l'approche posts_request.

Découvrez le billet # 36687 pour plus d’informations et le exemple ici de @boonebgorges.

7
birgire

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 clause WHERE de la requête SQL. Cela peut toujours entraîner une requête de base de données, 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 simplement essayer de remplacer la clause WHERE par where 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

2
Pieter Goosen

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 );
2
Tom J Nowell