I am writing a plugin that will allow simple comment upvoting.
I am trying to sort comments by the number of upvotes. But anything I do on the comments_array Hook gets somehow reset. My question is where and how?
Here is my code:
add_filter( 'comments_array', 'biiird_order_comments_by_likes' );
function biiird_order_comments_by_likes( $array ) {
$arraya = $array;
usort($arraya, function($a, $b) {
$likes_a = get_comment_meta( $a->comment_ID, 'likes', true );
$likes_b = get_comment_meta( $b->comment_ID, 'likes', true );
return ($likes_a > $likes_b) ? -1 : 1;
});
foreach ( $arraya as $comment ) {
$comment->comment_content .= 'something';
}
var_dump($arraya);
var_dump($array);
return $arraya;
}
The var_dump($arraya)
outputs a modified array in the proper order, but the comments show on a page as if the filter was not run.
I am writing a plugin that will allow simple comment upvoting.
I am trying to sort comments by the number of upvotes. But anything I do on the comments_array Hook gets somehow reset. My question is where and how?
Here is my code:
add_filter( 'comments_array', 'biiird_order_comments_by_likes' );
function biiird_order_comments_by_likes( $array ) {
$arraya = $array;
usort($arraya, function($a, $b) {
$likes_a = get_comment_meta( $a->comment_ID, 'likes', true );
$likes_b = get_comment_meta( $b->comment_ID, 'likes', true );
return ($likes_a > $likes_b) ? -1 : 1;
});
foreach ( $arraya as $comment ) {
$comment->comment_content .= 'something';
}
var_dump($arraya);
var_dump($array);
return $arraya;
}
The var_dump($arraya)
outputs a modified array in the proper order, but the comments show on a page as if the filter was not run.
2 Answers
Reset to default 0This is not a bug.
If you look at the comment starting at line 2100 of wp/wp-includes/comment-template.php in the wp_list_comments
function, you'll see that if the per_page
argument is set and its value is different to that of the main wp_query, it'll perform a separate comment query and display those, instead of the ones you have sorted.
To get around this you'll need to create a custom walker and pass that to the wp_list_comments
function and perform the sorting there:
wp_list_comments(['walker' => new MySortingCommentWalker()]);
Given that you are writing a plugin, you could use the wp_list_comments_args
filter to ensure your custom walker is always used:
add_filter('wp_list_comments_args', function($args) {
$args['walker'] = new MySortingCommentWalker();
return $args;
});
You could extend the default Walker_Comment
class, override the paged_walk
method and sort the comments in there. Once sorted you can pass them to the parent method:
class MySortingCommentWalker extends \Walker_Comment
{
public function paged_walk($elements, $max_depth, $page_num, $per_page, ...$args)
{
// Pass $elements to your sorting function here
return parent::paged_walk($elements, $max_depth, $page_num, $per_page, $args);
}
}
I think I have found a bug in wordpress, the thing that is causing the problem is the 'per_page'
argument passed in wp_list_comments()
. If it is set, then changes made to comments_array hook get reset or omitted later in the wp core.
I am 90% sure it's a bug and I have reported it on wordpress trac.