Jun 23, 2024 | Laravel 11 Laravel
Hello Dev,
A comment system is essential for blog and tutorial websites as it allows readers to share thoughts, ask questions, and interact with both the author and other readers. It fosters community, provides valuable feedback, and enhances engagement on the site. Comments enrich content by making it more dynamic and engaging, thereby improving the overall reader experience and encouraging return visits. Additionally, comments offer authors insights into their audience's interests and concerns, aiding in the creation of better content.
In this example, we'll start by setting up Laravel UI to establish basic authentication functionalities like login and registration. Next, we'll create a posts table with fields for title and body content. Users will be able to register, create posts, and view posts made by others. They can also add comments, with an additional feature allowing users to reply to comments. Leveraging Laravel's relationships such as hasMany() and belongsTo(), we'll ensure the comment system functions seamlessly.
Follow the steps outlined below to implement this example:
1. Install Laravel UI for user authentication.
2. Create a database table for posts, including fields for title and body.
3. Implement user registration and post creation functionality.
4. Enable viewing posts and adding comments with reply functionality.
5. Utilize Laravel relationships (hasMany() and belongsTo()) to manage comments effectively.
By following these steps, you'll be able to integrate a robust comment system into your Laravel 11 application, enhancing user interaction and content engagement.
Step 1: Install Laravel 11
Step 2: Scaffold Authentication
Step 3: Create Posts and Comments Tables
Step 4: Define Models
Step 5: Set Up Routes
Step 6: Develop Controllers
Step 7: Create and Modify Blade Templates
Step 8: Run Your Laravel Application
Following these steps will guide you through implementing a fully functional comment system in your Laravel 11 application.
Step 1: Install Laravel 10If you haven't already, create a new Laravel project:
composer create-project laravel/laravel example-appStep 2: Scaffold Authentication
Use Laravel UI to scaffold authentication views and routes:
composer require laravel/ui
php artisan ui bootstrap --auth
npm install && npm run devRead Also: Laravel 11 Database Notifications Example Tutorial Step 3: Create Posts and Comments Tables
Generate migrations for posts and comments tables:
php artisan make:migration create_posts_comments_tableComments Table Migration:
<?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'); } };
Run the migrations:
php artisan migrateStep 4: Define Models
Create models for Post and Comment. Define relationships where needed. For instance, in the Post model, you might define a one-to-many relationship with Comment:
php artisan make:model Post
now, update the model file with hasMany() relationship:
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'); } }Read Also: How to Install and Use Laravel 11 Debugbar Package? Step 5: Set Up Routes
Define routes for creating posts, commenting on posts, and replying to comments in routes/web.php:
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'); });Step 6: Develop Controllers
Generate a controller for Post:
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.'); } }Read Also: How to Create Like Dislike Button in Laravel 11? Step 7: Create and Modify Blade Templates
Create views for listing posts, adding comments, and displaying comments. Use Blade syntax to render dynamic content based on user actions and relationships between posts and comments.
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 - ItErrorSolution.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> @endsectionresources/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> @endforeachStep: Run the ApplicationNow, to run the Laravel application, please type the following command and press enter:
php artisan serveNow, open your web browser and enter the provided URL to view the output of the application.
View Your Applicationhttp://localhost:8000/Thank you for your encouragement! If you have any questions or need further assistance, feel free to ask. I'm here to help!
"Hey there! I'm a full-stack developer and proud owner of ItErrorSolution.com, based right here in India. I love nothing more than sharing handy tips and tricks with my fellow developers through easy-to-follow tutorials. When it comes to coding, I'm all about PHP, Laravel, Angular, Vue, Node, JavaScript, jQuery, CodeIgniter, and Bootstrap – been hooked on them forever! I'm all about putting in the work and staying committed. Ready to join me on this journey to coding?"