何时使用WP_QUERY()、QUERY_POST()和PRE_GET_POST

时间:2012-05-01 作者:saltcod

我读过@nacin\'s You don\'t know Query 昨天,他被送到了一个有点可疑的兔子洞里。昨天之前,我(错误地)使用query_posts() 满足我所有的查询需求。现在我对使用WP_Query(), 但仍有一些灰色区域。

What I think I know for sure:

如果我在侧边栏、页脚、任何类型的“相关帖子”等页面上的任何位置进行附加循环,我想使用WP_Query(). 我可以在一页纸上重复使用,不会有任何伤害。(对吗?)。

What I don\'t know for sure

<我什么时候使用@nacin\'s pre_get_posts vs。WP_Query()? 我应该使用pre_get_posts 现在的一切当我想修改模板页面中的循环时-假设我想修改分类法归档页面-我是否删除if have_posts : while have_posts : the_post 分开写我自己的WP_Query()? 还是使用pre_get_posts 在我的功能中。php文件

tl;dr

tl;我想从中得出的dr规则是:

切勿使用query_posts 当在一个页面上运行多个查询时,请使用WP_Query()

特里

附言:我看到并阅读了:When should you use WP_Query vs query_posts() vs get_posts()? 增加了另一个维度-get_posts. 但不处理pre_get_posts 完全

5 个回复
最合适的回答,由SO网友:Stephen Harris 整理而成

你说得对:

从不使用query_posts 不再

pre\\u get\\u帖子

pre_get_posts 是一个过滤器,用于改变any 查询它通常仅用于更改“主查询”:

