Add ratings to the WordPress comment system.

Star ratings are a quick and simple way to get feedback from your users, that’s why it has become so popular all around the web. Today we’ll extend WordPress comments by adding our own star rating system.

The main plugin file

Let’s create the main file that will contain most of our plugin’s code. Using an FTP client navigate to /wp-content/plugins/ in your WordPress installation and create a folder called ci-comment-rating (or anything else you prefer). Next enter the folder and create a file called ci-comment-rating.php (again, naming is up to you).

Edit the file and paste in a header similar to the one below:

<?php
/*
Plugin Name: CI Comment Rating
Description: Adds a star rating system to WordPress comments
Version: 1.0.0
Author: The CSSIgniter Team
Author URI: https://cssigniter.com/
*/
Plugin header

Creating the rating interface.

First we will need to create the interface which the visitor uses to rate our post. To do that paste the code below in the plugin’s file.

//Create the rating interface.
add_action( 'comment_form_logged_in_after', 'ci_comment_rating_rating_field' );
add_action( 'comment_form_after_fields', 'ci_comment_rating_rating_field' );
function ci_comment_rating_rating_field () {
	?>
	<label for="rating">Rating<span class="required">*</span></label>
	<fieldset class="comments-rating">
		<span class="rating-container">
			<?php for ( $i = 5; $i >= 1; $i-- ) : ?>
				<input type="radio" id="rating-<?php echo esc_attr( $i ); ?>" name="rating" value="<?php echo esc_attr( $i ); ?>" /><label for="rating-<?php echo esc_attr( $i ); ?>"><?php echo esc_html( $i ); ?></label>
			<?php endfor; ?>
			<input type="radio" id="rating-0" class="star-cb-clear" name="rating" value="0" /><label for="rating-0">0</label>
		</span>
	</fieldset>
	<?php
}

The code above will take care of placing the rating system in the comment form, for both logged in and logged out users. This is what you it will look like after you add the code:

Not very pretty, right? Let’s fix that.

Adding some styling

We will need some stars, after all it’s a star rating system, so we will need to enqueue dashicons on the frontend as well. Along with that we will need to create an assets folder in the plugin’s main folder and inside it create a style.css file.  Edit the style.css file and paste in the code below.

.comments-rating {
	border: none;
	padding: 0;
	margin-left: 0;
}

.comments-rating label {
	display: inline-block;
}

.rating-container {
	/* remove inline-block whitespace */
	font-size: 0;
	/* flip the order so we can use the + and ~ combinators */
	unicode-bidi: bidi-override;
	direction: rtl;
}

.rating-container * {
	font-size: 1.4rem;
}

.rating-container > input {
	display: none;
}

.rating-container > input + label {
	/* only enough room for the star */
	font-family: 'dashicons';
	display: inline-block;
	overflow: hidden;
	text-indent: 9999px;
	width: 1em;
	white-space: nowrap;
	cursor: pointer;
	margin: 0;
}

.rating-container > input + label:before {
	display: inline-block;
	text-indent: -9999px;
	content: "\f154";
	color: #888;
}

.rating-container > input:checked ~ label:before,
.rating-container > input + label:hover ~ label:before,
.rating-container > input + label:hover:before {
	content: "\f155";
	color: #e52;
	text-shadow: 0 0 1px #333;
}

.rating-container > .star-cb-clear + label {
	text-indent: -9999px;
	width: .5em;
	margin-left: -.5em;
}

.rating-container > .star-cb-clear + label:before {
	width: .5em;
}

.rating-container:hover > input + label:before {
	content: "\f154";
	color: #888;
	text-shadow: none;
}

.rating-container:hover > input + label:hover ~ label:before,
.rating-container:hover > input + label:hover:before {
	content: "\f155";
	color: #e52;
	text-shadow: 0 0 1px #333;
}

.comment-respond .rating-container > .star-cb-clear + label, .comment-respond .rating-container > input + label:before {
	text-indent: 9999px;
}

