如何让分页在 WordPress 中为 get_posts() 工作?

Posted

技术标签:

【中文标题】如何让分页在 WordPress 中为 get_posts() 工作?【英文标题】:How do I get pagination to work for get_posts() in WordPress? 【发布时间】:2014-09-10 09:50:14 【问题描述】:

我正在开发一个 WordPress 网站,并且我创建了一个页面模板,该模板按类别 slug 显示帖子。为此,我为页面创建了一个字段 WP_Catid,并将其设置为与我要从中显示帖子的类别 slug 相同。但是,我只希望每页显示五个帖子,并在这些帖子的底部显示分页链接。如何让分页链接正确显示?

我的代码如下:

<div id="container">
  <div id="content" role="main">
    <?php
      $btpgid=get_queried_object_id();
      $btmetanm=get_post_meta( $btpgid, 'WP_Catid','true' );
      $paged = (get_query_var('paged')) ? get_query_var('paged') : 1;

      $args = array( 'posts_per_page' => 5,
                     'category_name' => $btmetanm,
                     'paged' => $paged,
                     'post_type' => 'post' );

      $myposts = get_posts( $args );
      foreach ( $myposts as $post ) : setup_postdata( $post ); 
        echo "<div style='border:2px groove black; margin-bottom:5px;'><h3 class='btposth'>";
        the_title(); 
        echo "</h3><div class='btpostdiv'>";
        the_content();
        echo "</div></div>";
      endforeach; 
      next_posts_link( 'Older Entries'); //not displaying
      previous_posts_link('Newer Entries &raquo;'); //not displaying
      wp_reset_postdata();
    ?>
  </div><!-- #content -->
</div><!-- #container -->

【问题讨论】:

wordpress.stackexchange.com/… 【参考方案1】:

如果您需要分页查询,请不要使用get_posts。如果您要使用不需要分页的自定义查询,get_posts 可以完美地工作,但是当您需要引入分页时,它确实变得非常复杂。

我认为这里最简单最合适的方法是使用WP_Query 来构造您的自定义查询,即如果您不能使用pre_get_posts 将主查询更改为从主查询中获取所需的输出。

我确实认为next_posts_link()previous_posts_link() 更适合用于自定义查询,即WP_Query。但是,您必须记住在使用自定义查询时设置 $max_pages 参数,否则您的分页将中断

经过一些小的调整,您的查询应该如下所示

<div id="container">
<div id="content" role="main">
<?php
$btpgid=get_queried_object_id();
$btmetanm=get_post_meta( $btpgid, 'WP_Catid','true' );
$paged = (get_query_var('paged')) ? get_query_var('paged') : 1;

$args = array( 'posts_per_page' => 5, 'category_name' => $btmetanm,
'paged' => $paged,'post_type' => 'post' );
    $postslist = new WP_Query( $args );

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


             echo "<div style='border:2px groove black; margin-bottom:5px;'><h3 class='btposth'>";
                 the_title(); 
             echo "</h3><div class='btpostdiv'>";
                 the_content();
             echo "</div></div>";

         endwhile;  

             next_posts_link( 'Older Entries', $postslist->max_num_pages );
             previous_posts_link( 'Next Entries &raquo;' ); 
        wp_reset_postdata();
    endif;
    ?>

</div><!-- #content -->
</div><!-- #container -->

【讨论】:

谢谢。这段代码中有一些 PHP 错误(没有 endwhile 表达式,“Older Entries”之后没有终止单引号,并且“?>”不应该放在 while 表达式之前)。除此之外,您的代码解决了我的问题。 get_posts 内部不使用 WP_Query 吗?也许你的意思是 get_pages 对分页不是很好? @BjörnAliGöransson 是的,get_posts() 在内部使用 WP_Query,但仅从查询对象返回 $posts 属性。因此,您失去了 $max_num_pages 属性,这是分页功能的关键。 get_posts 还通过将no_found_rows=true 传递给WP_Query 合法地打破了分页(这使得get_posts 比普通的WP_Query 查询更快)。正如其他答案指出的那样,您可以分页 get_posts 查询,但它确实需要大量 不必要的 开销,使用 WP_Query 可以简单地避免这些开销 或者更好,使用paginate_links @RenéRoth 是的,你可以,但请记住,它仍然不适用于开箱即用的get_posts,分页功能需要知道查询将有多少页,这不是由get_posts 返回。对get_posts 进行分页并知道将有多少页的唯一方法是运行另一个get_posts 查询以返回所有 个帖子以计算它们,其中转向既昂贵又不必要。【参考方案2】:

