Quite often, we face the challenge to display comment replies in a proper way. Showing them chronologically does not fit our need sometimes. We may require showing them in such a way that the reply for each comment is below the actual comment itself. In other words, we can say we need a nested comment reply system or threaded comments. We want to build something similar to the following screenshot:
We can follow the same steps we did in the nested category section. However, this time, we will have some UI elements to give it a more realistic look. Let's assume that we have a table named comments with the following data and columns. For simplicity, we are not going into multiple table relationships. We are assuming that the usernames are stored in the same table with the comments:
Id |
comments |
username |
Datetime |
parentID |
postID |
1 |
First comment |
Mizan |
2016-10-01 15:10:20 |
0 |
1 |
2 |
First reply |
Adiyan |
2016-10-02 04:09:10 |
1 |
1 |
3 |
Reply of first reply |
Mikhael |
2016-10-03 11:10:47 |
2 |
1 |
4 |
Reply of reply of first reply |
Arshad |
2016-10-04 21:22:45 |
3 |
1 |
5 |
Reply of reply of reply of first reply |
Anam |
2016-10-05 12:01:29 |
4 |
1 |
6 |
Second comment |
Keith |
2016-10-01 15:10:20 |
0 |
1 |
7 |
First comment of second post |
Milon |
2016-10-02 04:09:10 |
0 |
2 |
8 |
Third comment |
Ikrum |
2016-10-03 11:10:47 |
0 |
1 |
9 |
Second comment of second post |
Ahmed |
2016-10-04 21:22:45 |
0 |
2 |
10 |
Reply of second comment of second post |
Afsar |
2016-10-18 05:18:24 |
9 |
2 |
Let's now write a prepared statement to fetch all the comments from a post. Then, we can construct an array similar to the nested category one:
$sql = "Select * from comments where postID = :postID order by parentID asc, datetime asc";
$stmt = $dbh->prepare($sql, array(PDO::ATTR_CURSOR => PDO::CURSOR_FWDONLY));
$stmt->setFetchMode(PDO::FETCH_OBJ);
$stmt->execute(array(':postID' => 1));
$result = $stmt->fetchAll();
$comments = [];
foreach ($result as $row) {
$comments[$row->parentID][] = $row;
}
Now, we have the array and all required data in it; we can now write a function that will call recursively to display the comment with proper indentations:
function displayComment(Array $comments, int $n) {
if (isset($comments[$n])) {
$str = "<ul>";
foreach ($comments[$n] as $comment) {
$str .= "<li><div class='comment'><span class='pic'>
{$comment->username}</span>";
$str .= "<span class='datetime'>{$comment->datetime}</span>";
$str .= "<span class='commenttext'>" . $comment->comment . "
</span></div>";
$str .= displayComment($comments, $comment->id);
$str .= "</li>";
}
$str .= "</ul>";
return $str;
}
return "";
}
echo displayComment($comments, 0);
Since we have added some HTML elements in the PHP code, we need some basic CSS to make it work. Here is the CSS code we have written to make it a clean design. Nothing fancy, but pure CSS to create the cascading effects and some basic styling for each section of the comment:
ul {
list-style: none;
clear: both;
}
li ul {
margin: 0px 0px 0px 50px;
}
.pic {
display: block;
width: 50px;
height: 50px;
float: left;
color: #000;
background: #ADDFEE;
padding: 15px 10px;
text-align: center;
margin-right: 20px;
}
.comment {
float: left;
clear: both;
margin: 20px;
width: 500px;
}
.datetime {
clear: right;
width: 400px;
margin-bottom: 10px;
float: left;
}
As mentioned earlier, we are not trying to make something complex here, just responsive, device friendly, and so on. We are assuming that you can integrate the logic in different parts of your application without any problem.
Here is the output from the data and the preceding code:
From the preceding two examples, we can see that it is very easy to create nested contents without having multiple queries or having a limitation of join statements for nesting. We do not even require a self-join to generate the nested data.