.comment-respond .rating-container > input + label {
	text-indent: -9999px;
}

Next go back to the ci-comment-rating.php file and paste this in:

//Enqueue the plugin's styles.
add_action( 'wp_enqueue_scripts', 'ci_comment_rating_styles' );
function ci_comment_rating_styles() {

	wp_register_style( 'ci-comment-rating-styles', plugins_url(/,__FILE__) . 'assets/style.css' );

	wp_enqueue_style( 'dashicons' );
	wp_enqueue_style( 'ci-comment-rating-styles' );
}

We start by registering the style.css file we created earlier, then we enqueue both the dashicons and the stylesheet. Now let’s save and refresh the page.

Ah, much better!

Saving the user’s input

We have successfully created the interface the user can use to rate our post, next we need to make sure the rating is stored in our database. To do that we will use add_comment_meta to create a custom field in the comments which will store our rating data. Paste the code below in the plugin’s main file.

//Save the rating submitted by the user.
add_action( 'comment_post', 'ci_comment_rating_save_comment_rating' );
function ci_comment_rating_save_comment_rating( $comment_id ) {
	if ( ( isset( $_POST['rating'] ) ) && ( '' !== $_POST['rating'] ) )
	$rating = intval( $_POST['rating'] );
	add_comment_meta( $comment_id, 'rating', $rating );
}

In the code above we hook into comment_post which fires exactly after a comment is submitted. We check to see if the user added a rating, sanitize it, and store it in the database.

Making the rating required (optional)

If you want to have the users always submit a rating along with their comments you can paste this in the plugin’s main file.

//Make the rating required.
add_filter( 'preprocess_comment', 'ci_comment_rating_require_rating' );
function ci_comment_rating_require_rating( $commentdata ) {
	if ( ! is_admin() && ( ! isset( $_POST['rating'] ) || 0 === intval( $_POST['rating'] ) ) )
	wp_die( __( 'Error: You did not add a rating. Hit the Back button on your Web browser and resubmit your comment with a rating.' ) );
	return $commentdata;
}

Here we check if there is a rating in the submitted comment’s data, and if not we output an error prompting the user to go back and resubmit along with a rating. This is of course optional.

TIP: if you don’t want to make the rating required consider removing the

<span class="required">*</span>

bit from the rating interface above. This will remove the visual cue that rating is required.

Display  the rating on a submitted comment

Once a user has rated our post we should display that rating along with their comment. To do that paste the code below in the plugin’s main file.

//Display the rating on a submitted comment.
add_filter( 'comment_text', 'ci_comment_rating_display_rating');
function ci_comment_rating_display_rating( $comment_text ){

	if ( $rating = get_comment_meta( get_comment_ID(), 'rating', true ) ) {
		$stars = '<p class="stars">';
		for ( $i = 1; $i <= $rating; $i++ ) {
			$stars .= '<span class="dashicons dashicons-star-filled"></span>';
		}
		$stars .= '</p>';
		$comment_text = $comment_text . $stars;
		return $comment_text;
	} else {
		return $comment_text;
	}
}

What we do here, is hook into comment_text, check if there is an actual rating on the post, if there is we generate some markup that will display it and return it along the comment’s text. If there is no rating we just return the comment’s text.

Job done!

That’s pretty much it, we have created a simple plugin that will add a star rating system on WordPress comments.

Extending the plugin

Now that you have the data, you can utilize it in any way you wish by extending the plugin a bit. For example let’s get a post’s average rating and display it above the content.

In the plugin’s main file paste this in.

//Get the average rating of a post.
function ci_comment_rating_get_average_ratings( $id ) {
	$comments = get_approved_comments( $id );

	if ( $comments ) {
		$i = 0;
		$total = 0;
		foreach( $comments as $comment ){
			$rate = get_comment_meta( $comment->comment_ID, 'rating', true );
			if( isset( $rate ) && '' !== $rate ) {
				$i++;
				$total += $rate;
			}
		}

		if ( 0 === $i ) {
			return false;
		} else {
			return round( $total / $i, 1 );
		}
	} else {
		return false;
	}
}