Pieter Goosen's answer 是完全正确的,他建议使用WP_Query 是最有意义的。但是,我在寻找循环外的get_posts 分页时偶然发现了这个问题,所以我认为这对其他人来说可能也是一个有用的选择:

get_posts 有一个名为offset 的直接属性,它与WP_Query 中的paged 实现几乎相同的功能;但其中paged 指的是分页(例如1、2、3),offset 是您希望将查询抵消的实际帖子数(例如5、10、15)。通过一些数学运算 - numberToShow * pageNumber - 您可以轻松获得正确的偏移量:

$paged = (get_query_var('paged')) ? get_query_var('paged') : 0;

$postsPerPage = 5;
$postOffset = $paged * $postsPerPage;

$args = array(
    'posts_per_page'  => $postsPerPage,
    'category_name'   => $btmetanm,
    'offset'          => $postOffset,
    'post_type'       => 'post'
);

$myposts = get_posts($args);

此示例中的初始paged 值为0 而不是1,因为在乘以posts_per_page 时,您希望初始偏移量为0 而不是5

如果您想要更精细的控制而不是简单的分页,这可能是最方便的,但应该与接受答案中的循环结合使用。

【讨论】:

顺便说一句,WP_Query 使用完全相同的方法来计算应该根据页面返回哪些帖子,我的意思是,使用页码和每页帖子来计算偏移量 最后一点,get_posts 使用WP_Query 运行其自定义查询。 get_posts 只是返回 WP_Query()-&gt;posts,所以为什么不使用 WP_Query 并让我们来做这项工作 @PieterGoosen 所有完全有效的积分;正如我所提到的,您对使用 WP_Query 的建议在这种特殊情况下更有意义,因为显然需要完整的帖子信息。在我的特定情况下,我使用get_posts 来获取一组信息(并且get_posts 不会返回与WP_Query 相同的完全相同 - 只是子集查询帖子对象 - 次要区别-并且还关闭分页查询并忽略粘性帖子)。我只是想指出offset 作为替代方案,如果不是完全适合这项工作的话。 没问题,您的回答仍然非常有效,是一个不错的选择;-) 很好的答案,考虑到这完全符合无限滚动的需要:)【参考方案3】:

尝试改变你的 $args:

$args = array( 
'posts_per_page' => 5,
'category_name' => $btmetanm,
'post_type' => 'post',
'paged' => ( get_query_var('paged') ? get_query_var('paged') : 1 )
   );

在循环之后放这个:

if (function_exists('wp_pagenavi')) 
wp_pagenavi();

【讨论】:

他的$args和你一样,只是使用了wp_pagenavi()。这对我不起作用。 你需要通过wp_pagenavi(array('query' =&gt;$your_wp_query_object))【参考方案4】:

我不会告诉你使用 get_posts() 是正确的做法……但这里是我使用 get_posts() 设置的一些基本分页代码。

编辑:正如 Pieter 所指出的,这并不意味着在生产代码中使用。但无论如何,我只是在玩一些东西,看看我是否可以使用 get_posts() 进行分页。如果您在生产环境中,您不会想使用它。

$cpt_name = 'post-type'; //add your own post type

//what pagination page are we on?
if(! empty($_GET['pag']) && is_numeric($_GET['pag']) )
    $paged = $_GET['pag'];
else
    $paged = 1;

//you could use this if you want, just make sure to use "/page/2" instead of "?pag=2" in the pagination links.
//$paged = (get_query_var('paged')) ? get_query_var('paged') : 0;

//how many posts should we display?
$posts_per_page = (get_option('posts_per_page')) ? get_option('posts_per_page') : 10; 

//let's first get ALL of the possible posts
$args = array(
        'posts_per_page'   => -1,
        'orderby'          => 'title',
        'order'            => 'ASC',
        'fields'           => 'ids',
        'post_type'        => $cpt_name
    );

$all_posts = get_posts($args);

//how many total posts are there?
$post_count = count($all_posts);

//how many pages do we need to display all those posts?
$num_pages = ceil($post_count / $posts_per_page);

//let's make sure we don't have a page number that is higher than we have posts for
if($paged > $num_pages || $paged < 1)
    $paged = $num_pages;


//now we get the posts we want to display
$args = array(
        'posts_per_page'   => $posts_per_page,
        'orderby'          => 'title',
        'order'            => 'ASC',
        'post_type'        => $cpt_name,
        'paged'        => $paged
    );

$my_posts = get_posts($args);

