Eliminar la consulta de la página de inicio

8

Tengo una página de inicio que muestra la home.phpplantilla, que contiene 2 barras laterales con widgets en ellas.

La consulta principal todavía incluye las 10 publicaciones estándar, pero como no las estoy mostrando, me gustaría eliminar por completo la consulta que se realiza en la base de datos. Si es necesario, un bucle de publicación vacío funcionará ya que no estoy usando el bucle principal en mi home.phpplantilla.

¿Cómo haría esto? Podría usar pre_get_postspara minimizar y reducir la consulta, pero eso todavía me deja con una consulta muy rápida, ¿cómo la elimino por completo?

Tom J Nowell
fuente
1
Parece que vale la pena leer esta pregunta . Pero si me preguntas, usaría mi propia plantilla y la configuraría como página de inicio estática desde la configuración, porque si bien sería posible, simplemente no vale la pena. Más lectura interesante aquí . O todo eso o me perdí completamente el punto de tu pregunta.
N00b

Respuestas:

7

El posts_requestfiltro

Hojeando a través del WP_Queryencontramos esta parte de interés:

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;
   }

Podríamos intentar eliminar la solicitud de inicio principal a través del posts_requestfiltro. Aquí hay un ejemplo:

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 );

donde forzamos la 'fields' => 'ids'salida anticipada.

El posts_pre_queryfiltro (WP 4.6+)

También podríamos usar el nuevo filtro posts_pre_querysrc disponible en 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 );

Este filtro permite omitir las consultas habituales de la base de datos para implementar una inyección de publicaciones personalizada.

Acabo de probar esto y noté que esto no evitará publicaciones pegajosas, opuestas al posts_requestenfoque.

Mira el boleto # 36687 para obtener más información y el ejemplo de @boonebgorges.

Birgire
fuente
Muy similar a lo que acabo de escribir, pero no detecté la parte de ID de campo, que eliminó otras 2 consultas, ¡gracias!
Tom J Nowell
1
Ok, genial, a veces me viene a la mente lo bueno que sería tener una manera fácil de salir WP_Querytemprano, por ejemplo, a través de un argumento como 'skip_query' => trueo incluso a través de un filtro, pero luego me doy cuenta de lo fácil que podría estropear los sitios en Internet, por lo que muchas maneras ;-) @TomJNowell
birgire
Hay un filtro split_the_queryjusto debajo de las líneas, haga exactamente lo mismo, ¡pero me pregunto si no reduce la cantidad de consultas!
Sumit
Gran solución, incluso la perdí 'fields' => 'ids', y la uso mucho ;-)
Pieter Goosen,
2

Aquí hay un buen truco que aprendí de @birgire, podemos detener la consulta principal agregando AND where 0=1a la WHEREcláusula de la consulta SQL. Esto aún puede generar una consulta de base de datos, pero seguramente detendrá la consulta principal de las publicaciones.

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 ); 

También puede intentar reemplazar la WHEREcláusula conwhere 0 = 1

$where = ' where 0 = 1';

en vez de

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

Desafortunadamente, no tengo tiempo para probar nada, pero este debería ser un buen punto de partida

Pieter Goosen
fuente
Parece que es lo más cerca que puedo llegar a lo que pedí, o al menos, la consulta más optimizada. Consideraré esto mientras investigo si la consulta en sí puede ser erradicada
Tom J Nowell
+1 por compartir esta idea. Pero lo probé y redujo el tiempo en 2 ms :)
Sumit
Desearía poder recordar de dónde lo aprendí, pero esto también lo usa core ;-) Creo que sería bueno también ignorar las notas adhesivas por $q->set( 'ignore_sticky_posts', true );si acaso.
Birgire
@birgire Gran lugar. Incluso con mi solución, aún obtienes notas adhesivas de la consulta principal ;-)
Pieter Goosen
2

Para referencia, antes: 45q, después: 42q

El código es muy similar al código utilizado por @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
fuente