web-dev-qa-db-ja.com

ホームページクエリを削除します。

私はhome.phpテンプレートを表示するホームページを持っていて、そこにはウィジェットが入った2つのサイドバーがあります。

メインのクエリはまだ標準の10の投稿を引き込んでいますが、これらを表示していないので、データベースに対して行われているクエリを完全に排除したいと思います。必要に応じて、home.phpテンプレートでメインループを使用していないので、空のポストループでも問題ありません。

どのようにこれをしますか?クエリを最小化したり減らしたりするためにpre_get_postsを使用することもできますが、それでも非常に高速なクエリが残ります。

8
Tom J Nowell

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フィルタ(WP 4.6以上)

新しいposts_pre_queryを使うこともできますsrc 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による。

7
birgire

これは@birgireから学んだきちんとしたトリックです。SQLクエリのWHERE句にAND where 0=1を追加することでメインクエリを停止できます。これでも1つのdbクエリが発生する可能性がありますが、確実にメインのクエリが投稿をクエリするのを阻止します。

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

残念ながら、私は何もテストする時間がありません、しかしこれはいい出発点であるべきです

2
Pieter Goosen

参考までに、前: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 );
2
Tom J Nowell