问题描述

我有以下查询,我通过 query_brands_geo('dealers', 'publish', '1', $taxtype, $geo, $brands); 在我的 taxonomy.php 模板中调用

这个功能很完美。但是,在阅读 codex 查询帖子后,它提到了 pre_get_posts 作为更改默认查询的首选方法。 pre_get_posts 会更有效,那么下面我的 wp_query 功能呢?

如果是,我如何构建 pre_get_posts 并在下面传递我的变量和查询?

function my_custom_query($posttype, $poststatus, $paidvalue, $taxtype, $geo, $brands) {
   global $wp_query;
   $wp_query = new WP_Query();
   $args = array(
      'post_type' => $posttype,
      'post_status' => array($poststatus),
      'orderby' => 'rand',
      'posts_per_page' => 30,
      'meta_query' => array(
         array(
            'key' => 'wpcf-paid',
            'value' => array($paidvalue),
            'compare' => 'IN',
            )
      ),
      'tax_query' => array(
         'relation' => 'AND',
         array(
            'taxonomy' => $taxtype,
            'field' => 'slug',
            'terms' => $geo
         ),
         array(
            'taxonomy' => 'brands',
            'field' => 'slug',
            'terms' => $brands
         )
      )
   );

   return $wp_query->query($args);
}

最佳解决方案

 pre_get_posts 将运行相同的查询,因此两者都需要相同的时间。但是,如果您使用 pre_get_posts 操作,您将保存一个或多个 SQL 查询。现在,WordPress 正在运行默认查询,然后使用此函数运行查询,替换默认查询的结果 (结果,默认查询是没有用的) 。以下是如何将 $args 移动到

function custom_pre_get_posts($query, $posttype='dealers', $poststatus='publish', $paidvalue='1', $taxtype='any_default_value', $geo='any_default_value', $brands='any_default_value') {

    // filter your request here.
    if($query->is_category) {

        $args = array(
            'post_type' => $posttype,
            'post_status' => array($poststatus),
            'orderby' => 'rand',
            'posts_per_page' => 30,
            'meta_query' => array(
                array(
                    'key' => 'wpcf-paid',
                    'value' => array($paidvalue),
                    'compare' => 'IN',
                )
            ),
            'tax_query' => array(
                'relation' => 'AND',
                array(
                    'taxonomy' => $taxtype,
                    'field' => 'slug',
                    'terms' => $geo
                ),
                array(
                    'taxonomy' => 'brands',
                    'field' => 'slug',
                    'terms' => $brands
                )
            )
        );
        $query->query_vars = $args;
    }
}
add_action('pre_get_posts', 'custom_pre_get_posts');

次佳解决方案

迟到的答案是最受欢迎的答案将会打破您的查询,在某些要点上根本不是真的。

主要的 WP_Query 和它的过滤器

首先,WordPress 内部使用 query_posts()(WP_Query 周围的薄包装,不应该在主题或插件中使用) 来做 WP_Query 。该 WP_Query 作为主循环/查询。此查询将运行大量的过滤器和操作,直到构建实际的 SQL 查询字符串。其中之一是 pre_get_posts 。其他都是 posts_clausesposts_where 等,也允许你拦截查询字符串构建过程。

深入了解核心内部发生的情况

WordPress runs the wp() function (in wp-includes/functions.php), which calls $wp->main() ($wp is an object of class WP, which is defined in wp-includes/class-wp.php). This tells WordPress to:

  1. Parse the URL into a query specification using WP->parse_request() — more on that below.
  2. Set all the is_ variables that are used by Conditional Tags using $wp_query->parse_query() ($wp_query is an object of class WP_Query, which is defined in wp-includes/query.php). Note that in spite of this function’s name, in this case WP_Query->parse_query doesn’t actually do any parsing for us, since that is done before-hand by WP->parse_request().
  3. Convert the query specification into a MySQL database query, and run the database query to get the list of posts, in function WP_Query->get_posts(). Save the posts in the $wp_query object to be used in the WordPress Loop.

Source Codex

Conclusion

如果您真的要修改主查询,那么可以使用各种过滤器。只需使用 $query->set( 'some_key', 'some_value' ); 来更改数据,或者使用 $query->get( 'some_key' ); 检索数据进行条件检查。这样就可以避免您进行第二次查询,因为您仅更改 SQL 查询。

如果您需要执行其他查询,那么请使用 WP_Query 对象。这将向 DB 添加另一个查询。

例子

因为答案总是以一个例子更好地工作,你在这里得到一个非常好的 (道具到 Brad Touesnard),它只是扩展核心对象,因此是非常可重用的 (使一个插件):

class My_Book_Query extends WP_Query
{
    function __construct( $args = array() )
    {
        // Forced/default args
        $args = array_merge( $args, array(
            'posts_per_page' => -1
        ) );

        add_filter( 'posts_fields', array( $this, 'posts_fields' ) );

        parent::__construct( $args );
    }

    public function posts_fields( $sql )
    {
        return "{$sql}, {$GLOBALS['wpdb']->terms}.name AS 'book_category'";
    }
}

然后,您可以运行您的第二个/其他查询,如下例所示。不要忘了重置您的查询。

$book_query = new My_Book_Query();
if ( $book_query->have_posts() )
{
    while ( $book_query->have_posts() )
    {
        $book_query->the_post();
        # ...do stuff...
    } // endwhile;
    wp_reset_postdata();
} // endif;

第三种解决方案

请查看 When to use WP_query(), query_posts() and pre_get_posts 的答案。

如果您有任何疑问,这是一个很好的资源。

参考文献

注:本文内容整合自 Google/Baidu/Bing 辅助翻译的英文资料结果。如果您对结果不满意,可以加入我们改善翻译效果:薇晓朵技术论坛。