当前位置: 首页>>网站问题>>正文


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

webfans 网站问题 , , , 去评论

问题描述

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

是否有某种参数可以传递给WP_Query,如'force_no_results' => true,它会强制它返回没有结果?

最佳解决思路

尝试

'post__in' => array(0)

简单而重要。

次佳解决思路

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

如果它是主要查询你可能在WP->parse_request()周围工作,那里似乎有相对较新的(3.5)do_parse_request过滤器。

但是对于WP_Query本身的脏黑客通常是有序的,比如通过posts_where过滤器等添加AND 1=0的short-circuiting SQL查询等。

第三种解决思路

将查询参数设置为不存在的值的问题是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. 在确定过滤器被触发之后,adda过滤器返回这种请求:SELECT ID FROM wp_posts WHERE 0 = 1一旦删除了所有过滤器,就不可能更改此查询并且它非常快,并且没有确定结果

  3. 在运行此查询后,立即恢复所有原始过滤器(如果有的话),并且所有后续查询都将按预期工作。

参考资料

本文由朵颐IT整理自网络, 文章地址: https://duoyit.com/article/3029.html,转载请务必附带本地址声明。