query_posts()
满足了所有查询需求。现在,我对使用WP_Query()
更为明智,但仍然有一些灰色区域。 我想我肯定知道的内容:
如果我要在页面上的任何地方(在侧边栏中,在页脚中)进行任何其他循环,则需要进行各种“相关帖子” ”等-我想使用
WP_Query()
。我可以在单个页面上重复使用它而不会造成任何伤害。 (对?)。 我不确定的是什么
何时使用@nacin的
pre_get_posts
和WP_Query()
?我现在应该使用pre_get_posts
吗? 当我想修改模板页面中的循环时(假设我要修改分类档案页面),是否要删除
if have_posts : while have_posts : the_post
部分并编写自己的WP_Query()
?还是在我的functions.php文件中使用pre_get_posts
修改输出? tl; dr
我想从中得出的tl; dr规则是:
不再使用
query_posts
在单个页面上运行多个查询时,请使用
WP_Query()
修改循环时,请执行__________________。
感谢任何智慧
特里
ps:我已经看过并读过:什么时候应该使用WP_Query vs query_posts()vs get_posts() ?这增加了另一个维度-
get_posts
。但根本不处理pre_get_posts
。 #1 楼
您说对了:不再使用
query_posts
pre_get_posts
pre_get_posts
是过滤器,用于更改任何查询。它最常用于仅更改“主查询”: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
。即,如果您想使用query_posts()
,请改用pre_get_posts
。WP_Query
主查询是
WP_Query object
的重要实例。 WordPress使用它来决定要使用的模板,例如,传递给url的任何参数(例如,分页)都将传递到WP_Query
对象的该实例中。用于辅助循环(例如,在侧面) -bars或“相关帖子”列表),则需要创建自己的
WP_Query
对象的单独实例。例如。 $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_posts()
这实际上是
WP_Query
对象的单独实例的包装。这将返回一个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
。 评论
那么,有什么方案可以直接使用get_posts()而不是WP_Query吗?
–urok93
2012年8月25日16:09
@drtanz-是的。举例来说,您不需要分页,也不需要顶部的粘性帖子-在这种情况下,get_posts()效率更高。
–斯蒂芬·哈里斯(Stephen Harris)
2012年8月25日18:00
但是,这不会在我们可以修改pre_get_posts来修改主查询的地方添加额外的查询吗?
–urok93
2012年8月26日在20:54
@drtanz-您不会在主查询中使用get_posts()-在辅助查询中使用它。
–斯蒂芬·哈里斯(Stephen Harris)
2012年8月26日在22:42
@StephenHarris Right =)如果在对象上使用next_post()而不是使用the_post,则无需执行全局查询,也不必记住以后要使用wp_reset_postdata。
–私有
15年9月19日在18:01
#2 楼
循环有两种不同的上下文:基于URL请求发生的主循环,并在加载模板之前进行处理。
以任何其他方式发生,从模板文件调用,否则以其他方式调用
query_posts()
的问题是,它是试图成为主要循环并且失败惨重的次要循环。这样就忘记了它的存在。修改主循环
不要使用
query_posts()
使用带有
pre_get_posts
检查的$query->is_main_query()
过滤器或者使用
request
过滤器(有点粗糙,所以上面的效果更好)运行次级循环
使用可以互换的
new WP_Query
或get_posts()
(后者是薄包装纸) 要清理
,如果您使用
wp_reset_query()
或直接与全局query_posts()
混淆,请使用$wp_query
-这样您几乎就不需要了。如果使用
wp_reset_postdata()
或the_post()
或与全局setup_postdata()
混淆,并且需要恢复与帖子相关的事物的初始状态,请使用$post
。评论
Rarst的意思是wp_reset_postdata()
–格雷戈里
2012年6月1日上午9:18
#3 楼
有使用query_posts($query)
的合法方案,例如:要在页面上显示帖子列表或自定义帖子类型的帖子(使用页面模板)
您想对这些帖子进行分页
现在为什么要在页面上显示它而不使用存档模板?
更多对于管理员(您的客户?)很直观-他们可以在“页面”中看到该页面
最好将其添加到菜单中(没有页面,他们必须直接添加url)
如果您想在模板上显示其他内容(文本,缩略图或任何自定义元内容),则可以轻松地从页面上获取它(这对客户来说也更有意义)。看看是否使用了存档模板,您是否需要对其他内容进行硬编码或使用例如主题/插件选项(这会使客户不那么直观)
这是一个简化的示例代码(这将在您的页面模板上-例如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...
}
现在,非常清楚,我们可以避免在这里也使用
query_posts()
,而改用WP_Query
-像这样:什么时候有这么好的功能可用?评论
布莱恩,谢谢你。我一直在努力使pre_get_posts在您所描述的场景中的页面上正常工作:客户端需要将自定义字段/内容添加到原本为存档的页面中,因此需要创建“页面”;客户需要查看一些要添加到导航菜单的内容,因为添加自定义链接会使它们转义;等我+1!
–拉尼(Will Lanni)
2012年12月13日上午11:07
也可以使用“ pre_get_posts”来完成。我这样做是为了让“静态首页”以自定义顺序和自定义过滤器列出我的自定义帖子类型。此页面也是分页的。看看这个问题,看看它是如何工作的:wordpress.stackexchange.com/questions/30851/…因此,简而言之,仍然没有更多使用query_posts的合法方案了;)
– 2ndkauboy
2015年1月12日14:47
因为“应该注意,用它代替页面上的主查询会增加页面加载时间,在最坏的情况下,所需的工作量增加一倍以上或更多。虽然易于使用,但该功能也容易造成混乱和以后的问题。”源代码x.wordpress.org/Function_Reference/query_posts
– Claudiu Creanga
15年3月9日在16:31
答案是各种各样的错误。您可以在WP中使用与自定义帖子类型相同的URL创建一个“页面”。例如,如果您的CPT是Bananas,则可以获得具有相同URL的名为Bananas的页面。然后,您将获得siteurl.com/bananas。只要您的主题文件夹中有archive-bananas.php,它就会使用模板并“覆盖”该页面。如其他评论之一所述,使用此“方法”会为WP造成两倍的工作负载,因此永远不要使用。
–混合Web开发
15年6月19日在20:07
#4 楼
我从functions.php修改WordPress查询://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%')";
}
评论
希望看到此示例,但where子句位于自定义元上。
–安德鲁·韦尔奇(Andrew Welch)
17 Mar 3 '17 at 16:20
#5 楼
只是为了概述自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();
}
get_posts()
这实际上是一个单独包装器WP_Query对象的实例。
实际上,如今
WP_Query
是一个类,因此我们有一个类的实例。 总结:当时@StephenHarris编写的所有内容很可能都是真实的,但是随着时间的流逝,WordPress中的情况已经发生了变化。
评论
从技术上讲,这是所有过滤器,操作只是一个简单的过滤器。但是您在这里是对的,它是通过引用传递参数的操作,这与更简单的操作有所不同。
–米洛
16 Dec 28'在2:16
get_posts返回一个post对象数组,而不是WP_Query对象,因此这仍然是正确的。并且WP_Query一直是一个类,一个类=对象的实例。
–米洛
16 Dec 28'在2:16
谢谢@Milo,由于某种原因我的脑子里简化了模型,这是正确的。
–prosti
16年12月28日在8:51
评论
何时应该使用WP_Query与query_posts()与get_posts()的可能重复项?@saltcod,现在有所不同,WordPress不断发展,与此处接受的答案相比,我添加了一些评论。