Counting Likes in PHP/OOP Tutorial

In this tutorial, I will show the simplest way to Count Likes of Posts in PHP and MySQL Database. Here, you will learn how to join a total count of rows from another table in a query. I will be providing a simple source code of a simple blog application that illustrate our main goal for this tutorial

About the Tutorial Application

The source code output a simple blog posting web application that allows the user to post content that is visible to other users. Each post contains a Thumbs Up or Like Icon that shows only an outline if the user hasn't liked the post yet while it displays the icon with filled color for the liked post. The total number of likes of each post is shown beside each like icon of the posts. Users don't need to register on the application. They can simply log in with a random user name and this feature is for demo purposes only.

Getting Started

In this tutorial, I used XAMPP v3.2.4 and Bootstrap v5 Framework on developing the source code. Kindly download the following so you can test the source code on your local machine. In my case, all CSS (Cascading Style Sheet) files are complied on a CSS directory while the JavaScript files are located at the JS directory.

You can download the Virtual Server and Library I used at:

After download installing the server and library. Open your XAMPP's Control Panel and start the Apache and the MySQL servers.

Creating the Database

Open yout preferred browser such as Chrome Browser. Next, browse localhost/phpmyadmin and create a new database naming dummy_db. Then, navigate the page at the SQL Page and copy/paste the following sql code on the given text field and click the "Go" button.

  1. CREATE TABLE `like_list` (
  2. `id` int(30) NOT NULL,
  3. `session_name` text NOT NULL,
  4. `post_id` int(30) NOT NULL
  5.  
  6. CREATE TABLE `post_list` (
  7. `id` int(30) NOT NULL,
  8. `title` text NOT NULL,
  9. `author` text NOT NULL,
  10. `content` text NOT NULL,
  11.  
  12. ALTER TABLE `like_list`
  13. ADD PRIMARY KEY (`id`),
  14. ADD KEY `post_id` (`post_id`);
  15.  
  16. ALTER TABLE `post_list`
  17. ADD PRIMARY KEY (`id`);
  18.  
  19. ALTER TABLE `like_list`
  20.  
  21. ALTER TABLE `post_list`
  22.  
  23. ALTER TABLE `like_list`
  24. ADD CONSTRAINT `post_id_fk_ll` FOREIGN KEY (`post_id`) REFERENCES `post_list` (`id`) ON DELETE CASCADE ON UPDATE NO ACTION;

Creating the Database Connection

Open your preferred text editor such as notepad++ or sublime text. Create a new PHP File naming db-connect.php and save it inside your source code folder. Then, copy/paste the PHP script below and save the file.

  1. <?php
  2.  
  3. $host = "localhost";
  4. $username = "root";
  5. $pw = "";
  6. $dbname = "dummy_db";
  7.  
  8. $conn = new mysqli($host, $username, $pw, $dbname);
  9. if(!$conn){
  10. die("Database connection failed. Error: " .$conn->error);
  11. }

Creating the Login Page Interface

Create a new PHP File on your text editor naming login.php and save it also to yout source code folder. Then, copy/paste the source code below and save the file. This contains the html scripts of the application's login page elements and PHP script for login form submission.

  1. <!--
  2. This is a simple Web App. This was developed for educational purposes only.
  3. Author: oretnom23
  4. -->
  5. <?php
  6. if(isset($_SESSION['session_name']) && !empty($_SESSION['session_name']))
  7. header("location: index.php");
  8. // Require/Include DB Connection
  9. require_once('./db-connect.php');
  10. if($_SERVER['REQUEST_METHOD'] == 'POST'){
  11. $_SESSION['session_name'] = $_POST['session_name'];
  12. header("location: index.php");
  13. }
  14. ?><!DOCTYPE html>
  15. <html lang="en">
  16.  
  17. <head>
  18. <meta charset="UTF-8">
  19. <meta http-equiv="X-UA-Compatible" content="IE=edge">
  20. <meta name="viewport" content="width=device-width, initial-scale=1.0">
  21. <title>PHP Counting Likes</title>
  22. <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.1.1/css/all.min.css" integrity="sha512-KfkfwYDsLkIlwQp6LFnl8zNdLGxu9YAA1QvwINks4PhcElQSvqcyVLLD9aMhXd13uQjoXtEKNosOWaZqXgel0g==" crossorigin="anonymous" referrerpolicy="no-referrer" />
  23. <link rel="stylesheet" href="./css/bootstrap.min.css">
  24. <script src="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.1.1/js/all.min.js" integrity="sha512-6PM0qYu5KExuNcKt5bURAoT6KCThUmHRewN3zUFNaoI6Di7XJPTMoT6K0nsagZKk2OB4L7E3q1uQKHNHd4stIQ==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
  25. <script src="./js/bootstrap.min.js"></script>
  26.  
  27. </head>
  28. <style>
  29. html, body{
  30. height:100%;
  31. width:100%;
  32. }
  33. main{
  34. height:calc(100%);
  35. width:calc(100%);
  36. display:flex;
  37. flex-direction:column;
  38. align-items:center;
  39. justify-content:center
  40. }
  41. </style>
  42. <body class="bg-gradient bg-dark bg-opacity-50">
  43. <script>
  44. start_loader()
  45. </script>
  46. <main>
  47. <div class="col-lg-12">
  48. <h1 class="fw-bolder text-center" id="project-title">PHP Counting Likes</h1>
  49. </div>
  50. <div class="col-lg-6 col-md-8 col-sm-12 col-xs-12">
  51. <div class="card rounded-0">
  52. <div class="card-header">
  53. <h4 class="card-title text-center">Login</h4>
  54. </div>
  55. <div class="card-body">
  56. <div class="container-fluid">
  57. <form action="login.php" method="POST">
  58. <div class="form-group">
  59. <label for="session_name" class="control-label">Username</label>
  60. <input type="text" class="form-control form-control-sm rounded-0" id="session_name" name="session_name" placeholder="jsmith" required="required">
  61. </div>
  62. <div class="form-group text-end my-3">
  63. <button class="btn btn-primary btn-sm bg-gradient-primary rounded-0">Login</button>
  64. </div>
  65. </form>
  66. </div>
  67. </div>
  68. </div>
  69. </div>
  70. </main>
  71. </body>
  72. </html>

Creating the Main Interface

Create a new PHP File on your text editor naming index.php and save it also on your source code folder. Copy/Paste the script below and save the file. This file contains the Main Page HTML Elements and other PHP scripts for the for database queries and processes.

  1. <!--
  2. This is a simple Web App. This was developed for educational purposes only.
  3. Author: oretnom23
  4. -->
  5. <?php
  6. if(!isset($_SESSION['session_name']) || (isset($_SESSION['session_name']) && empty($_SESSION['session_name'])))
  7. header("location: login.php");
  8. // Require/Include DB Connection
  9. require_once('./db-connect.php');
  10. if(isset($_GET['logout']) && $_GET['logout'] == 'true'){
  11. header("location:login.php");
  12. }
  13. if($_SERVER['REQUEST_METHOD'] == 'POST'){
  14. extract($_POST);
  15. $sql = "INSERT INTO `post_list` (`title`, `author`, `content`) VALUES ('{$conn->real_escape_string($title)}','{$conn->real_escape_string($session_name)}', '{$conn->real_escape_string($content)}')";
  16. $save= $conn->query($sql);
  17. if($save){
  18. echo "<script> alert('Post has been inserted successfully.'); location.replace('index.php'); </script>";
  19. }else{
  20. echo "<script> alert('Post has failed to insert. Error: '.$conn->error); location.replace('index.php'); </script>";
  21. }
  22. echo "<script> location.replace('index.php'); </script>";
  23. }
  24. if(isset($_GET['post_id'])){
  25. extract($_GET);
  26. $get = $conn->query("SELECT * FROM `like_list` where post_id = '{$post_id}' and session_name = '{$_SESSION['session_name']}'");
  27. if($get->num_rows > 0){
  28. $sql = "DELETE FROM `like_list` where post_id = '{$post_id}' and session_name = '{$_SESSION['session_name']}' ";
  29. }else{
  30. $sql = "INSERT INTO `like_list` set post_id = '{$post_id}', session_name = '{$_SESSION['session_name']}' ";
  31. }
  32. $process= $conn->query($sql);
  33. if($process){
  34. echo "<script> alert('Post Like has been updated.'); location.replace('index.php'); </script>";
  35. }else{
  36. echo "<script> alert('Post Like/Unlike has failed.'); location.replace('index.php'); </script>";
  37. }
  38.  
  39. }
  40. if(isset($_GET['delete_post'])){
  41. extract($_GET);
  42. $sql = "DELETE FROM `post_list` where id = '{$delete_post}'";
  43. $delete = $conn->query($sql);
  44. if($delete){
  45. echo "<script> alert('Post has been deleted successfully.'); location.replace('index.php'); </script>";
  46. }else{
  47. echo "<script> alert('Post has failed to delete. Error: '.$conn->error); location.replace('index.php'); </script>";
  48. }
  49. }
  50.  
  51. ?><!DOCTYPE html>
  52. <html lang="en">
  53.  
  54. <head>
  55. <meta charset="UTF-8">
  56. <meta http-equiv="X-UA-Compatible" content="IE=edge">
  57. <meta name="viewport" content="width=device-width, initial-scale=1.0">
  58. <title>PHP Counting Likes</title>
  59. <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.1.1/css/all.min.css" integrity="sha512-KfkfwYDsLkIlwQp6LFnl8zNdLGxu9YAA1QvwINks4PhcElQSvqcyVLLD9aMhXd13uQjoXtEKNosOWaZqXgel0g==" crossorigin="anonymous" referrerpolicy="no-referrer" />
  60. <link rel="stylesheet" href="./css/bootstrap.min.css">
  61. <script src="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.1.1/js/all.min.js" integrity="sha512-6PM0qYu5KExuNcKt5bURAoT6KCThUmHRewN3zUFNaoI6Di7XJPTMoT6K0nsagZKk2OB4L7E3q1uQKHNHd4stIQ==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
  62. <script src="./js/bootstrap.min.js"></script>
  63.  
  64. </head>
  65. <style>
  66. html, body{
  67. height:100%;
  68. width:100%;
  69. }
  70. </style>
  71. <body class="bg-gradient bg-dark bg-opacity-50">
  72. <script>
  73. start_loader()
  74. </script>
  75. <nav class="navbar navbar-expand-sm navbar-dark bg-gradient bg-dark">
  76. <div class="container-fluid">
  77. <a class="navbar-brand" href="./">PHP Counting Likes</a>
  78.  
  79. <div>
  80. <a href="./?logout=true" class="text-light fw-bolder text-decoration-none"><i class="fa fa-sign-out"></i> <?= $_SESSION['session_name'] ?></a>
  81. </div>
  82. </div>
  83. </div>
  84. </nav>
  85. <main>
  86. <div class="container w-100 mt-3">
  87. <div class="d-flex w-100 align-items-center mb-3">
  88. <div class="col-auto flex-shrink-1 flex-grow-1">
  89. <h3 class="text-center fw-bolder text-light">Posts</h3>
  90. </div>
  91. <div class="col-auto">
  92. <button class="btn btn-primary btn-sm bg-gradient rounded-0" type="button" data-bs-toggle="modal" data-bs-target="#postFormModal"><i class="fa fa-plus"></i> Add Post</button>
  93. </div>
  94. </div>
  95. <?php
  96. $posts = $conn->query("SELECT *,COALESCE((SELECT COUNT(id) FROM like_list where post_id = post_list.id), 0) as `likes` FROM `post_list` order by unix_timestamp(date_created) desc");
  97. while($row = $posts->fetch_assoc()):
  98. $is_liked = $conn->query("SELECT * FROM `like_list` where post_id = '{$row['id']}' and session_name = '{$_SESSION['session_name']}'")->num_rows;
  99.  
  100. ?>
  101. <div class="card card-default rounded-0 mb-4">
  102. <div class="card-header py-1">
  103. <div class="card-title fw-light text-muted d-flex w-100">
  104. <div class="col-auto flex-shricnk-1 flex-grow-1"><?= $row['author'] ?></div>
  105. <div class="col-auto"><?= date("F d, Y h:i A", strtotime($row['date_created'])) ?></div>
  106. </div>
  107. </div>
  108. <div class="card-body">
  109. <h3 class="fw-bolder"><?= $row['title'] ?></h3>
  110. <div>
  111. <?= $row['content'] ?>
  112. </div>
  113. </div>
  114. <div class="card-footer py-1">
  115. <div class="d-flex w-100">
  116. <div class="col-auto flex-shrink-1 flex-grow-1">
  117. <?php if($is_liked > 0): ?>
  118. <a href="index.php?post_id=<?= $row['id'] ?>" class="text-decoration-none text-reset me-3"><i class="fa fa-thumbs-up text-primary"></i></a>
  119. <?php else: ?>
  120. <a href="index.php?post_id=<?= $row['id'] ?>" class="text-decoration-none text-reset me-3"><i class="far fa-thumbs-up"></i></a>
  121. <?php endif; ?>
  122. <span class="fw-bolder"><?= $row['likes'] ?> Like<?= $row['likes'] > 1 ? "s" : "" ?></span>
  123. </div>
  124. <div class="col-auto">
  125. <?php if($_SESSION['session_name'] == $row['author']): ?>
  126. <a href="./?delete_post=<?= $row['id'] ?>" onclick="if(confirm('Are you sure to delete this post?') == false){ event.preventDefault() }" class="btn btn-flat btn-danger rounded-0"><i class="fa fa-trash"></i> Delete</a>
  127. <?php endif; ?>
  128. </div>
  129. </div>
  130.  
  131. </div>
  132. </div>
  133. <?php endwhile; ?>
  134.  
  135. </div>
  136. <div class="modal fade" id="postFormModal" data-bs-backdrop="static" data-bs-keyboard="false" tabindex="-1" aria-labelledby="postFormModallabel" aria-hidden="true">
  137. <div class="modal-dialog modal-dialog-centered modal-dialog-scrollable modal-lg">
  138. <div class="modal-content rounded-0">
  139. <div class="modal-header">
  140. <h5 class="modal-title" id="postFormModallabel">New Member Form</h5>
  141. <button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
  142. </div>
  143. <div class="modal-body">
  144. <form action="index.php" method="POST" id="new_post">
  145. <input type="hidden" name="session_name" value="<?= $_SESSION['session_name'] ?>">
  146. <div class="border-top border-bottom item py-2">
  147. <div class="form-group mb-3">
  148. <label for="title" class="control-label">Title</label>
  149. <input type="text" class="form-control form-control-sm rounded-0" id="title" name="title" required="required">
  150. </div>
  151. <div class="form-group mb-3">
  152. <label for="content" class="control-label">Content</label>
  153. <textarea rows="4" class="form-control form-control-sm rounded-0" id="content" name="content" required="required"></textarea>
  154. </div>
  155. </div>
  156. </form>
  157. </div>
  158. <div class="modal-footer">
  159. <button type="submit" class="btn btn-primary btn-sm rounded-0" form="new_post">Save Post</button>
  160. <button type="button" class="btn btn-secondary btn-sm rounded-0" data-bs-dismiss="modal">Close</button>
  161. </div>
  162. </div>
  163. </div>
  164. </div>
  165. </main>
  166. </body>
  167. </html>

There you go! You can now test the application on your end and see if it meets our goal for this tutorial. If there's an error occurred on your side, please review your changes with the source code I provided above. Or, you can also download the working source code I created for this tutorial. The download button for the source code zip file is located below this article.

DEMO VIDEO

That's the end of this tutorial. I hope this will help you with what you are looking for and for your future PHP Projects. Explore more on this website for more Tutorials and Free Source Codes.

Happy Coding!!!

Add new comment