This function will get the ID of a post, run through all of the approved comments, sum up the existing ratings and return the average rounded up to the first decimal. If there are no ratings on the tested post it will return false.

To display the average comment rating above the post’s content we can use this code:

//Display the average rating above the content.
add_filter( 'the_content', 'ci_comment_rating_display_average_rating' );
function ci_comment_rating_display_average_rating( $content ) {

	global $post;

	if ( false === ci_comment_rating_get_average_ratings( $post->ID ) ) {
		return $content;
	}
	
	$stars   = '';
	$average = ci_comment_rating_get_average_ratings( $post->ID );

	for ( $i = 1; $i <= $average + 1; $i++ ) {
		
		$width = intval( $i - $average > 0 ? 20 - ( ( $i - $average ) * 20 ) : 20 );

		if ( 0 === $width ) {
			continue;
		}

		$stars .= '<span style="overflow:hidden; width:' . $width . 'px" class="dashicons dashicons-star-filled"></span>';

		if ( $i - $average > 0 ) {
			$stars .= '<span style="overflow:hidden; position:relative; left:-' . $width .'px;" class="dashicons dashicons-star-empty"></span>';
		}
	}
	
	$custom_content  = '<p class="average-rating">This post\'s average rating is: ' . $average .' ' . $stars .'</p>';
	$custom_content .= $content;
	return $custom_content;
}

The code above will try to get the average rating using the function we created on the previous step, if it doesn’t get anything it will just return the content, otherwise it will place a paragraph, just above the post’s content, displaying the average post rating.

Wrapping up

That’s all for this tutorial, we hope you found it useful and if you come up with interesting ideas of extending the plugin and using the gathered data, please let us know in the comments below!

The complete plugin file

Below you will find the entire ci-comment-rating.php file which you can copy/paste into your plugin folder.

<?php
/*
Plugin Name: CI Comment Rating
Description: Adds a star rating system to WordPress comments
Version: 1.0.0
Author: The CSSIgniter Team
Author URI: https://cssigniter.com/
*/

//Enqueue the plugin's styles.
add_action( 'wp_enqueue_scripts', 'ci_comment_rating_styles' );
function ci_comment_rating_styles() {

	wp_register_style( 'ci-comment-rating-styles', plugins_url(/,__FILE__) . 'assets/style.css' );

	wp_enqueue_style( 'dashicons' );
	wp_enqueue_style( 'ci-comment-rating-styles' );
}

//Create the rating interface.
add_action( 'comment_form_logged_in_after', 'ci_comment_rating_rating_field' );
add_action( 'comment_form_after_fields', 'ci_comment_rating_rating_field' );
function ci_comment_rating_rating_field () {
	?>
	<label for="rating">Rating<span class="required">*</span></label>
	<fieldset class="comments-rating">
		<span class="rating-container">
			<?php for ( $i = 5; $i >= 1; $i-- ) : ?>
				<input type="radio" id="rating-<?php echo esc_attr( $i ); ?>" name="rating" value="<?php echo esc_attr( $i ); ?>" /><label for="rating-<?php echo esc_attr( $i ); ?>"><?php echo esc_html( $i ); ?></label>
			<?php endfor; ?>
			<input type="radio" id="rating-0" class="star-cb-clear" name="rating" value="0" /><label for="rating-0">0</label>
		</span>
	</fieldset>
	<?php
}

//Save the rating submitted by the user.
add_action( 'comment_post', 'ci_comment_rating_save_comment_rating' );
function ci_comment_rating_save_comment_rating( $comment_id ) {
	if ( ( isset( $_POST['rating'] ) ) && ( '' !== $_POST['rating'] ) )
	$rating = intval( $_POST['rating'] );
	add_comment_meta( $comment_id, 'rating', $rating );
}

