我可以强制WP_Query不返回任何结果吗?


23

我正在使用一个具有搜索功能的网站,该功能允许用户搜索大量帖子元。有一种特定的搜索模式,我想强制不返回任何结果。从技术上讲WP_Query会在数据库中找到结果,但是我想以某种方式覆盖它,以强制它不返回任何结果以触发if( $example->have_posts() )失败。

我可以将某种参数传递给WP_Query,那样'force_no_results' => true会迫使它不返回任何结果?


1
IT似乎是在要求已经确定的实现,而不是在问如何解决根本问题。阅读这句话,我认为您真正应该问的是:如何使特定的搜索模式不可查询?。导致WP_Query()不返回结果可能是也可能不是回答该问题的最佳方法。如果您要描述想要不可查询的搜索模式,这也可能会有所帮助。了解搜索模式可能有助于找出解决方案。
Chip Bennett 2014年

Answers:


28

尝试

'post__in' => array(0)

简单明了。


我的第一个想法是–一定在某个地方出错,但是从略读相关代码后,这实际上应该可以很好地工作。:)
Rarst

5
零非常重要,因为只有一个空数组会返回最近的帖子。
马克·卡普伦

谢谢!这为我解决了一个错误,因为post__in传递一个空数组时返回帖子…… array(0)效果很好!这很奇怪,但实际上可以追溯到WP核心中作为一个错误出现的问题,但后来被保留下来,因为有太多主题/插件开发人员围绕它构建了功能-_- core.trac.wordpress.org/票证/ 28099
EranSch '17

3

奇怪的是,没有干净/明确的短路方法WP_Query

如果是主要查询,则可能需要解决一些问题WP->parse_request(),那里似乎是相对较新的(3.5)do_parse_request过滤器。

但是对于它们WP_Query自己来说,通常是有序的骇客,例如AND 1=0通过通过posts_where过滤器添加来使SQL查询短路等。


2
谢谢(你的)信息。顺便说一句,这是一个次要循环。而且我最后还是做了一个肮脏的骇客,就像"post_type" => "break_loop"那是一种不存在的帖子类型。
布莱恩

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. 此查询运行后,将立即还原所有原始过滤器(如果有),并且所有后续查询将按预期运行。
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.