问题描述
我已经将自定义/辅助查询添加到模板文件/自定义页面模板中; 如何使 WordPress 使用我的自定义查询进行分页,而不是使用主查询循环的分页?
Addendum
我已经通过 query_posts()
修改了主循环查询。为什么不分页工作,怎么解决?
最佳解决方案
问题
默认情况下,在任何给定的上下文中,WordPress 使用主查询来确定分页。主查询对象存储在 $wp_query
全局中,也用于输出主查询循环:
if ( have_posts() ) : while ( have_posts() ) : the_post();
当您使用 use a custom query 时,您将创建一个完全独立的查询对象:
$custom_query = new WP_Query( $custom_query_args );
该查询通过一个完全独立的循环输出:
if ( $custom_query->have_posts() ) :
while ( $custom_query->have_posts() ) :
$custom_query->the_post();
但分页模板标签,包括 previous_posts_link()
,next_posts_link()
,posts_nav_link()
和 paginate_links()
,它们的输出基于主查询对象 $wp_query
。该主要查询可能是也可能不会被分页。如果当前上下文是自定义页面模板,例如,主 $wp_query
对象将仅包含单个帖子 – 分配了自定义页面模板的页面的 ID 。
如果当前上下文是某种归档索引,则主 $wp_query
可能包含足够的帖子导致分页,导致下一部分问题:对于主 $wp_query
对象,WordPress 会将 paged
参数传递给查询,基于 paged
URL 查询变量。获取查询后,将使用该 paged
参数来确定要返回哪一组分页的帖子。如果单击显示的分页链接,并且下一页加载,您的自定义查询将无法知道分页已更改。
解决方案
将正确的分页参数传递给自定义查询
假设自定义查询使用 args 数组:
$custom_query_args = array(
// Custom query parameters go here
);
您将需要将正确的 paged
参数传递给阵列。您可以通过获取用于确定当前页面的 URL 查询变量,通过 get_query_var()
:
get_query_var( 'paged' );
然后,您可以将该参数附加到自定义查询 args 数组中:
$custom_query_args['paged'] = get_query_var( 'paged' )
? get_query_var( 'paged' )
: 1;
注意:如果您的页面是静态首页,请确保使用 page
代替 paged
作为静态首页使用 page
而不是 paged
。这是您应该拥有的静态首页
$custom_query_args['paged'] = get_query_var( 'page' )
? get_query_var( 'page' )
: 1;
现在,当提取自定义查询时,将返回正确的一组分页帖子。
使用自定义查询对象进行分页功能
为了使分页函数产生正确的输出 – 即相对于自定义查询的上一页/下一页/页面链接 – 需要强制 WordPress 识别自定义查询。这需要一点”hack”:使用自定义查询对象 $custom_query
替换主 $wp_query
对象:
破解主查询对象
- 备份主查询对象:
$temp_query = $wp_query
- 空的主查询对象:
$wp_query = NULL;
-
将自定义查询交换到主查询对象:
$wp_query = $custom_query;
$temp_query = $wp_query; $wp_query = NULL; $wp_query = $custom_query;
必须在调用任何分页功能之前完成此”hack”
重置主查询对象
分页功能输出后,重新设置主查询对象:
$wp_query = NULL;
$wp_query = $temp_query;
分页功能修复
无论分页如何,previous_posts_link()
功能都能正常工作。它只是确定当前页面,然后输出 page - 1
的链接。但是,需要修复 next_posts_link()
才能正确输出。这是因为 next_posts_link()
使用 max_num_pages
参数:
<?php next_posts_link( $label , $max_pages ); ?>
与其他查询参数一样,默认情况下,该函数将使用 max_num_pages
作为主 $wp_query
对象。为了强制 next_posts_link()
考虑 $custom_query
对象,您需要将 max_num_pages
传递给该功能。您可以从 $custom_query
对象获取此值:$custom_query->max_num_pages
:
<?php next_posts_link( 'Older Posts' , $custom_query->max_num_pages ); ?>
把它们放在一起
以下是具有正确功能的分页功能的自定义查询循环的基本构造:
// Define custom query parameters
$custom_query_args = array( /* Parameters go here */ );
// Get current page and append to custom query parameters array
$custom_query_args['paged'] = get_query_var( 'paged' ) ? get_query_var( 'paged' ) : 1;
// Instantiate custom query
$custom_query = new WP_Query( $custom_query_args );
// Pagination fix
$temp_query = $wp_query;
$wp_query = NULL;
$wp_query = $custom_query;
// Output custom query loop
if ( $custom_query->have_posts() ) :
while ( $custom_query->have_posts() ) :
$custom_query->the_post();
// Loop output goes here
endwhile;
endif;
// Reset postdata
wp_reset_postdata();
// Custom query loop pagination
previous_posts_link( 'Older Posts' );
next_posts_link( 'Newer Posts', $custom_query->max_num_pages );
// Reset main query object
$wp_query = NULL;
$wp_query = $temp_query;
附录:query_posts()
怎么样?
query_posts()
二级循环
如果您使用 query_posts()
输出自定义循环,而不是通过 WP_Query()
实例化用于自定义查询的单独对象,那么您将是_doing_it_wrong()
,并且将遇到几个问题 (其中最不重要的是分页问题) 。解决这些问题的第一步将是将 query_posts()
的不当使用转换为适当的 WP_Query()
呼叫。
使用 query_posts()
修改主循环
如果您只想修改主循环查询的参数 (例如更改每页的帖子或排除类别),则可能会尝试使用 query_posts()
。但你还不应该。当您使用 query_posts()
时,强制 WordPress 替换主查询对象。 (WordPress 实际上是第二个查询,并覆盖 $wp_query
) 。但问题是,在更新分页的过程中,这个替换太晚了。
解决方案是通过 pre_get_posts
钩子获取帖子之前过滤主查询。
而不是将其添加到类别模板文件 (category.php
) 中:
query_posts( array(
'posts_per_page' => 5
) );
将以下内容添加到 functions.php
中:
function wpse120407_pre_get_posts( $query ) {
// Test for category archive index
// and ensure that the query is the main query
// and not a secondary query (such as a nav menu
// or recent posts widget output, etc.
if ( is_category() && $query->is_main_query() ) {
// Modify posts per page
$query->set( 'posts_per_page', 5 );
}
}
add_action( 'pre_get_posts', 'wpse120407_pre_get_posts' );
而不是将其添加到博客帖子索引模板文件 (home.php
) 中:
query_posts( array(
'cat' => '-5'
) );
将以下内容添加到 functions.php
中:
function wpse120407_pre_get_posts( $query ) {
// Test for main blog posts index
// and ensure that the query is the main query
// and not a secondary query (such as a nav menu
// or recent posts widget output, etc.
if ( is_home() && $query->is_main_query() ) {
// Exclude category ID 5
$query->set( 'category__not_in', array( 5 ) );
}
}
add_action( 'pre_get_posts', 'wpse120407_pre_get_posts' );
这样,当确定分页时,WordPress 将使用 already-modified $wp_query
对象,不需要模板修改。
什么时候使用什么功能
研究 this question and answer 和 this question and answer,了解如何和何时使用 WP_Query
,pre_get_posts
和 query_posts()
。
次佳解决方案
我使用这个代码进行自定义循环与分页:
<?php
if ( get_query_var('paged') ) {
$paged = get_query_var('paged');
} elseif ( get_query_var('page') ) { // 'page' is used instead of 'paged' on Static Front Page
$paged = get_query_var('page');
} else {
$paged = 1;
}
$custom_query_args = array(
'post_type' => 'post',
'posts_per_page' => get_option('posts_per_page'),
'paged' => $paged,
'post_status' => 'publish',
'ignore_sticky_posts' => true,
//'category_name' => 'custom-cat',
'order' => 'DESC', // 'ASC'
'orderby' => 'date' // modified | title | name | ID | rand
);
$custom_query = new WP_Query( $custom_query_args );
if ( $custom_query->have_posts() ) :
while( $custom_query->have_posts() ) : $custom_query->the_post(); ?>
<article <?php post_class(); ?>>
<h3><a href="<?php the_permalink(); ?>"><?php the_title(); ?></a></h3>
<small><?php the_time('F jS, Y') ?> by <?php the_author_posts_link() ?></small>
<div><?php the_excerpt(); ?></div>
</article>
<?php
endwhile;
?>
<?php if ($custom_query->max_num_pages > 1) : // custom pagination ?>
<?php
$orig_query = $wp_query; // fix for pagination to work
$wp_query = $custom_query;
?>
<nav class="prev-next-posts">
<div class="prev-posts-link">
<?php echo get_next_posts_link( 'Older Entries', $custom_query->max_num_pages ); ?>
</div>
<div class="next-posts-link">
<?php echo get_previous_posts_link( 'Newer Entries' ); ?>
</div>
</nav>
<?php
$wp_query = $orig_query; // fix for pagination to work
?>
<?php endif; ?>
<?php
wp_reset_postdata(); // reset the query
else:
echo '<p>'.__('Sorry, no posts matched your criteria.').'</p>';
endif;
?>
资源:
参考文献
注:本文内容整合自 Google/Baidu/Bing 辅助翻译的英文资料结果。如果您对结果不满意,可以加入我们改善翻译效果:薇晓朵技术论坛。