Удалить запрос главной страницы

8

У меня есть домашняя страница, отображающая home.phpшаблон, содержащая 2 боковые панели с виджетами в них.

Основной запрос по-прежнему использует 10 стандартных сообщений, но, поскольку я их не отображаю, я бы хотел полностью исключить запрос к базе данных. Если потребуется, пустой пост-цикл будет делать, поскольку я не использую основной цикл в моем home.phpшаблоне.

Как бы я это сделал? Я мог бы использовать, pre_get_postsчтобы свести к минимуму и уменьшить запрос, но это все еще оставляет мне очень быстрый запрос, как мне полностью его исключить?

Том Дж Новелл
источник
1
Этот вопрос, кажется, стоит прочитать. Но если бы вы спросили меня, я бы использовал свой собственный шаблон и установил его как статическую домашнюю страницу из настроек, потому что, хотя это было бы возможно, это просто не стоит. Более интересное чтение здесь . Либо все это, либо я полностью упустил суть вашего вопроса.
N00b

Ответы:

7

posts_requestфильтр

Пролистывая, WP_Queryмы находим эту часть интереса:

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

Мы можем попытаться устранить основной домашний запрос через posts_requestфильтр. Вот пример:

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

где мы форсируем 'fields' => 'ids'ранний выход.

posts_pre_queryФильтр (РГ 4.6+)

Мы также могли бы использовать новый фильтр posts_pre_querysrc, доступный в 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 );

Этот фильтр позволяет пропустить обычные запросы к базе данных, чтобы вместо этого внедрить пользовательское внедрение сообщений.

Я только что проверил это и заметил, что это не предотвратит липкие сообщения, в противоположность posts_requestподходу.

Проверьте билет # 36687 для получения дополнительной информации и примера там @boonebgorges.

birgire
источник
Очень похоже на то, что я только что написал, но я не заметил часть идентификаторов полей, что отбросило еще 2 запроса, спасибо!
Том Дж. Новелл
1
Хорошо, отлично, иногда приходит в голову, как хорошо было бы иметь простой способ WP_Queryрано выйти , например, с помощью аргумента, подобного 'skip_query' => trueили даже через фильтр, но потом я понимаю, как легко это может испортить сайты в Интернете, так много способов ;-) @TomJNowell
birgire
split_the_queryПрямо под строками есть фильтр , делайте то же самое, но мне интересно, он не уменьшает количество запросов!
Sumit
Отличное решение, даже я пропустил 'fields' => 'ids', и я часто его использую ;-)
Питер Гусен
2

Вот замечательный трюк, который я узнал от @birgire, мы можем остановить основной запрос, добавив AND where 0=1к WHEREпредложению SQL-запроса. Это может все еще привести к одному запросу базы данных, но это наверняка остановит основной запрос от запроса постов

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

Вы также можете просто попробовать заменить WHEREпредложение наwhere 0 = 1

$where = ' where 0 = 1';

вместо

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

К сожалению, у меня нет времени что-либо тестировать, но это должно стать хорошей отправной точкой

Питер Гусен
источник
Это звучит так, как будто я ближе всего к тому, что я просил, или, по крайней мере, к наиболее оптимизированному запросу, я учту это при рассмотрении вопроса о том, можно ли удалить сам запрос
Том Дж. Новелл
+1 за то, что поделился этой идеей. Но я проверил это, и оно сократило время на 2 мс :)
Sumit
Хотелось бы мне вспомнить, откуда я это узнал, но это также используется ядром ;-) Я думаю, было бы неплохо игнорировать липкие слова на $q->set( 'ignore_sticky_posts', true );всякий случай.
Биргире
@birgire Отличное место. Даже с моим решением вы по-прежнему получаете отрывки из основного запроса ;-)
Питер Гусен
2

Для справки, до: 45q, после: 42q

Код очень похож на код, используемый @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 );
Том Дж Новелл
источник