This tutorial gives code to display a 5 star rating option in HTML. The HTML view shows a question-answer model with a clickable 5 star rating.
In a previous article, we have seen how to create a PHP star rating system in JavaScript. This tutorial example creates a dynamic star rating for an answer list from the database.
View demo
This step is to display the data for which the star rating is applicable. This HTML code displays the question and answers to the web page.
It has a textarea to allow inserting more answers to the question.
index.php
<?php
ini_set("display_errors", 1);
require_once __DIR__ . '/lib/QAModel.php';
$userId = 3; // Replace it with the authenticated user id
$QAModel = new QAModel();
$questionResult = $QAModel->getQuestion();
$questionId = $questionResult[0]["id"];
$answersResult = $QAModel->getAnswer();
?>
<!DOCTYPE html>
<html lang="en">
<head>
<title>Simple HTML 5 star rating code</title>
</head>
<body>
<div class="phppot-container">
<h1>Simple HTML 5 star rating code</h1>
<h2>
<?php echo $questionResult[0]['question']; ?>
</h2>
<?php require_once __DIR__ . '/answer-form.php'; ?>
<?php require_once __DIR__ . '/answer-list.php'; ?>
</body>
<script src="rating.js"></script>
</html>
On submitting the form to add new answer, it inserts the record and displays the answers in a descending order.
answer-form.php
<form method="post">
<div class="row">
<label for="answer"> Enter your answer:</label>
<textarea name="answer" id="answer" rows="6" class="full-width" required></textarea>
</div>
<div class="row">
<input type="submit" name="submit_answer" value="Post your answer">
</div>
<p class="validation-message" id="demo"> </p>
</form>
This code iterates the answerResult
array from the database. It shows the average rating added for the answer out of 5 stars.
The $starCount
variable shows the average rating of a record. And the userRatingCount is rating given the answer by the current user.
In this example it hardcodes a userId variable which is the place to plug in your authentication.
answer-list.php
<div class="answer-list">
<h2>Answers:</h2>
<?php
if (!empty($answersResult)) {
foreach ($answersResult as $row) {
$userRatingCount = 0;
$userRating = $QAModel->getUserRating($row['id'], $userId);
if (!empty($userRating)) {
$userRatingCount = $userRating[0]["star_count"];
}
?>
<div class="row answer-row">
<div class="answer">
<?php echo $row['answer']; ?>
</div>
<div>
<img src='images/star.svg' class="star-view">
<?php
$starCount = round($row["average_star_count"], 1);
echo $starCount . "/5";
require __DIR__ . "/star-rating-html.php";
?>
</div>
</div>
<?php
}
}
?>
</div>
The above answer-list.php
file includes thisĀ 5 star rating HTML. A container displays svg icon for stars by running a loop with length 5.
The SVG tag has the selectors and event callback attributes to trigger mouse events.
On clicking the HTML star, it sets it highlighted and submit the selected rating to PHP.
star-rating-html.php
<div class="rating-container">
<?php
for ($i = 1; $i <= 5; $i++) {
$starClassName = "";
if ($i <= $userRatingCount) {
$starClassName = "filled";
}
?>
<svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 24 24" class="star-link <?php echo $starClassName; ?>" stroke-width="1" stroke-linecap="round" stroke-linejoin="round" class="feather feather-star" onclick="setRating(this, <?php echo $row['id']; ?>, <?php echo $i; ?>)">
<polygon points="12 2 15.09 8.26 22 9.27 17 14.14 18.18 21.02 12 17.77 5.82 21.02 7 14.14 2 9.27 8.91 8.26 12 2"></polygon>
</svg>
<?php
} ?>
</div>
This allows highlighting the stars on select or on hover the HTML icon. It allow to turn the star icon to be filled with a yellow background.
The setRating()
function is added to the onClick
attribute of the star rating icons in the HTML code.
On document ready, the jQuery event registration for the star-link
hover effect is shown below.
rating.js
function setRating(starIcon, answerId, rating) {
$(starIcon).parent().find(".star-link").removeClass("filled");
$(starIcon).parent().find(".star-link:lt(" + (rating) + ")").addClass("filled");
submitRating(answerId, rating);
}
function submitRating(answerId, rating) {
$.ajax({
url: 'save_rating.php',
type: 'POST',
data: { 'rating': rating, 'answerId': answerId}
});
}
$(document).ready(function() {
$(".star-link").on("mouseover", function() {
var index = $(this).index();
$(this).parent().find(".star-link").each(function(loopIndex) {
if(loopIndex <= index) {
$(this).removeClass("hout");
$(this).addClass("hovered");
}
if(loopIndex > index) {
$(this).removeClass("hovered");
$(this).addClass("hout");
}
});
});
$(".rating-container").on("mouseout", function() {
$(".star-link").removeClass("hout");
$(".star-link").removeClass("hovered");
});
});
On clicking the star icons below the answers, the added rating saved to the database using a server-side code.
This code checks if the current user already rated the particular article. If so, it will update only the star_count
. Otherwise, it will insert a new row on to the tbl_answer_rating
table.
save_rating.php
<?php
session_start();
require_once __DIR__ . '/lib/QAModel.php';
$QAModel = new QAModel();
if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['rating']) && isset($_POST['answerId'])) {
$rating = $_POST['rating'];
$answerId = $_POST['answerId'];
$userId = 3;
$isStarRated = $QAModel->getUserRating($answerId, $userId);
if(empty($isStarRated)) {
$QAModel->insertRating($answerId, $userId, $rating);
} else {
$QAModel->updateRating($rating, $isStarRated[0]["id"]);
}
}
exit;
?>
The below model class prepares query to add or update star rating in the database. It stores user’s rating in the DB table to retrieve and show it in the view.
lib/QAModel.php
<?php
class QAModel
{
private $conn;
function __construct()
{
require_once 'DataSource.php';
$this->conn = new DataSource();
}
function getQuestion()
{
$sqlSelect = "SELECT * FROM tbl_question";
$result = $this->conn->select($sqlSelect);
return $result;
}
function getAnswer()
{
$sql = "SELECT a.*, AVG(ar.star_count) AS average_star_count FROM tbl_answer a LEFT JOIN tbl_answer_rating ar ON a.id = ar.ans_id GROUP BY a.id, a.answer ORDER BY a.id DESC";
$result = $this->conn->select($sql);
return $result;
}
function insertAnswer($answer, $user_id, $question_id)
{
$sql = "INSERT INTO tbl_answer (answer, user_id, question_id) VALUES (?,?,?)";
$paramType = "sii";
$paramArray = array($answer, $user_id, $question_id);
$result = $this->conn->insert($sql, $paramType, $paramArray);
return $result;
}
function insertRating($answerId, $userId, $rating)
{
$sql = "INSERT INTO tbl_answer_rating (ans_id, user_id, star_count) VALUES (?, ?, ?)";
$paramType = "iii";
$paramArray = array($answerId, $userId, $rating);
$result = $this->conn->insert($sql, $paramType, $paramArray);
if ($result === false) {
return;
}
return true;
}
function updateRating($rating, $ratingId)
{
$sql = "UPDATE tbl_answer_rating SET star_count = ? WHERE id = ?";
$paramType = "ii";
$paramArray = array($rating, $ratingId);
$result = $this->conn->execute($sql, $paramType, $paramArray);
if ($result === false) {
return;
}
return true;
}
function getUserRating($answerId, $userId)
{
$sql = "SELECT * FROM tbl_answer_rating WHERE ans_id = ? AND user_id = ?";
$paramType = "ii";
$paramArray = array($answerId, $userId);
$result = $this->conn->select($sql, $paramType, $paramArray);
return $result;
}
}
?>
The database script contains the table structure with some initial data for the question and answers.
sql/database.sql
--
-- Database: `db_question_answer_rating`
--
-- --------------------------------------------------------
--
-- Table structure for table `tbl_answer`
--
CREATE TABLE `tbl_answer` (
`id` int(11) NOT NULL,
`answer` varchar(255) NOT NULL,
`user_id` int(11) NOT NULL,
`question_id` int(11) NOT NULL,
`answered_at` timestamp NOT NULL DEFAULT current_timestamp(),
`star_count` int(11) DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
--
-- Dumping data for table `tbl_answer`
--
INSERT INTO `tbl_answer` (`id`, `answer`, `user_id`, `question_id`, `answered_at`, `star_count`) VALUES
(1, 'It is a concept of attributing metal states about desires, beliefs, emotions and all.', 2, 1, '2024-03-23 10:06:29', NULL),
(2, 'It is a concept of predicting the behaviour. And, it is a study of researching the similarities and differnces.', 2, 1, '2024-03-23 10:06:47', NULL);
-- --------------------------------------------------------
--
-- Table structure for table `tbl_answer_rating`
--
CREATE TABLE `tbl_answer_rating` (
`id` int(11) NOT NULL,
`ans_id` int(11) NOT NULL,
`user_id` int(11) NOT NULL,
`star_count` int(11) NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
-- --------------------------------------------------------
--
-- Table structure for table `tbl_question`
--
CREATE TABLE `tbl_question` (
`id` int(11) NOT NULL,
`question` varchar(255) NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
--
-- Dumping data for table `tbl_question`
--
INSERT INTO `tbl_question` (`id`, `question`) VALUES
(1, 'What is \'theory of mind\' in the context of understanding the intelligence of apes and human?');
--
-- Indexes for dumped tables
--
--
-- Indexes for table `tbl_answer`
--
ALTER TABLE `tbl_answer`
ADD PRIMARY KEY (`id`),
ADD KEY `fk_question_id` (`question_id`) USING BTREE;
--
-- Indexes for table `tbl_answer_rating`
--
ALTER TABLE `tbl_answer_rating`
ADD PRIMARY KEY (`id`),
ADD KEY `fk_ans_id` (`ans_id`) USING BTREE;
--
-- Indexes for table `tbl_question`
--
ALTER TABLE `tbl_question`
ADD PRIMARY KEY (`id`);
--
-- AUTO_INCREMENT for dumped tables
--
--
-- AUTO_INCREMENT for table `tbl_answer`
--
ALTER TABLE `tbl_answer`
MODIFY `id` int(11) NOT NULL AUTO_INCREMENT, AUTO_INCREMENT=7;
--
-- AUTO_INCREMENT for table `tbl_answer_rating`
--
ALTER TABLE `tbl_answer_rating`
MODIFY `id` int(11) NOT NULL AUTO_INCREMENT;
--
-- AUTO_INCREMENT for table `tbl_question`
--
ALTER TABLE `tbl_question`
MODIFY `id` int(11) NOT NULL AUTO_INCREMENT, AUTO_INCREMENT=2;
--
-- Constraints for dumped tables
--
--
-- Constraints for table `tbl_answer`
--
ALTER TABLE `tbl_answer`
ADD CONSTRAINT `tbl_answer_ibfk_1` FOREIGN KEY (`question_id`) REFERENCES `tbl_question` (`id`) ON DELETE CASCADE;
--
-- Constraints for table `tbl_answer_rating`
--
ALTER TABLE `tbl_answer_rating`
ADD CONSTRAINT `tbl_answer_rating_ibfk_1` FOREIGN KEY (`ans_id`) REFERENCES `tbl_answer` (`id`) ON DELETE CASCADE;