1

Goal

Sort comments in the "edit-comments.php" table based on a comment meta field after clicking on the title of a custom made column.

Context

For the sake of brevity let's assume that when a comment is posted, a meta field called "hearts" is assigned to it so that all comments have that field which is a positive int from 0 to 10. Of the bold steps mentioned below, the first three are given for context and work as intended, the problem is on the 4th step.

1. Creating the column

add_filter( 'manage_edit-comments_columns', 'hearts_add_comments_column' );
function hearts_add_comments_column( $cols ) {
    $cols['hearts'] = 'Hearts';
    return $cols;
}

2. Populating the column

add_action( 'manage_comments_custom_column', 'hearts_column_content', 10, 2 );
function hearts_column_content( $column, $comment_ID ) {
    switch ( $column ) :
        case 'hearts' : {           
            $hearts = get_comment_meta( $comment_ID, 'hearts', true );                  
            echo $hearts;           
            break;
        }
    endswitch;
}

3. Making the column sortable

add_filter( 'manage_edit-comments_sortable_columns', 'hearts_make_sortable' );
function hearts_make_sortable( $cols ) {
    $cols['hearts'] = 'by_hearts';
    return $cols;
}

4. Sort based on comment meta

This is where the problems start, something needs to change in the following code which when tested independently, returns a sorted list of comments as intended:

add_action( 'pre_get_comments', 'hearts_orderby' );
function hearts_orderby( $comments_query ) {
    $orderby = $comments_query->query_vars['orderby'];
 
    if( 'by_hearts' == $orderby ) {
        $comments_query->query(array( 
            'meta_key' => 'hearts',
            'orderby' => 'meta_value_num'
        ));         
    }
}

Critical Error when clicking on the column's title "Hearts" to sort the column. Redirection to an empty page with the following message: Critical Error when clicking on the column's title "Hearts" to sort the column.

Things tried

The code below gives no errors, the comments are listed but are not sorted. If i remove the code below entirely, the result is the same. The code is based on the last snippet of this page.

add_action( 'pre_get_comments', 'hearts_orderby' );
function hearts_orderby( $comments_query ) {
    $orderby = $comments_query->query_vars['orderby'];
 
    if( 'by_hearts' == $orderby ) {
        $comments_query->set('meta_key','hearts');
        $comments_query->set('orderby','meta_value_num');   
    }
}

Questions

  1. Is it possible to somehow alter the hearts_orderby() function in the 4th step to get the desired outcome?
  2. Is it possible to use a different hook in the 4th step?

1 Answer 1

2

Is it possible to use a different hook in the 4th step?

Yes, see parse_comment_query which is also an action hook, but it fires before pre_get_comments.

Is it possible to somehow alter the hearts_orderby() function in the 4th step to get the desired outcome?

Yes.

But first off, you should know that unlike the WP_Query class, WP_Comment_Query does not (currently) have a set() method, so despite calling $comments_query->set() did not cause any error, the meta_key and orderby args were never actually set.

( WP_Comment_Query has a magic __call() method, hence calling non-existent methods such as the set() would simply return false without doing anything else )

Now to make your function works, just set the meta query via direct modification on the $comments_query->query_vars array like so:

if( 'by_hearts' == $orderby ) {
    $comments_query->query_vars['meta_key'] = 'hearts';
    $comments_query->query_vars['orderby'] = 'meta_value_num';
}

If, however, you want to include comments without the hearts meta, then you can instead use the meta_query arg:

$meta_query = isset( $comments_query->query_vars['meta_query'] ) ?
    (array) $comments_query->query_vars['meta_query'] : array();

$meta_query[] = array(
    'relation'  => 'OR',

    // Include comments having the meta.
    // Match the array key with the $orderby value.
    'by_hearts' => array(
        'key'  => 'hearts',
        'type' => 'NUMERIC',
    ),

    // Include comments without the meta.
    'no_hearts' => array(
        'key'     => 'hearts',
        'compare' => 'NOT EXISTS',
    ),
);

$comments_query->query_vars['meta_query'] = $meta_query;
1
  • Hello again, just tried your first snippet and it worked. I had given up on that implementation because when tested independently, it didn't work: $comments_query = new WP_Comment_Query(); $comments_query->query_vars['meta_key'] = 'hearts'; $comments_query->query_vars['orderby'] = 'meta_value_num'; $comments = $comments_query->comments; maybe it is because the query here happens at the first line and the query_vars change afterwards, while in the pre_get_comments callback the query hasn't happened yet. Thanks for the detailed answer!
    – PantelD
    Aug 30, 2021 at 19:35

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.