如何修复定制循环的分页?

时间:2013-10-28 作者:Chip Bennett

我已经向模板文件/自定义页面模板添加了自定义/辅助查询;如何使WordPress使用自定义查询进行分页,而不是使用主查询循环的分页?

附录

我通过修改了主循环查询query_posts(). 为什么分页不起作用,如何修复?

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

默认情况下,在任何给定的上下文中,WordPress都使用主查询来确定分页。主查询对象存储在$wp_query global,也用于输出主查询循环:

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 可能由足够多的帖子组成,导致分页,从而导致问题的下一部分:对于main$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\' );
然后,可以将该参数附加到自定义查询参数数组中:

$custom_query_args[\'paged\'] = get_query_var( \'paged\' ) 
    ? get_query_var( \'paged\' ) 
    : 1;
Note: 如果您的页面是static front page, 确保使用page 而不是paged 作为静态首页使用page 而不是paged. 这是静态首页应该具备的功能

$custom_query_args[\'paged\'] = get_query_var( \'page\' ) 
    ? get_query_var( \'page\' ) 
    : 1;
现在,当获取自定义查询时,将返回正确的分页帖子集。

为分页函数使用自定义查询对象,以便分页函数生成正确的输出,即与自定义查询相关的上一页/下一页/页面链接,需要强制WordPress识别自定义查询。这需要一点“黑客”:更换主$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;
在调用任何分页函数之前,必须进行此“破解”

重置主查询对象

输出分页函数后,重置主查询对象:

$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 对象,无需修改模板。

何时使用什么功能研究this question and answerthis question and answer 了解如何以及何时使用WP_Query, pre_get_posts, 和query_posts().

SO网友:webvitaly

我将此代码用于分页的自定义循环:

<?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;
?>
资料来源:

SO网友:Tom Auger

像往常一样棒极了,奇普。作为本文的补充,请考虑这样一种情况,即您正在使用附加到某个页面的全局页面模板来获取一些“简介文本”,然后是您想要分页的子查询。

使用paginate_links() 正如您上面提到的,在大多数默认情况下(并且假设您已经打开了相当多的永久链接),分页链接将默认为mysite.ca/page-slug/page/# 这很可爱,但会404 错误,因为WordPress不知道特定的URL结构,实际上会查找“page”的子页,而“page slug”的子页。

这里的技巧是插入一个漂亮的重写规则,该规则只适用于接受/page/#/ 结构并将其重写为WordPress可以理解的查询字符串,即mysite.ca/?pagename=page-slug&paged=#. 笔记pagenamepagednamepage (这让我痛苦了好几个小时,这也激发了我的回答!)。

以下是重定向规则:

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\' );
缺点/注意事项这种方法的一个缺点让我有点恶心,那就是页面段塞的硬编码。如果管理员更改了伪归档页面的页面段塞,你就完蛋了——重写规则将不再匹配,你将得到可怕的404。

我不确定我能想出一个解决方法来解决这个问题,但如果它是以某种方式触发重写规则的全局页面模板,那就太好了。有一天,如果没有其他人解决了这个问题,我可能会重新考虑这个答案。

SO网友:prosti

我已通过修改主循环查询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();
其他芯片勾勒出的一切都保留了下来。在查询重置部分之后,可以调用以下分页函数f($wp_query), — 他们依赖于$wp_query 全球的


以进一步改进分页机制并为query_posts 功能I创建了此可能的改进:

https://core.trac.wordpress.org/ticket/39483

SO网友:Ravi Patel
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;
    ?>
结束