Skip to:
Content

Opened 11 months ago

Last modified 7 months ago

#3201 new enhancement

Pagination for threaded comments

Reported by: MBV Owned by:
Milestone: Future Release Priority: normal
Severity: normal Version:
Component: Component - Replies Keywords:
Cc: wpdennis

Description

It would be really great if pagination for threaded comments could be looked into again. I notice there are a lot of people wanting this feature.

@svetoslavd79 came up with a mostly working solution https://wpup.co/bbpress-threaded-nested-replies-with-paging/ and in the comments section suggested an idea/consideration on how it could be re-done more elegantly to prevent url linking issues:

...I’m starting to think that the most elegant way to deal with all this issues surrounding pagination of replies is to create a hidden field in the reply form that saves the page number as a custom field attached to the reply. If you can accomplish that, modifying or filtering anything that needs a link to that particular reply post should be a breeze after that. Anything else will have to involve some wild math to calculate each reply page number and will only weigh in on the execution and ultimately site speed and performance. This is still not super simple but something to consider if you want to pursue such implementation.

Nevertheless, the code outlined below seems to work well with standard bbpress forum, with a couple of issues:

  1. There is an issue with a buddypress group forum: after posting reply there, the refreshed url page number is incorrect.
  1. When trashing a reply in forum, the pagination breaks... redirect goes to something like this .../?view=all#post-4296 and the pagination does not work and can't navigate pages as their url links are no longer correct.
  1. Links may not link to the correct page number for the topic subscription email notifications and the Recent Replies widget.

Below is the extract of @svetoslavd79 code from https://wpup.co/bbpress-threaded-nested-replies-with-paging/

Copy the below function to your functions.php file. The modification will allow us to pass the current page and number of replies per page, so the query returns the correct reply posts.

function wpup_bbp_list_replies( $args = array() ) {
 
    // Reset the reply depth
    bbpress()->reply_query->reply_depth = 0;
 
    // In reply loop
    bbpress()->reply_query->in_the_loop = true;
 
    $r = bbp_parse_args( $args, array(
        'walker'       => null,
        'max_depth'    => bbp_thread_replies_depth(),
        'style'        => 'ul',
        'callback'     => null,
        'end_callback' => null
    ), 'list_replies' );
 
    // Get replies to loop through in $_replies
    $walker = new BBP_Walker_Reply;
    $walker->paged_walk( bbpress()->reply_query->posts, $r['max_depth'], $r['page'], $r['per_page'], $r );
 
    bbpress()->max_num_pages = $walker->max_pages;
    bbpress()->reply_query->in_the_loop = false;
}

Next copy the below function to your functions.php file, right after the previous one from Step 1. This piece of code is responsible for displaying the page number navigation. The 2 important variables here are $numeplies – the total number of replies of the currently displayed topic and $paged – the current page number the visitor is displaying. You will find out how we are going to pass those values in the next few steps.

//Custom Pagination function
function wpup_custom_pagination($numreplies='', $pagerange='', $paged='', $repliesperpage='') {
 
  /**
   * $pagerange
   * How many pages to display after the current page
   * Used in combination with 'shaw_all' => false
   */
  if (empty($pagerange)) {
    $pagerange = 3;
  }
   
  /**
   * $numreplies
   * What is the total number of replies in the current topic
   * $numpages
   * Calculate total number of pages to display based on number of replies and replies per page
   */
  if ($numreplies != '') {
    $numpages = ceil($numreplies / $repliesperpage);
  }
   
  //assign value of 1 to $paged variable in case it's not passed on 
  global $paged;
  if (empty($paged)) {
    $paged = 1;
  }
 
  /** 
   * We construct the pagination arguments to enter into our paginate_links
   * function. 
   */
 $pagination_args = array(
    'base'            => get_pagenum_link(1) . '%_%',
    'format'          => 'page/%#%',
    'total'           => $numpages,
    'current'         => $paged,
    'show_all'        => False,
    'end_size'        => 1,
    'mid_size'        => $pagerange,
    'prev_next'       => True,
    'prev_text'       => __('<'),
    'next_text'       => __('>'),
    'type'            => 'plain',
    'add_args'        => false,
    'add_fragment'    => ''
  );
 
  $paginate_links = paginate_links($pagination_args);
 
  if ($paginate_links) {
    echo "<nav class='custom-pagination'>";
      echo $paginate_links;
    echo "</nav>";
  }
 
}

This next snippet takes the current page you are on and changes the value of the hidden field in the reply form. This is so after replying, the page doesn't load at page 1.

//customize the forum reply form redirect to send back to the current page you are on

function wpup_reply_redirect() {

if (bbp_is_single_topic()) {

$redirect_to = '<input type="hidden" id="bbp_redirect_to" name="redirect_to" value="' . esc_url( $_SERVER['REQUEST_URI'] ) . '"/>';

}

return $redirect_to;

}


