我已经在模板文件/自定义页面模板中添加了自定义/辅助查询;如何使WordPress使用我的自定义查询进行分页,而不是使用主查询循环的分页?
附录
我已经通过修改了主循环查询query_posts()
。为什么分页不起作用,如何解决?
我已经在模板文件/自定义页面模板中添加了自定义/辅助查询;如何使WordPress使用我的自定义查询进行分页,而不是使用主查询循环的分页?
我已经通过修改了主循环查询query_posts()
。为什么分页不起作用,如何解决?
Answers:
默认情况下,在任何给定的上下文中,WordPress都会使用主查询来确定分页。主查询对象存储在$wp_query
全局对象中,该对象也用于输出主查询循环:
if ( have_posts() ) : while ( have_posts() ) : the_post();
当您使用自定义查询,您可以创建一个完全独立的查询对象:
$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”:用$wp_query
自定义查询对象替换主对象$custom_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将$wp_query
在确定分页时使用已修改的对象,而无需修改模板。
研究这个问题,并回答与这个问题和答案,以了解如何以及何时使用WP_Query
,pre_get_posts
和query_posts()
。
paged
没有更新(观察到与admin-有关ajax.php环境),所以我添加了它: global $paged; $paged = $custom_query_args['paged'];
并且起作用了:)
我将此代码用于带有分页的自定义循环:
<?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;
?>
资源:
一如既往的酷。作为对此的附录,请考虑以下情况:您正在使用连接到页面的全局页面模板作为“介绍文字”,并在其后跟要分页的子查询。
如上文所述,使用paginate_links()并使用大多数默认值(并假设已启用漂亮的永久链接),您的分页链接将默认设置mysite.ca/page-slug/page/#
为可爱,但会引发404
错误,因为WordPress不知道该特定URL结构,实际上寻找“ page”的子页面,即“ page-slug”的子页面。
这里的技巧是插入一个巧妙的重写规则,该规则仅适用于接受该/page/#/
结构并将其重写为WordPress可以理解的查询字符串的特定“伪存档页面”页面mysite.ca/?pagename=page-slug&paged=#
。请注意,pagename
而paged
不要注意(和name
,page
这确实使我悲伤了HOURS,在此激励了这个答案!)。
这是重定向规则:
add_rewrite_rule( "page-slug/page/([0-9]{1,})/?$", 'index.php?pagename=page-slug&paged=$matches[1]', "top" );
与往常一样,在更改重写规则时,请记住通过访问管理后端中的“设置”>“永久链接” 来刷新永久链接。
如果您有多个页面将以这种方式运行(例如,在处理多种自定义帖子类型时),则可能要避免为每个页面段创建新的重写规则。我们可以编写一个更通用的正则表达式,该表达式可用于您标识的任何页面信息。
下面是一种方法:
function wpse_120407_pseudo_archive_rewrite(){
// Add the slugs of the pages that are using a Global Template to simulate being an "archive" page
$pseudo_archive_pages = array(
"all-movies",
"all-actors"
);
$slug_clause = implode( "|", $pseudo_archive_pages );
add_rewrite_rule( "($slug_clause)/page/([0-9]{1,})/?$", 'index.php?pagename=$matches[1]&paged=$matches[2]', "top" );
}
add_action( 'init', 'wpse_120407_pseudo_archive_rewrite' );
这种方法的缺点是让Page slug硬编码,这使我有些p嘴。如果管理员更改了该伪归档页面的页面标签,那么您将敬酒-重写规则将不再匹配,您将获得可怕的404。
我不确定是否可以考虑此方法的解决方法,但是如果是全局页面模板以某种方式触发了重写规则,那将是很好的。有一天,如果没有其他人能破解那个特定的螺母,我可能会重新审视这个答案。
_wp_page_template
,然后添加另一个重写和刷新规则。
我已经通过修改了主循环查询
query_posts()
。为什么分页不起作用,如何解决?
好的答案创建的芯片今天需要修改。在主查询执行之后的
一段时间内,我们拥有的$wp_the_query
变量应等于$wp_query
全局变量。
这就是为什么这部分来自芯片的答案:
破解主要查询对象
不再需要。我们可以通过创建临时变量来忘记这一部分。
// Pagination fix
$temp_query = $wp_query;
$wp_query = NULL;
$wp_query = $custom_query;
现在,我们可以致电:
$wp_query = $wp_the_query;
甚至更好,我们可以致电:
wp_reset_query();
Chip概述的所有其他内容均会保留。在查询重置部分之后,您可以调用分页函数,f($wp_query)
它们取决于$wp_query
全局。
为了进一步改善分页机制并赋予query_posts
功能更多的自由,我创建了以下可能的改进:
global $wp_query;
$paged = get_query_var('paged', 1);
$args = array(
'post_type' => '{your_post_type_name}',
'meta_query' => array('{add your meta query argument if need}'),
'orderby' => 'modified',
'order' => 'DESC',
'posts_per_page' => 20,
'paged' => $paged
);
$query = new WP_Query($args);
if($query->have_posts()):
while ($query->have_posts()) : $query->the_post();
//add your code here
endwhile;
wp_reset_query();
//manage pagination based on custom Query.
$GLOBALS['wp_query']->max_num_pages = $query->max_num_pages;
the_posts_pagination(array(
'mid_size' => 1,
'prev_text' => __('Previous page', 'patelextensions'),
'next_text' => __('Next page', 'patelextensions'),
'before_page_number' => '<span class="meta-nav screen-reader-text">' . __('Page', 'patelextensions') . ' </span>',
));
else:
?>
<div class="container text-center"><?php echo _d('Result not found','30'); ?></div>
<?php
endif;
?>