1. Code
  2. JavaScript
  3. jQuery

Building a 5-Star Rating System With jQuery, AJAX, and PHP

Scroll to top

A star rating system on a website makes it easy for users to give their feedback and help others make choices. It gives businesses feedback on how customers like their products. Star ratings also help build trust in a website and its products.

All major eCommerce websites use ratings to let buyers know what kind of quality they can expect from a product.

In this tutorial, I will show you how to build a five-star rating system of your own.

Writing the HTML and CSS for the Structure

The first step in the process of building our star rating system is writing the markup, and that will depend on what element we want to show on the page.

We definitely want to include the name of the movie in our rating widget. We also need to show five stars inside the widget which users will be able to click in order to vote. We will also display the voting data to users once they have voted.

The following HTML achieves all this:

1
<div class="rating-wrapper" data-id="raiders">
2
  <h2>Raiders of the Lost Ark</h2>
3
  <div class="star-wrapper">
4
    <i class="fa-regular fa-star"></i>
5
    <i class="fa-regular fa-star"></i>
6
    <i class="fa-regular fa-star"></i>
7
    <i class="fa-regular fa-star"></i>
8
    <i class="fa-regular fa-star"></i>
9
  </div>
10
  <p class="v-data">Voting Data</p>
11
</div>

I am using the Font Awesome library to add the stars. We want the stars to have a black stroke and no fill by default. The fa-regular class does that for us.

We also want to change the color of the stars to something yellowish when users hover over them and to orange when users click on them to indicate that their ratings have been recorded. The following CSS accomplishes all this for us:

1
div.rating-wrapper {
2
  display: flex;
3
  align-items: first baseline;
4
  flex-direction: column;
5
  margin: 5rem;
6
  font-size: 1.5rem;
7
}
8
9
div.star-wrapper {
10
  font-size: 2rem;
11
}
12
13
div.star-wrapper i {
14
  cursor: pointer;
15
}
16
17
div.star-wrapper i.yellow {
18
  color: #FDD835;
19
}
20
21
div.star-wrapper i.vote-recorded {
22
  color: #F57C00;
23
}
24
25
p.v-data {
26
  background: #ccc;
27
  padding: 0.5rem;
28
}

Writing the jQuery for Interactivity

We will now use some jQuery to respond to user events. There are two events that we want to track on our stars.

Let's begin with the mouseover event, which will turn the star we are hovering over and all its preceding siblings yellow. However, this is only supposed to happen if the users haven't already clicked on a star to register their votes. We will be manipulating classes of the Font Awesome star icons to achieve this.

Here is the code we need:

1
$("div.star-wrapper i").on("mouseover", function () {
2
  if ($(this).siblings("i.vote-recorded").length == 0) {
3
    $(this).prevAll().addBack().addClass("fa-solid yellow").removeClass("fa-regular");  
4
    $(this).nextAll().removeClass("fa-solid yellow").addClass("fa-regular");
5
  }
6
});

We use the if statement to check if there are any siblings of the star we are currently hovering with the class vote-recorded attached to them. The presence of any such elements indicates that the vote has already been recorded. We do not do any class manipulation in this case.

However, if the vote has not been recorded, we take the current element and all the previous siblings of the element and add the fa-solid and yellow classes to them. We also remove these classes from all the siblings that follow the current element.

Now, we will write the jQuery code that handles the click event. Whenever a user clicks on, let's say, the fourth star, we know that they want to give the movie a rating of four stars. So we record the number of previous siblings and add one to get the rating. We also record the movie_id to add the ratings to the right movie.

1
$("div.star-wrapper i").on("click", function () {
2
  let rating = $(this).prevAll().length + 1;
3
  let movie_id = $(this).closest("div.rating-wrapper").data("id");
4
  
5
  if ($(this).siblings("i.vote-recorded").length == 0) {
6
    
7
    $(this).prevAll().addBack().addClass("vote-recorded");
8
    $.post("update_ratings.php", { movie_id: movie_id, user_rating: rating }).done(
9
      function (data) {
10
        parent_div.find("p.v-data").text(data);
11
      }
12
    );
13
    
14
  }
15
});

We again do a check to see if a vote has already been recorded for this particular movie. If no vote has been recorded already, we add the vote-recorded class to the current clicked element and all its previous siblings.

