Making shortcode of filtered number of comments by user role

The code below adds the counts for user roles. It’s commented pretty well to explain what’s happening. It should give you a good starting point for further customization (maybe you want to hide 0 counts, change the HTML output, etc.).

function comments_shortcode($atts) {

    $current_user = wp_get_current_user();

    extract( shortcode_atts( array(
                    'id' => ''
    ), $atts ) );
    $num = 0;
    $post_id = $id;
    $queried_post = get_post($post_id);
    $cc = $queried_post->comment_count;
                    if( $cc == $num || $cc > 1 ) : $cc = $cc.' Comments';
                    else : $cc = $cc.' Comment';
                    endif;
    $permalink = get_permalink($post_id);


    // Get all approved comments for this post.
    $args = array(
            'status'  => 'approve',
            'post_id' => get_the_id(),
    );
    $comments = get_comments( $args );

    // Get all roles in the system.
    // https://developer.wordpress.org/reference/functions/wp_roles/
    $all_roles = wp_roles();

    // Create an associative array.
    // Key is the role name, value holds human readable name and comment count.
    $comment_counts = array ();
    foreach ( $all_roles->role_names as $role_name => $role_nice_name ) {
        $comment_counts[ $role_name ] = array (
            'nice_name'     => $role_nice_name,
            'comment_count' => 0,
        );
    }   

    // Iterate over all comments for this post. Exlude trackbacks, pingbacks, and non-user comments.
    foreach ( $comments as $comment ) {
        // Exclude trackbacks and pingbacks
        if ( '' !== $comment->comment_type ) {
            continue;
        }

        if ( 0 === $comment->user_id ) { // Exclude comments from non-users
            continue;
        }   else { // Real user has commented...

            $comment_author = get_user_by( 'id', $comment->user_id );
            if ( $comment_author ) {
                // Users can be assigned multiple roles, although that is ideally not done in practice.
                foreach ( $comment_author->roles as $role ) {
                    $comment_counts[ $role ]['comment_count']++;
                }
            }
        }
    }

    // Create the HTML output.
    $comment_count_output="<h3>Comment Counts by Role</h3>";
    $comment_count_output .= '<ul>';
    foreach ( $comment_counts as $role => $role_data ) {
        $comment_count_output .= '<li><strong>' . esc_html( $role_data['nice_name'] ) . '</strong>: <span>'. esc_html( (string) $role_data['comment_count'] ) . '</span></li>';
    }
    $comment_count_output .= '</ul>';

    return '<a href="'. $permalink . '" class="comments_link">' . $cc . '</a>' . $comment_count_output;
}
add_shortcode('comments', 'comments_shortcode');

Example output:

24 Comments

Comment Counts by Role

  • Administrator: 3
  • Editor: 0
  • Author: 0
  • Contributor: 0
  • Subscriber: 4
  • Customer: 0
  • Shop Manager: 0
  • Employer: 0

Notes:

Commenters are not necessarily registered users, so the total comment count won’t always equal the sum of all comments by each role.

If a user leaves multiple comments, the comment count for their role(s) will be increased for each comment they leave. There is no checking here to only count one comment per user, but you could add that pretty easily.

WordPress will technically allow users to have multiple roles. This code will work with that ill-advised use case. In those situations, for a given user, each assigned role’s comment count would be incremented by one for a single comment.