我应该使用Pre Get Posts还是WP_Query


29

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

此功能运行完美。但是,在阅读了用于查询帖子的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); 
} 

Answers:


14

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

非常感谢你的答复。这是非常有帮助的。一个简单的问题。我将函数放在主题function.php文件中。我从我的taxonomy.php运行此函数custom_pre_get_posts($ query)。在taxonomy.php中,我设置了变量$ posttype,$ post_status,$ geo,$ brands,$ taxtype,并运行了两个循环来更改这些变量。有没有办法将变量从taxonomy.php传递到上述函数中?当我尝试custom_pre_get_posts($ query,'dealers','publish','1',$ taxtype,$ geo,$ brands); 对于custom_pre_get_posts(),我得到了缺少的参数2到7。我假设由于add_action ???
user1609391 2012年

1
我假设您已将custom_pre_get_posts更改为接受其余参数。是的,由于add_action导致出现错误。add_action使用单个参数(即$ query)调用此函数,您应该为其他参数提供默认值,以避免遗漏参数错误。像($ posttype = null,$ poststatus = null ...)这样可以通过add_action正确调用。
MR

先生,谢谢您的答复。我阅读了添加操作,发现应该分配一个优先级和参数编号。所以我将添加动作更改为<code> add_action('pre_get_posts','custom_pre_get_posts',10,7); </ code>然后在我的taxonomy.php页面中,我<code> do_action('pre_get_post',$ query,'经销商”,“发布”,“ 1”,$ taxtype,$ geo,$ brands); </ code>。但是我仍然遇到同样的错误。我不确定在哪里放置默认值。我尝试了google,但找不到参考。您能给我更多有关如何处理此问题的信息吗?
user1609391 2012年

感谢您的答复和示例。但是我想我应该在做一个新的wordpress查询时尝试使用pre_get_posts。我试图保存查询,但就我而言,这可能是不可能的。原因是您在参数中设置的所有参数,我想从我的taxonomy.php文件传递给函数。因此,取决于我在taxonomy.php中执行的条件,$ paidvalue =“ 1”可能是1或0。即使页面未加载,似乎pre_get_posts也会正确触发,即使我未在taxonomy.php文件中调用该函数也是如此。我看到这个正确吗?
user1609391 2012年

3
该答案目前尚无意义。您将有效地覆盖$wp_query对象内部的任何值,并且事情将完全失败。除此之外,它的根本不是真的pre_get_posts将运行一个额外的查询...
凯泽

10

迟来的答案是最受好评的答案,这会打断您的查询,在某些要点上根本不正确。

WP_Query和它的过滤器

首先,WordPress内部使用query_posts()(主题或插件WP_Query不应使用的薄包装纸)来做WP_Query。这WP_Query充当主循环/查询。该查询将通过许多过滤器和操作运行,直到构建实际的SQL查询字符串为止。其中之一是pre_get_posts。其他是posts_clausesposts_where等,它们允许您拦截查询字符串的构建过程。

深入研究核心内部发生的情况

WordPress运行wp()(中的wp-includes/functions.php)函数,该函数调用$wp->main()$wp是WP类的对象,该类在中定义wp-includes/class-wp.php)。这告诉WordPress:

  1. 使用WP->parse_request()-在下面的更多内容将URL解析为查询规范。
  2. 使用$wp_query->parse_query()$wp_query是的对象class WP_Query,在中定义wp-includes/query.php)设置条件标签使用的所有is_变量。请注意,尽管使用了该函数的名称,但在这种情况下WP_Query->parse_query实际上并不会为我们进行任何解析,因为这是由预先完成的WP->parse_request()
  3. 将查询规范转换为MySQL数据库查询,然后运行数据库查询以在函数WP_Query-> get_posts()中获取帖子列表。将帖子保存在$ wp_query对象中以在WordPress循环中使用。

来源食品

结论

如果您确实要修改主查询,则可以使用各种过滤器。只需使用$query->set( 'some_key', 'some_value' );的变化有数据或使用$query->get( 'some_key' );获取数据做条件检查。这将使您免于进行第二次查询,因为您仅更改了SQL查询。

如果您必须执行其他查询,请选择一个WP_Query对象。这将向数据库添加另一个查询。

由于答案总是很好地配合一个示例,因此您在这里得到了一个非常不错的示例(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'";
    }
}

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

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

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.