
Hi Dev,
People can chat with you and each other. That makes them feel part of something, and they’re more likely to return. When readers comment, they spend more time on your page. They may even come back to reply. That’s good for your blog’s stickiness. Comments tell you what readers liked, didn’t get, or want more of—great sparks for new posts. Readers’ comments add new words and ideas to your posts. This can help search engines see your page as more valuable.
We’ll begin by adding Laravel UI to set up basic user authentication, including registration and login screens. Next, we’ll build a posts table with title and body fields to allow users to create content. Once users are registered, they’ll be able to publish posts that other users can view. We’ll enable commenting on posts, and also support replies to those comments for nested discussions. To manage these relationships, we’ll utilize Laravel’s Eloquent methods—hasMany() for one-to-many and belongsTo() for the inverse connection. Follow along through each step to implement this fully functional, user-driven content system with nested commenting!
Step for Creating Comment System in Laravel 12
Step 1: Install Laravel 12
Step 2: Create Auth using Scaffold
Step 3: Create Posts and Comments Tables
Step 4: Create Models
Step 5: Create Routes
Step 6: Create Controller
Step 7: Create and Update Blade Files
Run Laravel App
Install Laravel 12
For Installing Laravel application 12 run below command. let’s start:
composer create-project laravel/laravel example-app
Create Auth using Scaffold
Now, we will create an auth scaffold command to generate login, register, and dashboard functionalities. So, run the below commands:
Laravel 12 UI Package:
composer require laravel/ui
Generate Auth:
php artisan ui bootstrap --auth
npm install
npm run build
Create Posts and Comments Tables
For Creating Posts and Comments tables run below command.
php artisan make:migration create_posts_comments_table
now, let’s update the following migrations table:
database/migrations/2024_06_19_140622_create_posts_comments_table.php
<?php use Illuminate\Database\Migrations\Migration; use Illuminate\Database\Schema\Blueprint; use Illuminate\Support\Facades\Schema; return new class extends Migration { /** * Run the migrations. */ public function up(): void { Schema::create('posts', function (Blueprint $table) { $table->id(); $table->string('title'); $table->text('body'); $table->timestamps(); }); Schema::create('comments', function (Blueprint $table) { $table->id(); $table->integer('user_id')->unsigned(); $table->integer('post_id')->unsigned(); $table->integer('parent_id')->unsigned()->nullable(); $table->text('body'); $table->timestamps(); }); } /** * Reverse the migrations. */ public function down(): void { Schema::dropIfExists('posts'); Schema::dropIfExists('comments'); } };
now, run the following command:
php artisan migrate
Create Models
To implement a comment system in Laravel, you’ll need to create Post and Comment models, update the User model, also we will right relationship and some model function.
php artisan make:model Post
Now, With hasMany() relationship we will update the model file.
app/Models/Post.php
<?php namespace App\Models; use Illuminate\Database\Eloquent\Factories\HasFactory; use Illuminate\Database\Eloquent\Model; class Post extends Model { use HasFactory; /** * The attributes that are mass assignable. * * @var array */ protected $fillable = ['title', 'body']; /** * The has Many Relationship * * @var array */ public function comments() { return $this->hasMany(Comment::class)->whereNull('parent_id')->latest(); } }
app/Models/Comment.php
<?php namespace App\Models; use Illuminate\Database\Eloquent\Factories\HasFactory; use Illuminate\Database\Eloquent\Model; class Comment extends Model { use HasFactory; /** * The attributes that are mass assignable. * * @var array */ protected $fillable = ['user_id', 'post_id', 'parent_id', 'body']; /** * The belongs to Relationship * * @var array */ public function user() { return $this->belongsTo(User::class); } /** * The has Many Relationship * * @var array */ public function replies() { return $this->hasMany(Comment::class, 'parent_id'); } }
Create Routes
Now, we need to create some routes. So open your “routes/web.php” file and add the following route.
routes/web.php
<?php use Illuminate\Support\Facades\Route; use App\Http\Controllers\PostController; Route::get('/', function () { return view('welcome'); }); Auth::routes(); Route::get('/home', [App\Http\Controllers\HomeController::class, 'index'])->name('home'); Route::middleware('auth')->group(function () { Route::get('/posts', [PostController::class, 'index'])->name('posts.index'); Route::post('/posts', [PostController::class, 'store'])->name('posts.store'); Route::get('/posts/{id}', [PostController::class, 'show'])->name('posts.show'); Route::post('/posts/comment/store', [PostController::class, 'commentStore'])->name('posts.comment.store'); });
Create Controller
In this step, We create a new controoler, PostController. So let’s put the code below.
app/Http/Controllers/PostController.php
<?php namespace App\Http\Controllers; use Illuminate\Http\Request; use App\Models\Post; use App\Models\Comment; class PostController extends Controller { /** * Display a listing of the resource. * * @return \Illuminate\Http\Response */ public function index() { $posts = Post::latest()->get(); return view('posts.index', compact('posts')); } /** * Write code on Method * * @return response() */ public function store(Request $request) { $this->validate($request, [ 'title' => 'required', 'body' => 'required' ]); $post = Post::create([ 'title' => $request->title, 'body' => $request->body ]); return back()->with('success','Post created successfully.'); } /** * Show the form for creating a new resource. * * @return \Illuminate\Http\Response */ public function show($id) { $post = Post::find($id); return view('posts.show', compact('post')); } /** * Write code on Method * * @return response() */ public function commentStore(Request $request) { $request->validate([ 'body'=>'required', ]); $input = $request->all(); $input['user_id'] = auth()->user()->id; Comment::create($input); return back()->with('success','Comment added successfully.'); } }
Create and Update Blade Files
Now, we will update app.blade.php file and create posts.blade file. so, let’s do it.
resources/views/layouts/app.blade.php
<!doctype html> <html lang="{{ str_replace('_', '-', app()->getLocale()) }}"> <head> <meta charset="utf-8"> <meta name="viewport" content="width=device-width, initial-scale=1"> <!-- CSRF Token --> <meta name="csrf-token" content="{{ csrf_token() }}"> <title>{{ config('app.name', 'Laravel') }}</title> <!-- Fonts --> <link rel="dns-prefetch" href="//fonts.bunny.net"> <link href="https://fonts.bunny.net/css?family=Nunito" rel="stylesheet"> <!-- Scripts --> @vite(['resources/sass/app.scss', 'resources/js/app.js']) <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.5.1/css/all.min.css" /> <style type="text/css"> .img-user{ width: 40px; border-radius: 50%; } .col-md-1{ padding-right: 0px !important; } .img-col{ width: 5.33% !important; } </style> </head> <body> <div id="app"> <nav class="navbar navbar-expand-md navbar-light bg-white shadow-sm"> <div class="container"> <a class="navbar-brand" href="{{ url('/') }}"> Laravel Comment System Example - ItSolutionStuff.com </a> <button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarSupportedContent" aria-controls="navbarSupportedContent" aria-expanded="false" aria-label="{{ __('Toggle navigation') }}"> <span class="navbar-toggler-icon"></span> </button> <div class="collapse navbar-collapse" id="navbarSupportedContent"> <!-- Left Side Of Navbar --> <ul class="navbar-nav me-auto"> </ul> <!-- Right Side Of Navbar --> <ul class="navbar-nav ms-auto"> <!-- Authentication Links --> @guest @if (Route::has('login')) <li class="nav-item"> <a class="nav-link" href="{{ route('login') }}">{{ __('Login') }}</a> </li> @endif @if (Route::has('register')) <li class="nav-item"> <a class="nav-link" href="{{ route('register') }}">{{ __('Register') }}</a> </li> @endif @else <li class="nav-item"> <a class="nav-link" href="{{ route('posts.index') }}">{{ __('Posts') }}</a> </li> <li class="nav-item dropdown"> <a id="navbarDropdown" class="nav-link dropdown-toggle" href="#" role="button" data-bs-toggle="dropdown" aria-haspopup="true" aria-expanded="false" v-pre> {{ Auth::user()->name }} </a> <div class="dropdown-menu dropdown-menu-end" aria-labelledby="navbarDropdown"> <a class="dropdown-item" href="{{ route('logout') }}" onclick="event.preventDefault(); document.getElementById('logout-form').submit();"> {{ __('Logout') }} </a> <form id="logout-form" action="{{ route('logout') }}" method="POST" class="d-none"> @csrf </form> </div> </li> @endguest </ul> </div> </div> </nav> <main class="py-4"> @yield('content') </main> </div> </body> </html>
resources/views/posts/index.blade.php
@extends('layouts.app') @section('content') <div class="container"> <div class="row justify-content-center"> <div class="col-md-12"> <div class="card"> <div class="card-header"><i class="fa fa-list"></i> {{ __('Posts List') }}</div> <div class="card-body"> @session('success') <div class="alert alert-success" role="alert"> {{ $value }} </div> @endsession <p><strong>Create New Post</strong></p> <form method="post" action="{{ route('posts.store') }}" enctype="multipart/form-data"> @csrf <div class="form-group"> <label>Title:</label> <input type="text" name="title" class="form-control" /> @error('title') <div class="text-danger">{{ $message }}</div> @enderror </div> <div class="form-group"> <label>Body:</label> <textarea class="form-control" name="body"></textarea> @error('body') <div class="text-danger">{{ $message }}</div> @enderror </div> <div class="form-group mt-2"> <button type="submit" class="btn btn-success btn-block"><i class="fa fa-save"></i> Submit</button> </div> </form> <p class="mt-4"><strong>Post List:</strong></p> @foreach($posts as $post) <div class="card mt-2"> <div class="card-body"> <h5 class="card-title">{{ $post->title }}</h5> <p class="card-text">{{ $post->body }}</p> <div class="text-end"> <a href="{{ route('posts.show', $post->id) }}" class="btn btn-primary">View</a> </div> </div> </div> @endforeach </div> </div> </div> </div> </div> @endsection
resources/views/posts/show.blade.php
@extends('layouts.app') @section('content') <div class="container"> <div class="row justify-content-center"> <div class="col-md-12"> <div class="card"> <div class="card-header"><h1><i class="fa fa-thumbs-up"></i> {{ $post->title }}</h1></div> <div class="card-body"> @session('success') <div class="alert alert-success" role="alert"> {{ $value }} </div> @endsession {{ $post->body }} <h4 class="mt-4">Comments:</h4> <form method="post" action="{{ route('posts.comment.store') }}"> @csrf <div class="form-group"> <textarea class="form-control" name="body" placeholder="Write Your Comment..."></textarea> <input type="hidden" name="post_id" value="{{ $post->id }}" /> </div> <div class="form-group text-end"> <button class="btn btn-success mt-2"><i class="fa fa-comment"></i> Add Comment</button> </div> </form> <hr/> @include('posts.comments', ['comments' => $post->comments, 'post_id' => $post->id]) </div> </div> </div> </div> </div> @endsection
resources/views/posts/comments.blade.php
@foreach($comments as $comment) <div class="display-comment row mt-3" @if($comment->parent_id != null) style="margin-left:40px;" @endif> <div class="col-md-1 text-end img-col"> <img src="https://randomuser.me/api/portraits/men/43.jpg" class="img-user"> </div> <div class="col-md-11"> <strong>{{ $comment->user->name }}</strong> <br/><small><i class="fa fa-clock"></i> {{ $comment->created_at->diffForHumans() }}</small> <p>{!! nl2br($comment->body) !!}</p> <form method="post" action="{{ route('posts.comment.store') }}"> @csrf <div class="row"> <div class="col-md-11"> <div class="form-group"> <textarea class="form-control" name="body" placeholder="Write Your Reply..." style="height: 40px;"></textarea> <input type="hidden" name="post_id" value="{{ $post_id }}" /> <input type="hidden" name="parent_id" value="{{ $comment->id }}" /> </div> </div> <div class="col-md-1"> <button class="btn btn-warning"><i class="fa fa-reply"></i> Reply</button> </div> </div> </form> @include('posts.comments', ['comments' => $comment->replies]) </div> </div> @endforeach
Run Laravel App:
php artisan serve
I hope it will assist you…