add_action(\'pre_get_posts\',\'wpse50761_alter_query\');
function wpse50761_alter_query($query){

      if( $query->is_main_query() ){
        //Do something to main query
      }
}
(我还要检查一下is_admin() 返回false(尽管这可能是多余的)。主查询在模板中显示为:

if( have_posts() ):
    while( have_posts() ): the_post();
       //The loop
    endwhile;
endif;
如果您觉得有必要编辑此循环-请使用pre_get_posts. i、 e.如果您想使用query_posts() - 使用pre_get_posts 相反

WP\\u Query

主查询是WP_Query object. WordPress使用它来决定使用哪个模板,例如,传递到url的任何参数(例如分页)都被传递到WP_Query 对象

对于次循环(例如,在侧栏或“相关帖子”列表中),您需要创建自己的WP_Query 对象E、 g。

$my_secondary_loop = new WP_Query(...);
if( $my_secondary_loop->have_posts() ):
    while( $my_secondary_loop->have_posts() ): $my_secondary_loop->the_post();
       //The secondary loop
    endwhile;
endif;
wp_reset_postdata();
注意事项wp_reset_postdata(); - 这是因为辅助循环将覆盖全局$post 标识“当前职位”的变量。这实际上会将其重置为$post 我们开始了。

get\\u posts()

这实际上是WP_Query 对象这将返回post对象的数组。上面循环中使用的方法对您不再可用。这不是“循环”,只是post对象的数组。

<ul>
<?php
global $post;
$args = array( \'numberposts\' => 5, \'offset\'=> 1, \'category\' => 1 );
$myposts = get_posts( $args );
foreach( $myposts as $post ) :  setup_postdata($post); ?>
    <li><a href="<?php the_permalink(); ?>"><?php the_title(); ?></a></li>
<?php endforeach; wp_reset_postdata(); ?>
</ul>
回答您的问题时,请使用pre_get_posts 更改主查询。使用单独的WP_Query 对象(方法2),用于模板页中的二次循环pre_get_posts.

SO网友:Rarst

循环有两种不同的上下文:

  • main 基于URL请求发生的循环,在加载模板之前进行处理secondary 以任何其他方式发生的循环,从模板文件调用或以其他方式调用query_posts() 就是二次回路试图成为主回路,却惨遭失败。因此,忘记它的存在。

    要修改主回路,请不要使用query_posts()

  • 使用pre_get_posts 使用筛选$query->is_main_query() 检查交替使用request 过滤器(有点太粗糙,所以上面更好)要运行二次回路,请使用new WP_Queryget_posts() 它们几乎可以互换(后者是前者的薄包装)。

    要清理,请使用wp_reset_query() 如果您使用query_posts() 或与global发生冲突$wp_query 直接-因此您几乎不需要这样做。

    使用wp_reset_postdata() 如果您使用the_post()setup_postdata() 或与global发生冲突$post 并且需要恢复与post相关的事物的初始状态。

SO网友:Lukas Pecinka

There are legitimate scenarios for using query_posts($query), for example:

  1. You want to display a list of posts or custom-post-type posts on a page (using a page template)

  2. You want to make pagination of those posts work

Now why would you want to display it on a page instead of using an archive template?

  1. It\'s more intuitive for an administrator (your customer?) - they can see the page in the \'Pages\'

  2. It\'s better for adding it to menus (without the page, they\'d have to add the url directly)

  3. If you want to display additional content (text, post thumbnail, or any custom meta content) on the template, you can easily get it from the page (and it all makes more sense for the customer too). See if you used an archive template, you\'d either need to hardcode the additional content or use for example theme/plugin options (which makes it less intuitive for the customer)

Here\'s a simplified example code (which would be on your page template - e.g. page-page-of-posts.php):

/**
 * Template Name: Page of Posts
 */

while(have_posts()) { // original main loop - page content
  the_post();
  the_title(); // title of the page
  the_content(); // content of the page
  // etc...
}

// now we display list of our custom-post-type posts

// first obtain pagination parametres
$paged = 1;
if(get_query_var(\'paged\')) {
  $paged = get_query_var(\'paged\');
} elseif(get_query_var(\'page\')) {
  $paged = get_query_var(\'page\');
}

// query posts and replace the main query (page) with this one (so the pagination works)
query_posts(array(\'post_type\' => \'my_post_type\', \'post_status\' => \'publish\', \'paged\' => $paged));

// pagination
next_posts_link();
previous_posts_link();

// loop
while(have_posts()) {
  the_post();
  the_title(); // your custom-post-type post\'s title
  the_content(); // // your custom-post-type post\'s content
}

wp_reset_query(); // sets the main query (global $wp_query) to the original page query (it obtains it from global $wp_the_query variable) and resets the post data

// So, now we can display the page-related content again (if we wish so)
while(have_posts()) { // original main loop - page content
  the_post();
  the_title(); // title of the page
  the_content(); // content of the page
  // etc...
}

Now, to be perfectly clear, we could avoid using query_posts() here too and use WP_Query instead - like so:

// ...

global $wp_query;
$wp_query = new WP_Query(array(\'your query vars here\')); // sets the new custom query as a main query

// your custom-post-type loop here

wp_reset_query();

// ...

But, why would we do that when we have such a nice little function available for it?

SO网友:T.Todua

我从函数中修改WordPress查询。php:

//unfortunately, "IS_PAGE" condition doesn\'t work in pre_get_posts (it\'s WORDPRESS behaviour)
//so you can use `add_filter(\'posts_where\', ....);`    OR   modify  "PAGE" query directly into template file

add_action( \'pre_get_posts\', \'myFunction\' );
function myFunction($query) {
    if ( ! is_admin() && $query->is_main_query() )  {
        if (  $query->is_category ) {
            $query->set( \'post_type\', array( \'post\', \'page\', \'my_postType\' ) );
            add_filter( \'posts_where\' , \'MyFilterFunction_1\' ) && $GLOBALS[\'call_ok\']=1; 
        }
    }
}
function MyFilterFunction_1($where) {
   return (empty($GLOBALS[\'call_ok\']) || !($GLOBALS[\'call_ok\']=false)  ? $where :  $where . " AND ({$GLOBALS[\'wpdb\']->posts}.post_name NOT LIKE \'Journal%\')"; 
}

SO网友:prosti

仅概述自WordPress随着时间的推移而发展以来,对公认答案的一些改进,现在有些事情有所不同(五年后):

pre_get_posts 是一个过滤器,用于更改任何查询。它通常仅用于更改“主查询”:

实际上是一个动作钩。不是筛选器,它将影响任何查询。

主查询在模板中显示为:

if( have_posts() ):
    while( have_posts() ): the_post();
       //The loop
    endwhile;
endif;
其实,这也不是真的。功能have_posts 迭代global $wp_query 与主查询不相关的对象。global $wp_query; 也可以使用辅助查询进行更改。

function have_posts() {
    global $wp_query;
    return $wp_query->have_posts();
}
这本质上是WP\\U查询对象的一个单独实例的包装。

事实上,现在WP_Query 是一个类,因此我们有一个类的实例。

<小时>

To conclude: At the time @StephenHarris wrote most likely all this was true, but over the time things in WordPress have been changed.

结束

相关推荐

使用新的WP-Query()从循环中过滤后期格式;

嗨,我目前正在为我的博客构建一个主题。下面的代码指向最新的帖子(特色帖子)。因为这将有一个不同的风格比所有其他职位。然而我想过滤掉帖子格式:链接使用我在循环中定义的WP查询,因为它给我带来了更多的灵活性。我该怎么做呢? <?php $featured = new WP_Query(); $featured->query(\'showposts=1\'); ?> <?php while ($featured->have_post