Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Comments Laravel Package

laravelista/comments

Laravelista Comments adds polymorphic, threaded comments to any Laravel Eloquent model. It provides commentable and commenter traits, migrations, moderation support, configurable views and simple Blade integration, making it easy to add user discussions to existing applications.

View on GitHub
Deep Wiki
Context7

Getting Started

Requirement check first (this is what 4.5.0 changed). The 4.5.0 release is a compatibility release: it widens the PHP constraint to include 7.4 and 8.x. Before anything else, confirm the rest of the constraint set matches your app — PHP support does not imply Laravel-version support. Run:

composer why-not laravelista/comments 4.5.0
composer show laravelista/comments

If you are on Laravel 8/9 + PHP 8.x and the package was previously pinned out by a php constraint, 4.5.0 is the release that unblocks you. On Laravel 5.x/6 you may still be held back by the illuminate/* constraints — check composer.json in the package source (vendor/laravelista/comments/composer.json), not just the README.

Install and publish:

composer require laravelista/comments
php artisan vendor:publish --provider="Laravelista\Comments\CommentsServiceProvider"
php artisan migrate

Where to look first, in this order:

  1. config/comments.php — user model resolution, auth guard, and any route/prefix settings. This is the file that causes the most first-run confusion.
  2. The published migration — confirm the table name (default comments) and the morph columns (commentable_type / commentable_id) plus parent_id for nesting.
  3. src/ in the package — the trait names and model relations differ slightly between majors; read the installed version rather than a blog post.

First use case — comments on a Post:

// app/Models/Post.php
use Laravelista\Comments\Commentable; // verify trait name in your installed version

class Post extends Model
{
    use Commentable;
}

// app/Models/User.php
use Laravelista\Comments\Commenter;

class User extends Authenticatable
{
    use Commenter;
}

Then in a controller:

$post->comments; // top-level thread

Wire the package's shipped routes/controllers for a fast first pass, or write your own controller if you need JSON for Livewire/Inertia — see below.

Implementation Patterns

Two traits, two roles. The commentable trait goes on anything that can be commented on (posts, videos, products); the commenter trait goes on the model that authors comments (usually User). Keeping these separate is what lets you attach comments to more than one entity without duplicating tables. If you have a second commentable model, add the trait — do not add a second post_id column.

Threading via parent_id. Replies are flat rows pointing at a parent. Render recursively rather than querying per level:

$comments = $post->comments()
    ->whereNull('parent_id')
    ->with(['children' => fn ($q) => $q->withCount('children')])
    ->with('commenter')
    ->latest()
    ->paginate(20);

Paginate top-level comments only, then load children eagerly. Paginating the flat set breaks threads mid-conversation.

Blade rendering. A recursive partial is the cheapest correct option:

{{-- resources/views/comments/_comment.blade.php --}}
<div class="comment" id="comment-{{ $comment->id }}">
    <strong>{{ $comment->commenter->name }}</strong>
    <div>{!! nl2br(e($comment->body)) !!}</div>

    @foreach ($comment->children as $child)
        @include('comments._comment', ['comment' => $child])
    @endforeach
</div>

Prefer e() + nl2br() over a Markdown renderer; if you do allow Markdown, sanitize the HTML output — the package stores the body verbatim.

Bypass the shipped routes when you need JSON. The bundled controllers are a convenience, not a contract. Most production apps replace them with a thin controller returning an API Resource, so the front end controls thread shape:

class PostCommentController extends Controller
{
    public function index(Post $post)
    {
        return CommentResource::collection(
            $post->comments()->whereNull('parent_id')->with('children.commenter')->paginate()
        );
    }

    public function store(Request $request, Post $post)
    {
        $data = $request->validate(['body' => ['required', 'string', 'max:2000']]);

        $comment = $post->comments()->create([
            'body' => $data['body'],
            'parent_id' => $request->integer('parent_id') ?: null,
            'commenter_id' => $request->user()->id, // confirm the actual FK/column name
        ]);

        return new CommentResource($comment->load('commenter'));
    }
}

Authorization. The package does not know your tenancy or moderation rules. Add a CommentPolicy (update, delete) and call $this->authorize() in your controller — especially for destroy, where you must decide whether deleting a parent cascades to replies or promotes them.

Testing. Give yourself a factory for the package model so feature tests read cleanly:

Comment::factory()->for($post, 'commentable')->create(['commenter_id' => $user->id]);

Assert thread shape (assertCount(3, $comment->children)) and the 403 paths; those are the two things that regress when you swap controllers.

Gotchas and Tips

4.5.0 is a constraint bump — treat it as maintenance, not a feature release. No new API, so the upgrade is:

composer update laravelista/comments --with-dependencies
php artisan vendor:publish --provider="Laravelista\Comments\CommentsServiceProvider" --force
php artisan migrate
php artisan optimize:clear

Diff the published migration and config against your copies before --force overwriting anything you have customised.

PHP 8.1 deprecation noise. Running the package on 8.1 (allowed by an ^8.0 constraint) can emit ReturnTypeWillChange deprecations from any class in the dependency implementing ArrayAccess/Iterator/Countable, and Passing null to parameter #n of type string is deprecated when a nullable body or parent_id reaches a string function. These are warnings, not breakage, but they will flood laravel.log under APP_DEBUG. Fix by never storing null bodies and casting parent_id at the boundary.

PHP 8 support ≠ Laravel 9/10 support. Verify the illuminate/support and illuminate/database constraints in the package's composer.json. A package can accept php: ^8.0 while still capping illuminate/* at ^8.0.

N+1 on nested children. The single easiest way to make this package slow is iterating $comment->children inside a Blade loop without eager loading. Any time a page feels heavy, DB::listen() and count queries — you should see a constant number relative to thread depth, not to comment count.

Auth guard mismatch. If comments post as null commenter or the commenter relation is empty, the package's configured guard does not match the guard your route uses. Set it explicitly in config/comments.php rather than relying on the default.

Deleting parents. Decide and enforce it at the database level (onDelete('cascade') on parent_id) or in an observer that re-parents children. Doing neither leaves orphaned replies that render as invisible top-level rows.

Spam and rate limiting. The package does not rate limit. Put ->middleware('throttle:10,1') on your store route from day one; comment endpoints are a favourite for drive-by spam.

Route caching. If you rely on the bundled routes, confirm they are registered outside routes/ and survive php artisan route:cache — a common gotcha when package service providers conditionally load routes.

Extension points worth knowing: publish and edit config/comments.php (user model, guard), extend the package Comment model with your own class and re-point the config if you need scopes or extra casts, and publish views if the package ships any you intend to restyle. Prefer subclassing over editing vendor/ — vendor/ is lost on the next composer update, and given the cadence of this package's releases, that day will come.

Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
socialdept/atp-orm
cboxdk/laravel-assistant-client
socialdept/atp-resolver
socialdept/tenant-domains
tautvydasr/blade-class-names
socialdept/color-scales
maherelgamil/controller
coleus/widgets
coleus/table
coleus/users
coleus/music
coleus/health
coleus/calendar
coleus/notes
coleus/support
coleus/settings
coleus/apps
seampact/laravel
emmyconceptng/laravel-ng-postcode
jjsquady/round-robin