//Make the rating required.
add_filter( 'preprocess_comment', 'ci_comment_rating_require_rating' );
function ci_comment_rating_require_rating( $commentdata ) {
	if ( ! is_admin() && ( ! isset( $_POST['rating'] ) || 0 === intval( $_POST['rating'] ) ) )
	wp_die( __( 'Error: You did not add a rating. Hit the Back button on your Web browser and resubmit your comment with a rating.' ) );
	return $commentdata;
}

//Display the rating on a submitted comment.
add_filter( 'comment_text', 'ci_comment_rating_display_rating');
function ci_comment_rating_display_rating( $comment_text ){

	if ( $rating = get_comment_meta( get_comment_ID(), 'rating', true ) ) {
		$stars = '<p class="stars">';
		for ( $i = 1; $i <= $rating; $i++ ) {
			$stars .= '<span class="dashicons dashicons-star-filled"></span>';
		}
		$stars .= '</p>';
		$comment_text = $comment_text . $stars;
		return $comment_text;
	} else {
		return $comment_text;
	}
}

//Get the average rating of a post.
function ci_comment_rating_get_average_ratings( $id ) {
	$comments = get_approved_comments( $id );

	if ( $comments ) {
		$i = 0;
		$total = 0;
		foreach( $comments as $comment ){
			$rate = get_comment_meta( $comment->comment_ID, 'rating', true );
			if( isset( $rate ) && '' !== $rate ) {
				$i++;
				$total += $rate;
			}
		}

		if ( 0 === $i ) {
			return false;
		} else {
			return round( $total / $i, 1 );
		}
	} else {
		return false;
	}
}

//Display the average rating above the content.
add_filter( 'the_content', 'ci_comment_rating_display_average_rating' );
function ci_comment_rating_display_average_rating( $content ) {

	global $post;

	if ( false === ci_comment_rating_get_average_ratings( $post->ID ) ) {
		return $content;
	}
	
	$stars   = '';
	$average = ci_comment_rating_get_average_ratings( $post->ID );

	for ( $i = 1; $i <= $average + 1; $i++ ) {
		
		$width = intval( $i - $average > 0 ? 20 - ( ( $i - $average ) * 20 ) : 20 );

		if ( 0 === $width ) {
			continue;
		}

		$stars .= '<span style="overflow:hidden; width:' . $width . 'px" class="dashicons dashicons-star-filled"></span>';

		if ( $i - $average > 0 ) {
			$stars .= '<span style="overflow:hidden; position:relative; left:-' . $width .'px;" class="dashicons dashicons-star-empty"></span>';
		}
	}
	
	$custom_content  = '<p class="average-rating">This post\'s average rating is: ' . $average .' ' . $stars .'</p>';
	$custom_content .= $content;
	return $custom_content;
}

