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

附录

我已通过query_posts()修改了主循环查询。为什么分页不起作用,该如何解决?

#1 楼

问题

默认情况下,在任何给定的上下文中,WordPress都会使用主查询来确定分页。主查询对象存储在$wp_query全局变量中,该全局变量还用于输出主查询循环:单独的查询对象:

if ( have_posts() ) : while ( have_posts() ) : the_post();


,该查询通过完全独立的循环输出:

$custom_query = new WP_Query( $custom_query_args );


但是分页模板标签(包括previous_posts_link()next_posts_link()posts_nav_link()paginate_links())的输出基于主查询对象$wp_query。该主查询可以分页,也可以不分页。例如,如果当前上下文是自定义页面模板,则主$wp_query对象将仅包含一个帖子-自定义页面模板所分配到的页面ID的帖子。

如果当前上下文是某种存档索引,则主$wp_query可能包含足以引起分页的帖子,这将导致问题的下一部分:对于主$wp_query对象,WordPress将根据paged URL查询变量,将paged参数传递给查询。提取查询后,该paged参数将用于确定要返回哪一组分页的帖子。如果单击了显示的分页链接,并且加载了下一页,则您的自定义查询将无法知道分页已更改。

解决方案

传递自定义查询的正确分页参数

假定自定义查询使用了args数组:

if ( $custom_query->have_posts() ) : 
    while ( $custom_query->have_posts() ) : 
        $custom_query->the_post();


您将需要传递正确的paged数组的参数。您可以通过get_query_var()来获取用于确定当前页面的URL查询变量来做到这一点:

$custom_query_args = array(
    // Custom query parameters go here
);


然后可以将该参数附加到自定义查询args数组中:

get_query_var( 'paged' );


注意:如果您的页面是静态首页,请确保使用page而不是paged,因为静态首页使用page而不是paged。这是静态首页应该具有的功能

$custom_query_args['paged'] = get_query_var( 'paged' ) 
    ? get_query_var( 'paged' ) 
    : 1;


现在,当获取自定义查询时,将返回正确的分页帖子集。 >
对分页功能使用自定义查询对象

为了使分页功能产生正确的输出-即相对于自定义查询的上一页/下一页/页面链接-必须强制WordPress识别自定义查询。这需要一点“ hack”:用自定义查询对象$wp_query替换主$custom_query对象:

没有主查询对象


主查询对象:$temp_query = $wp_query

使主查询对象无效:$wp_query = NULL;


将自定义查询交换到主查询对象:$wp_query = $custom_query;

$custom_query_args['paged'] = get_query_var( 'page' ) 
    ? get_query_var( 'page' ) 
    : 1;



必须在调用任何分页功能之前完成此“ hack”操作

重置主查询对象

一次分页功能已输出,请重置主查询对象:

$temp_query = $wp_query;
$wp_query   = NULL;
$wp_query   = $custom_query;


分页功能修复

previous_posts_link()函数将正常运行,而不考虑分页。它仅确定当前页面,然后输出page - 1的链接。但是,需要修复才能正确输出next_posts_link()。这是因为next_posts_link()使用max_num_pages参数:

$wp_query = NULL;
$wp_query = $temp_query;


与其他查询参数一样,默认情况下该函数将max_num_pages用于主要$wp_query对象。为了强制next_posts_link()占用$custom_query对象,您需要将max_num_pages传递给函数。您可以从$custom_query对象获取此值:$custom_query->max_num_pages

<?php next_posts_link( $label , $max_pages ); ?>


将它们全部放在一起

以下是具有适当功能的分页功能的自定义查询循环的基本结构:

<?php next_posts_link( 'Older Posts' , $custom_query->max_num_pages ); ?>


附录:关于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)中:

// 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;


添加跟随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'
) );


这样,WordPress在确定分页时将使用已修改的functions.php对象,而无需修改模板。

何时使用什么功能

研究此问题和答案以及此问题和答案,以了解如何以及何时使用$wp_queryWP_Querypre_get_posts

评论


抄本中的希望页面可能是如此完整。

–Pieter Goosen
2014年4月3日在12:41

芯片,你让我开心!

–tepkenvannkorn
2014年9月8日在8:57

芯片,您总是可以节省很多时间!如果只有Google会在我疯狂搜索之前给您更高的答案(针对Googlers的标注);)谢谢。

–敏捷的SEO
2014-09-14 15:56

使用您的示例,直到我使用了if-else块(而不是?:有条件的)在此页面下找到该主题之前,我无法使分页正常工作:themeforest.net/forums/thread / ...,非常奇怪。否则,这个答案教给我很多东西。

– P a u l
2014年12月8日下午6:52

很好的答案-1件事,我在ajax调用中运行下一个/上一个帖子链接功能时遇到问题-只是不愿意-快速浏览后发现全局页面没有被更新(与管理员有关) -ajax.php环境),因此我添加了以下内容:global $ paged; $ paged = $ custom_query_args ['paged'];它起作用了:)

–morse
2014年12月20日16:00



#2 楼

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

<?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;
?>


来源:


带有分页的WordPress自定义循环


#3 楼

一如既往的酷。作为对此的补充,请考虑以下情况:正在使用附加到页面的全局页面模板作为“介绍文字”,然后是要分页的子查询。

使用paginate_links ()如上所述,大多数情况下都是默认设置(并且假设您已启用了永久链接),您的分页链接将默认设置为mysite.ca/page-slug/page/#,这很可爱,但会抛出404错误,因为WordPress不知道该特定的URL结构,实际上寻找“ page”的子页面,而“ page-slug”的子页面。

这里的技巧是插入一个漂亮的重写规则,该规则仅适用于特定的“ pseudo存档页面”页面slug接受/page/#/结构并将其重写为WordPress可以理解的查询字符串,即mysite.ca/?pagename=page-slug&paged=#。请注意pagenamepaged而不是namepage(这确实使我感到数小时的悲伤,在这里激发了这个答案!)。

这是重定向规则:
和往常一样,在更改重写规则时,请记住通过访问管理后端中的“设置”>“永久链接”来刷新永久链接。

如果有多个页面将以这种方式运行(例如,当处理多种自定义帖子类型时),您可能要避免为每个页面段创建新的重写规则。我们可以编写一个更通用的正则表达式,该表达式可用于您确定的任何页面信息。

下面是一种方法:

add_rewrite_rule( "page-slug/page/([0-9]{1,})/?$", 'index.php?pagename=page-slug&paged=$matches[1]', "top" );


缺点/警告

这种方法的一个缺点是Page slug的硬编码,这使我有些p嘴。如果管理员曾经更改过该伪归档页面的页面标签,那么您将敬酒-重写规则将不再匹配,您将获得可怕的404。

我不确定是否可以考虑此方法的解决方法,但是如果是全局页面模板以某种方式触发了重写规则,那就太好了。有一天,如果没人能破解那个特殊的螺母,我可能会重新审视这个答案。

评论


您可以挂钩保存,检查页面是否在元键_wp_page_template下具有存档模板,然后添加另一个重写和刷新规则。

–米洛
16 Dec 17'0:54

#4 楼


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

好答案今天创建的芯片需要修改。
一段时间以来,我们有$wp_the_query变量应该等于$wp_query
这就是为什么Chip答案中的这部分内容:

不再需要主查询对象


br />我们可以通过创建临时变量来忘记这部分。
// 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功能赋予更多自由度,我创造了这一可能的改进:
https://core.trac.wordpress.org/ticket/39483

#5 楼

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;
    ?>