add_filter('bbp_redirect_to_field', 'wpup_reply_redirect', 10, 2);

However, two other places that may need looking at where the links may not link to the correct page number are the topic subscription email notifications and the Recent Replies widget.

Next, edit loop-replies.php. On top of the file and right after the opening <?php tag, add this line of code -here we are checking/setting the $paged variable based on the page the user is on, so that we can use it further below....

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

Replace the default bbp_list_replies() with our own custom function that we created in Step 1. Scroll down and look at around line 45 for

<?php bbp_list_replies(); ?>

and replace it with

<?php 
//Change 15 to number of replies you want users to see per page 
wpup_bbp_list_replies(array('page' => $paged, 'per_page' => 15)); 
?>

*Remember to change 15 with the number of replies you want to see per page. Also, please note that only the main replies are considered when specifying the number per page, since the nested replies are children of the main reply.

Next we want to call our pagination function, to display the page navigation. To do that, scroll down to around line 84 and include the following, right after the </ul> closing tag:

<div id="pagination-links"><?php  
//Change 15 to number of replies you specified in wpup_bbp_list_replies
//First find the number of parent posts only and pass that to the custom pagination function
$replyposts = bbpress()->reply_query->posts;
$numparentreplies = 0;
foreach($replyposts as $value){
if($value->reply_to == 0) {
    $numparentreplies++;
  }
}
wpup_custom_pagination($numparentreplies,"",$paged, 15); ?></div>

Change History (4)

#1 @MBV
11 months ago

He also mentions re the link issue:

...As to the notifications, I don't know if it will be possible, for this to be fixed via something simple. It sounds like you may have to turn off the main notifications and write something completely custom that executes at the point of reply and is attached to the reply form. That should allow you to get all the info that can be then passed in an email, i.e current page address, contents of the reply textarea, etc.. For the Recent Replies widget I can't think of an easy scenario too, if at all possible to have that without a complete custom solution.

Which is why he suggested consideration to create a hidden field in the reply form that saves the page number as a custom field attached to the reply.

Last edited 11 months ago by MBV (previous) (diff)

#2 @netweb
11 months ago

  • Component changed from General to Component - Replies
  • Milestone changed from Awaiting Review to Future Release

Thanks for creating the ticket @MBV and including the referenced prior work.

#3 @wpdennis
10 months ago

  • Cc wpdennis added

#4 @wpdennis
7 months ago

A few things to note (with bbPress 2.6 in mind):

1) The solution from wpup just limits the amount of posts shown in the HTML output. As far as I can tell it doesn't limit the amount of posts loaded from the database. For larger forums with lots of replies this isn't a viable solution, since all posts will be loaded into $bbp->reply_query->posts in all instances.

2) The function wpup_bbp_list_replies() is not necessary, since bbp_list_replies() does pretty much the same.

3) Instead of using 15 as a hard coded value I would use bbp_get_replies_per_page().


Limit the amount of replies loaded

The posts are loaded from the database in bbp_has_replies():

<?php
        // Parse arguments against default values
        $r = bbp_parse_args( $args, $default, 'has_replies' );

        // Set posts_per_page value if replies are threaded
        $replies_per_page = (int) $r['posts_per_page'];
        if ( true === $r['hierarchical'] ) {
                $r['posts_per_page'] = -1;
        }

        // Get bbPress
        $bbp = bbpress();

        // Call the query
        $bbp->reply_query = new WP_Query( $r );

Since posts_per_page is always set to 1, even if we filter it via bbp_after_has_replies_parse_args there is currently no easy way to set a limit in bbPress. Probably pre_get_posts would be the way to go, but feels quite dirty.


But even with a way to set posts_per_page this topic is way more complicated. A few random thoughts:

  • We can't just limit the amount of top level replies (as in parent = topic_id) to e.g. 15. What if one of them gets way too many replies and we still end up loading a few hundred replies?
  • If we limit the total amount of replies (over all depths), what happens if a reply gets 15+ replies? If a user paginates to page 2, how do we solve the indentation? It would be great to show the parent reply, too.
  • What if the depth is 5? Do we load all parents on the second page? How does it look uasbility-wise? How do we load everything with the least amount of database queries?
  • What if some people reply to the first top level reply. Eventually this would move older replies to another page and all links (like bookmarks, notification mails) would become invalid.

With performance in mind this gets really complicated to do.


Some ideas I'm thinking about:

  • Get the total reply count (it's already cached).
  • If it's lower than bbp_get_replies_per_page() just show all replies as tree.
  • If it's higher just load the top level replies with a "load Y more..." link. This link would load the sub replies via ajax. We would need to limit the amount at this point, too.
  • Introduce some query arg to force a specific reply to be present. Use this parameter in notification mails & co. Or use a permalink to this reply. This permalink shows all sub replies, too and has link "back to topic".

There is still a lot of details missing, but maybe this helps.

Note: See TracTickets for help on using tickets.