34 comments

  1. Sia Seraf says:

    You are the Best!!!
    I spend so much time on pointless Plugins to do exactly what you’ve created. And then I found your Article from nowhere and works PERFECTLY…..Thank you for doing what you do and we – the people who are still learning – learning from people like you. I know I made you like a God but I’ve spend so much time on shitty Plugins and I’m really happy now…Thank you again :) :)

  2. Dee says:

    excellent !

  3. Dee says:

    Hi Nik, how do i create a general/universal rating and create short-code to include in custom post types ?

    thank you very much !

    1. Nik Vourvachis says:

      Hello Dee!

      The rating system is very simple, which, luckily, makes it universal. Any post type with a comments template will have the rating available. So if you have a custom post type that does not have comments, just edit the post type’s single template, add the comments template and you should be good to go.

  4. Cedar Mora says:

    If you are getting an error with the

    wp_register_style( ‘ci-comment-rating-styles’, plugins_url(/,__FILE__) . ‘assets/style.css’ );

    line on ci-comment-rating.php, changing the whole line to:

    wp_register_style( ‘ci-comment-rating-styles’, plugins_url() . ‘/ci-comment-rating/’ . ‘assets/style.css’ );

    may fix it for you.

  5. James says:

    Hello! This works perfectly. I would like to extend the plugin further by displaying the total number of reviews used to calculate the average, and have tried a new function but am calculating something greater than the total number.

    For example, an average rating of 3.5 might use a total of 2 or 2,000 reviews. I’d like to output that part to add context to the rating. Thank you!

    1. Nik Vourvachis says:

      Hello there!

      Glad to hear you found the post useful. Please check out this gist to implement the functionality you want.

      Specifically all changes have been done in the last two functions. ci_comment_rating_get_average_ratings was replaced by ci_comment_rating_get_ratings_data which now returns an array of the total number of reviews and their sum. ci_comment_rating_display_average_rating was modified to use that data to calculate an average and display the number of reviews used to get that average.

      Hope this helps!

  6. dameer.dj says:

    Unfortunately, this doesn’t work for comment replies.

    1. Nik Vourvachis says:

      Thank you for noticing!

      It was a styling issue due to the way WordPress handles comment replies. I have updated the styles in the style.css file and it should be ok now. Grab lines 77-83 from the style.css above and paste them in your existing one. That should do the trick.

  7. Tim says:

    This post is now 7 months old and doesn’t appear to work anymore? I’m getting this error when trying to activate it: “Parse error: syntax error, unexpected ‘/’ in /var/www/vhosts/72brain.com/httpdocs/wordpress/wp-content/plugins/ci-comment-rating/ci-comment-rating.php on line 14”

  8. Tim says:

    Looks like you need quotation marks around the / on line 14.

    plugins_url(/,__FILE__

    should be

    plugins_url(‘/’,__FILE__

    1. Nik Vourvachis says:

      Hello Tim.

      I’m not really sure as to why you got an error.
      If you check the code above you will see that the quotation marks are there, and they were there since the beginning.

  9. Sachin Ghare says:

    Such a Nice Plugin and cleverly made Nik. You are Awesome.

    But what i need is i want to make this one can be rate by guest users (outside comments section). This should be at the end of the post where every visitor can rate this. Also if it can show total no. of ratings made and overall average rating then would be great.

    Once you help me with this will post entire updated code as i have implemented some schema structured within code for SEO

    Regards
    Sachin G.

    1. Nik Vourvachis says:

      Hello Sachin.

      Glad to hear you like the plugin. What you are looking for is a completely different plugin, you can try having a look at GD Rating or any other post rating plugin on the WordPress plugin directory to help you achieve your goal.

  10. Heiko says:

    Hi Nik,

    I like this solution a lot! It works like a charm and is much lighter than all other full-blown rating solutions for WordPress.

    One single thing would be great: is there a chance for a non-development guy like me to display the average rating on any other place? I’d like to include it in a big header image and by now I can only display the rating directly above the content.

    1. Nik Vourvachis says:

      Hello Heiko.

      I’m happy to hear you find this small plugin useful.
      Regarding to your question, I’m afraid there is no easy way to do that without some development background. The output is now hooked to the post’s content, what you would need to do is unhook it from there and hook it to your theme’s header to overlay it on an image, however this requires your theme to have a hook on the header, if not one needs to be added there.

  11. Vladimir Ilic says:

    Thank you very much, awesome plugin!

  12. Thomas says:

    Hi there,

    Improvement suggestion: Instead of calculating the average rating on each post view, saving it in a custom field would be more efficient (once lots of comments with ratings are used).

    Cheers,
    Thomas

    1. Nik Vourvachis says:

      This is a great suggestion Thomas. Indeed it would be better performance-wise if the value was stored instead of being calculated on the fly.
      What we aimed to create was a base for a commenting system on which users could built-upon using their improvements, so we kept it pretty basic, simple and functional. If it where to become a full fledged plugin, it goes without saying that storing the value is better.

  13. Ajay says:

    Thanks a lot. You may update the line 14 in “The complete plugin file”
    It has / instead of ‘/’ which gives error and might confuse people.

    Also, can this plugin work with social/disqus comments

    1. Nik Vourvachis says:

      Hello Ajay.

      This is how I see line 14 on my end http://bit.ly/2OqEuCX do you see something different?

      Unfortunately no, it will only work on the default WordPress comments system.

  14. John says:

    Created ci-comment-rating directory in wp-content/plugins. Clicked on directory and created file called ci-comment-rating.php. Proceeded to enter header info and php code for //Create the rating interface. Permissions set to 755
    Plugin does show in WP plugins page. When I go to activate, I get “Plugin could not be activated because it triggered a fatal error.”
    Also tried pasting full code listed in “The complete plugin file”. I did not create style.css because it would not make difference if plugin did not work.
    Am I missing something here?

    1. Nik Vourvachis says:

      Hello John.

      Since it appears you know your way around server file management, could you please check your debug log file and see if there is an entry for said error?

      Thank you.

  15. Amit raj says:

    Hii there,

    I just want to add custom rating symbols instead of star for a particular category.For example if the category is of food then the post inside food category will have ice cream as an rating symbol. Plz help me out.

    1. Nik Vourvachis says:

      Hello Amit.

      This could be a bit tricky to implement. Our sample plugin uses icons from the Dashicons set included with WordPress. You could replace the content bits in the style.css file, i.e. content: "\f155"; with the content for another icon, for example \f155 is for the full star icon, it could be replaced with \f511 which is a carrot. However this would be global, there is currently no way to set a different icon per post category I’m afraid.

  16. Aure says:

    Hi there, thanks for code, i have a little proble when admin have to reply a comment.
    it checks for rating in administration page.. so it is imposible for an admin to live a reply in admin page, we have to go to post and reply there and make a rating.

    Is any way to not check if is rating in a post for admin only? thanks, best regards.

    1. Nik Vourvachis says:

      Hello.

      Excellent observation. I have patched the plugin file, now administrators should be able to reply without adding ratings from the dashboard. Replace line 48 in your plugin file with the one found in the article’s full plugin file, it should do the trick.

      1. Aure says:

        many thanks, i do it like this days before..
        “function ci_comment_rating_require_rating( $commentdata ) {
        if ( ! isset( $_POST[‘rating’] ) || 0 === intval( $_POST[‘rating’] ) )
        wp_die( __( ‘Error: You did not add a rating. Hit the Back button on your Web browser and resubmit your comment with a rating.’ ) );
        return $commentdata;
        }
        if( !is_admin() ){
        add_filter( ‘preprocess_comment’, ‘ci_comment_rating_require_rating’ );
        }”
        is it the same result as you wrote?

        I have a bit tricky question now, i think, how to return meta rating as a query string in url for reorder posts from average? Im trying to do it, but not get results atm, hope you can help on this too.. thanks, best regards!

        1. Nik Vourvachis says:

          Glad to hear you figured this out, what you did is pretty much the same thing. For your other question, have a look a this pretty thorough guide on query variables.

  17. ryan says:

    Sir, thanks for providing such wonderful step-by-step tutorial for us newbie, I just wonder if I can fix the code to be able to be commented by anyone(no need to login)? and furthermore, if I can add rating star from multiple perspective, like review A, review B, review C, review D…. all with star review, thanks in advance for your tutoring~

    1. Nik Vourvachis says:

      Hello Ryan.

      Glad to hear you found the tutorial helpful. Allowing people to comment without being logged in is a WordPress feature. Just navigate to Settings -> Discussion -> Other comment settings and uncheck the “Users must be registered and logged in to comment” box, that should do the trick.
      Could you please explain more the second part of your question?
      Thank you.

  18. Tonton says:

    Nice job thank you !

  19. Jarda says:

    Hello, thank you. How do this for google rich snippet? (stars in google search result)

    1. Nik Vourvachis says:

      Hello. Unfortunately there is no easy way of doing this at the moment. You would need to store each post’s average rating as post meta and then find a rich snippet plugin that accepts and displays custom meta.

Leave a Reply

Your email address will not be published. Required fields are marked *