We also use the jQuery post() method to send our voting data to the back end using a POST request. The first parameter is the URL of the PHP script that will process our request, while the second parameter is the data that we want to process.

We also provide a callback within done() to further work with the data that is sent to us from the server after successfully processing our request.

The following CodePen demo shows what the front end looks like for our rating system:

Writing the PHP to Record Votes

We will store our vote records in the back end using a MySQL database. You can use whatever application you prefer to manage your database. I am using phpMyAdmin. The first step here is creating a database, which I have named rating_test. We will now create a table within the database called movie_ratings. Run the following SQL query on your database to create the table:

1
CREATE TABLE `movie_ratings`(
2
    `id` INT(11) NOT NULL AUTO_INCREMENT,
3
    `movie_id` VARCHAR(128) NOT NULL DEFAULT '',
4
    `average_rating` DOUBLE NOT NULL DEFAULT 0,
5
    `total_votes` DOUBLE NOT NULL DEFAULT 0,
6
    PRIMARY KEY(`id`)
7
) ENGINE = InnoDB DEFAULT CHARSET = utf8;

Executing the above statement will create a table named movie_ratings with four different columns.

The first one is an auto-incrementing id that serves as the primary key for each record we add to the table. The second one is the movie_id, which will identify a movie and can contain up to 128 characters. The third one is the average_rating to store the average of all votes so far. The fourth one, total_votes, is the one which keeps track of the total number of votes that have been cast.

Look back again at the first parameter of the post() method in the previous section. You will see the string update_ratings.php, which is the file that we need to create now. This file will contain the PHP code that updates and records the movie ratings.

1
$movie_id = $_POST['movie_id'];
2
$user_rating = $_POST['user_rating'];
3
4
$mysqli = new mysqli('localhost', 'root', '', 'rating_test');
5
6
if ($mysqli->connect_errno) {
7
    die("Error while connecting: " . $mysqli->connect_error);
8
}

We begin by using $_POST to get the POST data and then create a new mysqli object to establish a connection to the database. We then check the value of connect_errno to see if there was an error during our database connection call.

1
$rating_query = $mysqli->query("SELECT * from `movie_ratings` WHERE `movie_id` = '$movie_id'");
2
$rating_query_rows = mysqli_num_rows($rating_query);
3
4
if($rating_query_rows == 0) {
5
    $mysqli->query("INSERT INTO `movie_ratings` (`movie_id`, `average_rating`, `total_votes`) VALUES ('$movie_id', $user_rating, 1)");
6
7
    echo "Average Rating: $user_rating Total Votes: 1";
8
} else {
9
10
    $rating_data = $rating_query->fetch_array(MYSQLI_ASSOC);
11
12
    $total_votes = $rating_data['total_votes'];
13
    $average_rating = $rating_data['average_rating'];
14
15
    $rating_sum = $average_rating*$total_votes + $user_rating;
16
17
    $total_votes += 1;
18
    $new_average_rating = round($rating_sum/($total_votes), 2);
19
20
    $mysqli->query("UPDATE `movie_ratings` SET `average_rating` = $new_average_rating, `total_votes` = $total_votes  WHERE `movie_id` = '$movie_id'");
21
22
    echo "Average Rating: $new_average_rating Total Votes: $total_votes";
23
}

Once the connection has been established, we run our first query to see if there is already a row for the movie whose ratings we want to update.

If there is no such movie, we run another query to insert the movie in the table. Since this is the first vote that was cast for the movie, we set the total number of votes to 1.

However, if there is already a row in the table with our passed movie_id, we get the total number of votes and the current average ratings for the movie from that row. After that, we calculate the new ratings and update the database accordingly.

Finally, we echo the new value of the average rating and total votes to display them to users.

Final Thoughts

For the sake of simplicity, this isn't a 100% complete solution. To extend this project, we should store a cookie to make sure people only vote once, or even record the IP address. It is, however, a great start, and is more than suitable for keeping track of votes on items like blog posts, comments, and images on your website.

Did you find this post useful?
Want a weekly email summary?
Subscribe below and we’ll send you a weekly email summary of all new Code tutorials. Never miss out on learning about the next big thing.
Looking for something to help kick start your next project?
Envato Market has a range of items for sale to help get you started.