WP_Queryに結果を返さないように強制できますか?


23

私は、ユーザーが多くの投稿メタを検索できる検索機能を備えたWebサイトで作業しています。強制的に結果を返さない特定の検索パターンがあります。WP_Queryは技術的にはデータベースで結果を見つけますが、それを何らかの方法でオーバーライドして、結果を返さないようにして強制的if( $example->have_posts() )に失敗させたいと思います。

'force_no_results' => true結果を返さないように強制するような、WP_Queryに渡すことができるパラメーターの種類はありますか?


1
ITは、根本的な問題を解決する方法を尋ねるのではなく、既に決まっている実装を求めているようです。行間を読んで、あなたが本当に求めているべきことは次のとおりだと思います:特定の検索パターンをクエリ不可能にする方法は?。原因WP_Query()は結果を返さないようにすることや、その質問に答えるための最良の方法であってもなくてもよいです。また、クエリ不可能にしたい検索パターン記述する場合にも役立ちます。検索パターンを知ることは、解決策を見つけるのに役立つかもしれません。
チップベネット14

回答:


28

試してみる

'post__in' => array(0)

シンプルで要点。


私が最初に考えたのは、これはどこか間違っていることですが、関連するコードをスキミングすることで、実際にはかなりうまくいくはずです。:)
Rarst

5
空の配列だけが最近の投稿を返すため、ゼロは非常に重要です。
マーク・Kaplun

ありがとう!これpost__inは、空の配列を渡されたときに投稿を返すというバグを解決しました... array(0)素晴らしい作品です!これは奇妙ですが、WPコアでバグとして出てきた問題にたどり着くことができますが、テーマ/プラグインの開発者が多すぎてその周辺に機能を構築したため、そのまま残されました-_- core.trac.wordpress.org/チケット/ 28099
EranSch

3

奇妙なことに、短絡するクリーン/明示的な方法はありませんWP_Query

それが主なクエリである場合WP->parse_request()、何かを解決するかもしれませんが、そこには比較的最近の(3.5)do_parse_requestフィルタがあるようです。

ただし、フィルタWP_QueryAND 1=0介して追加することでSQLクエリを短絡させるなど、ダーティハック自体が通常は適切ですposts_where


2
情報をありがとう。それは二次ループでした。そして、私はちょうど"post_type" => "break_loop"、存在しない投稿タイプであるような汚いハックをすることになりました。
ブライアン14

2

クエリパラメータを存在しない値に設定する場合の問題は2です。

  • クエリが実行されるため、結果が得られないことが既にわかっている場合でも、支払うべきパフォーマンスの価格はわずかです。
  • WordPressクエリには19種類の'posts_*'フィルターフック('posts_where''post_join'など)があり、それらがクエリに作用するため、クエリに存在しないパラメーターを設定しても結果が返されないこと、ORフィルターによって返される単純な句が何かを返すことを確認することはできません。

クエリが結果を返さず、パフォーマンスの問題がない(または非常に少ない)ことを確認するには、少し筋金入りのルーチンが必要です。

そのルーチンをトリガーするには、すべてのメソッドを使用できます。技術的にWP_Queryは、存在しないイベント引数に引数を渡すことができます。

のようなものが好きなら、次のように'force_no_results' => true使うことができます:

$a = new WP_Query( array( 's' => 'foo', 'force_no_results' => true ) );

そして'pre_get_posts'、ハードワークを実行するコールバックを追加します:

add_action( 'pre_get_posts', function( $q ) {
  if (array_key_exists('force_no_results', $q->query) && $q->query['force_no_results']) {
    $q->query = $q->query_vars = array();
    $added = array();
    $filters = array(
      'where', 'where_paged', 'join', 'join_paged', 'groupby', 'orderby', 'distinct',
      'limits', 'fields', 'request', 'clauses', 'where_request', 'groupby_request',
      'join_request', 'orderby_request', 'distinct_request','fields_request',
      'limits_request', 'clauses_request'
    );
    // remove all possible interfering filter and save for later restore
    foreach ( $filters as $f ) {
      if ( isset($GLOBALS['wp_filter']["posts_{$f}"]) ) {
        $added["posts_{$f}"] = $GLOBALS['wp_filter']["posts_{$f}"];
        unset($GLOBALS['wp_filter']["posts_{$f}"]);
      }
    }
    // be sure filters are not suppressed
    $q->set( 'suppress_filters', FALSE );
    $done = 0;
    // use a filter to return a non-sense request
    add_filter('posts_request', function( $r ) use( &$done ) {
      if ( $done === 0 ) { $done = 1;
        $r = "SELECT ID FROM {$GLOBALS['wpdb']->posts} WHERE 0 = 1";
      }
      return $r;
    });
    // restore any filter that was added and we removed
    add_filter('posts_results', function( $posts ) use( &$done, $added ) {
      if ( $done === 1 ) { $done = 2;
        foreach ( $added as $hook => $filters ) {
          $GLOBALS['wp_filter'][$hook] = $filters;
        }
      }
      return $posts;
    });
  }
}, PHP_INT_MAX );

このコードは'pre_get_posts'、できるだけ遅く実行されます。引数 'force_no_results'がクエリに存在する場合:

  1. 最初にクエリに干渉する可能性のあるすべてのフィルターを削除し、ヘルパー配列内に保存します
  2. フィルターがトリガーされたことを確認した後、この種の要求を返すフィルターを追加します。SELECT ID FROM wp_posts WHERE 0 = 1すべてのフィルターが削除されると、このクエリが変更される可能性はなく、クエリは非常に高速で、確実な結果はありません
  3. このクエリが実行された直後に、元のフィルター(存在する場合)がすべて復元され、その後のすべてのフィルターが期待どおりに機能します。
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.