//did we find any?
if(! empty($my_posts))

    echo '<div id="my-posts-wrapper">';

    //THE FAKE LOOP
    foreach($my_posts as $key => $my_post)
                //do stuff with your posts
        echo '<div class="my-post">'.$my_post->post_title.'</div>';

    

    echo '</div>';

    //we need to display some pagination if there are more total posts than the posts displayed per page
    if($post_count > $posts_per_page )

        echo '<div class="pagination">
                <ul>';

        if($paged > 1)
            echo '<li><a class="first" href="?pag=1">&laquo;</a></li>';
        else
            echo '<li><span class="first">&laquo;</span></li>';
        

        for($p = 1; $p <= $num_pages; $p++)
            if ($paged == $p) 
                echo '<li><span class="current">'.$p.'</span></li>';
            else
                echo '<li><a href="?pag='.$p.'">'.$p.'</a></li>';
            
        

        if($paged < $num_pages)
            echo '<li><a class="last" href="?pag='.$num_pages.'">&raquo;</a></li>';
        else
            echo '<li><span class="last">&raquo;</span></li>';
        

        echo '</ul></div>';
    

我希望有人能从中得到一些用处:)

编辑:什么鬼!以错误的方式做某事……还不如做对!这里也有一些 LESS(没有任何 mixins)。

.pagination              margin: 30px 0px;
    ul                     display:block; list-style-type:none; margin:0 auto; padding: 0px; 
      li                   display:inline-block; list-style-type:none; margin:0; padding:0;
        a, span            display:inline-block; font-size: 14px; width:auto; min-width:26px; height:26px; line-height: 26px; border: 1px solid #dddddd; border-right: 0px; background:#FFFFFF; color:#FF0000; padding: 5px; text-align: center;
          &:hover          cursor:pointer; text-decoration:none; 

          &.first          border-top-left-radius: 3px; border-bottom-left-radius: 3px; 
          &.last           border-top-right-radius: 3px; border-bottom-right-radius: 3px;
        

        span.last,
        span.first         color: #FF0000;
            &:hover        cursor: default; 
        

        a.last,
        a.first            
            &:hover         
        

        a:hover, 
        &.active a, 
        .current           background:#FF0000; color:#ffffff; border-color: #b21712; 

        &:last-child       
            a, span        border-right: 1px solid #dddddd; 

            a              
                &:hover    border-color: #FF0000; 
            
        
      
    

【讨论】:

没有名为pag 的查询变量。其次,您的查询非常昂贵。如果您有 1000 个帖子,您将查询 1000 个帖子只是为了获取帖子数。然后,您运行另一个查询只是为了再次获取帖子。这对页面速度和搜索引擎优化非常不利。顺便说一句,这就是get_posts() 所做的,$q = new WP_Query( $args ); return $q-&gt;posts;,所以在不知不觉中,你已经使用了WP_Query 在你的代码前添加timer_start();,然后在你的代码后添加echo '&lt;p&gt;' . get_num_queries() . ' queries in ' . timer_stop(1, 5) . ' seconds. &lt;/p&gt;';,检查我的代码和你的代码之间的巨大差异,然后你告诉我你是否还想使用get_posts分页查询 ;-) 大声笑,谢谢彼得。我知道这很糟糕,我个人不会将它用于任何事情。我只是想展示使用 get_posts 进行分页会是什么样子。另外,我没有使用“pag”作为查询变量。我将 pag 设置为 GET var,然后在注释掉的 get_query_var 中使用分页。也许我没有明确说明这不是一篇严肃的帖子,而只是让 get_posts() 与分页一起工作的有趣尝试。 只是一个提示,为了减少第一个用作帖子计数的查询的负载,请在参数中设置'fields' =&gt; 'ids'。这只会返回帖子 ID,而不是完整的帖子。如果您不需要任何 postdata,这可以节省大量资源 感谢 Pieter 提供的信息 :) 我继续在测试站点上实际设置了这段代码,还设置了 WP_query 并运行了一些测试。总共只有 9 个帖子,所以样本量非常小,但平均而言,WP_query 几乎快两倍(这可能是预期的差异)。

以上是关于如何让分页在 WordPress 中为 get_posts() 工作?的主要内容,如果未能解决你的问题,请参考以下文章

Wordpress category.php 分页 404 错误

如何根据分页在数据表中放置行的序列号

如何使用 Material UI 表格分页在每页显示正确的行

自定义wp_query上的Wordpress分页(next_posts_link)未显示

如何在 iOS 中使用分页在 Scrollview 中进行下一个或上一个

如何通过分页在 Spring Data JPA 中的 SELECT 子句中按别名对投影进行排序?