问题描述

我已经将自定义/辅助查询添加到模板文件/自定义页面模板中; 如何使 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 对象:

破解主查询对象

  1. 备份主查询对象:$temp_query = $wp_query
  2. 空的主查询对象:$wp_query = NULL;
  3. 将自定义查询交换到主查询对象:$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 answerthis question and answer,了解如何和何时使用 WP_Querypre_get_postsquery_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 辅助翻译的英文资料结果。如果您对结果不满意,可以加入我们改善翻译效果:薇晓朵技术论坛。