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

Lara Comments Laravel Package

tizis/lara-comments

tizis/lara-comments adds a lightweight comments system to Laravel apps, letting you attach comments to any Eloquent model via polymorphic relations and manage them through a simple, customizable API.

View on GitHub
Deep Wiki
Context7

Getting Started

Install and publish

composer require tizis/lara-comments
php artisan vendor:publish --provider="Tizis\LaraComments\CommentsServiceProvider"
php artisan migrate

The publish step typically drops out a config file (HTMLPurifier settings, auth rules, route prefix) and the migrations for the comments table. Read the published config first — it is where every non-default behavior lives (sanitization, moderation, rating bounds, route registration). Most "the package doesn't work" issues are config, not code.

Wire up the traits

// app/Models/Post.php
use Tizis\LaraComments\Traits\Commentable;

class Post extends Model
{
    use Commentable;
}

// app/Models/User.php
use Tizis\LaraComments\Traits\Commenter;

class User extends Authenticatable
{
    use Commenter;
}

Commentable gives the model a comments() morph-many relation and helpers to create comments. Commenter gives a user their own authored comments and the ability to post/reply/rate.

First use case: comment on a Post

$post = Post::find(1);

$comment = $post->comment('Great write-up!');       // creates against current user
$comment = auth()->user()->comment($post, 'Nice');  // explicit commenter form

$post->comments;                 // top-level + all, depending on config
$post->comments()->count();

Blade rendering:

@foreach($post->comments as $comment)
    <div class="comment">
        <strong>{{ $comment->commenter->name }}</strong>
        {!! $comment->body !!}   {{-- already purified by the package --}}
        @include('comments._replies', ['comments' => $comment->children])
    </div>
@endforeach

Where to look first

  1. config/lara-comments.php (or similarly named) — purifier profile, auth gates, nesting depth, route enable/disable.
  2. The published migration — confirm the morph index and foreign keys match your existing schema conventions.
  3. vendor/tizis/lara-comments/src/Models/Comment.php — the public methods here are the real API (reply(), rate(), children, parent, scopes).
  4. routes/ inside the package if you plan to use the API rather than hand-rolled endpoints.

Implementation Patterns

Polymorphic commenting across many models. The whole point of the package is that any model using Commentable can be commented on. In practice, register the trait on a shared base model or a small set of core resources (Post, Product, Ticket, Lesson) and do not add it to models you'll later want to comment on via a different type — morph aliases matter. If you use morph maps (Relation::enforceMorphMap), define aliases before the first comment is written, or you'll have a table full of FQCNs.

Threaded replies. Replies are parent-child via a parent_id (or morph equivalent). The daily pattern is a two-level UI: render roots, then $comment->children (or ->replies). For deeper threads either recursively include a partial or load the tree once:

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

Cap depth in config and enforce it on the server side too — a reply endpoint that trusts the client's parent_id will happily accept a 40-deep chain.

Ratings / upvotes. The package exposes rating as a column plus helper methods ($comment->rate(1), $comment->rate(-1), or similar depending on version). Two things to decide up front:

  • Is a rating idempotent per user? If the package only increments a counter, you must track per-user votes yourself (a comment_ratings pivot) or users can spam ratings on reload.
  • Sort order: "top" comments (by rating) vs "newest". Expose both and pick sane defaults per surface (blog = newest, forum = top).

Events for notifications and moderation. The package fires create/update/delete/rate events. This is the cleanest integration point — don't override the model:

// app/Providers/EventServiceProvider.php
protected $listen = [
    \Tizis\LaraComments\Events\CommentCreated::class => [
        \App\Listeners\NotifyCommentSubscribers::class,
        \App\Listeners\QueueModerationCheck::class,
    ],
];

Push the listener work onto a queue (ShouldQueue). Notification fan-out on a busy thread is the #1 latency source in comment sections.

Auth rules. Rather than sprinkling @can throughout Blade, centralize in a policy or the package's config-driven gate. Typical rules: authenticated to post, author to edit within N minutes, author or moderator to delete, author to edit body but not rating. If the package ships config booleans for these, prefer them over a parallel policy so the API and UI agree.

API usage. If the package registers routes, put them behind auth:sanctum (or auth:api) and your rate limiter:

Route::middleware(['auth:sanctum', 'throttle:comments'])->group(function () {
    // package API routes, or your own controllers wrapping Comment::create()
});

For a SPA/mobile client, wrap the package in your own thin controller/Resource so you control the JSON shape and can version it. Coupling mobile clients directly to a 2023-era package's response format is how you get stuck.

HTML filtering customization. The package uses HTMLPurifier. The custom hook you'll actually use is tightening or loosening the allowed tags per context:

// config/lara-comments.php
'purifier' => [
    'HTML.Allowed' => 'p,br,strong,em,a[href|title],code,pre,blockquote',
    'AutoFormat.AutoParagraph' => true,
    'URI.AllowedSchemes' => ['http' => true, 'https' => true, 'mailto' => true],
],

Define named profiles (e.g. strict for public blog comments, rich for internal tickets) and choose one per commentable type. Keep sanitization on input, then render with {!! !!} — don't rely on Blade escaping a value you also purified, or you'll double-encode entities.

Moderation workflow. A common pattern is to add a status column via your own migration on top of the package table (or use the package's if present): pending, approved, spam. Then a global scope or query scope on the Comment model filters unapproved comments out of public listings while admins see everything. Do this as a scope, not a trait override, so you can opt out in admin panels.


Gotchas and Tips

Maintenance is the headline risk. Last release is March 2023 and the repo has ~119 stars. Before adopting:

  • Pin the version ("tizis/lara-comments": "1.x") — never dev-master in production.
  • Verify it runs on your Laravel/PHP version. HTMLPurifier and Laravel's PHP constraints are the usual blockers on new PHP releases.
  • Budget for a fork. The comment domain is small enough (one table, one model, a few events) that you can vendor it and fix forward if abandoned. Do not let this package become the reason you can't upgrade Laravel.

Sanitization config is compiled. HTMLPurifier caches its serialized config in storage. If you change HTML.Allowed and see no effect, clear the package/config cache:

php artisan config:clear
php artisan cache:clear
rm -rf storage/framework/cache/*   # or the configured purifier cache path

Also check that the purifier cache directory is writable — on read-only container filesystems it fails silently or throws deep in the library.

N+1 is the default failure mode. $comment->commenter and $comment->children are lazy relations. A 20-comment page with replies can easily become hundreds of queries. Always with() the commenter and the reply chain you render. Add a DB index on (commentable_type, commentable_id, parent_id, created_at) if you paginate by newest under a parent.

Morph integrity on delete. Deleting a Post does not necessarily delete its comments unless the migration defined onDelete('cascade') on the morph pair — and morph columns often can't have FK constraints. Either add a model observer that deletes comments when a commentable is deleted, or rely on a scheduled cleanup. Soft-deleting a comment also matters: does the UI show "[deleted]" with replies intact, or hide the whole subtree? Decide and implement explicitly; packages rarely do it for you.

Replies to deleted/hidden parents. Enforce the invariant that a reply's parent exists and is visible. Filtering only top-level comments in a scope will orphan visible replies to a hidden parent, producing broken thread UIs.

Rating counters drift. If the package maintains an aggregate rating column, concurrent votes can produce lost updates. Wrap vote logic in a transaction or use atomic increments (increment('rating')), and back it with a unique constraint on (comment_id, user_id) if you track per-user votes. Add a periodic reconciliation job if aggregates matter.

Auth checks must live server-side. Any "can comment" UI flag is cosmetic. Verify on the create/update/destroy path — including the API — that the current user is the author or a moderator. The package's config-level auth rules only apply to its own routes; your custom controllers must re-check.

Extension points to prefer, in order: events → config → model scopes → subclassing the Comment model (if the package resolves it from config). Overriding the model is the most fragile option across upgrades; prefer events and scopes.

Route collisions. If you publish the package routes under /api/comments and also have your own comments resource, Laravel will silently match one and shadow the other. Namespace package routes with a prefix and confirm with php artisan route:list.

Testing. Use RefreshDatabase and assert after the events fire — comment creation fires events, and a listener that throws will fail the test with a confusing stack trace. For the UI, test that sanitization actually strips a <script> payload end-to-end ($post->comment('<script>alert(1)</script>hi')) so a config regression gets caught.

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.
shitoudev/permissionmanager
johannesclimacus/laravel-tui
hocvt/seotools
vitalybaev/sypexgeo
amphibee/themosis-ignition
gito-me/fast-excel
frankyso/laravel-ipaymu
geolize-studio/laravel-chile
boomerangui/chat
jinas/dhivatar
store-doc/laravel-storage-driver
plus-it/laravel-translation-manager
diephp/perhaps
diephp/telegraph
osmaviation/spreadsheet
microsoft/fluentui-system-icons
mmccook/php-json-canonicalization-scheme
middlewares/firewall
qubiqx/montapacking
nyoncode/laravel-package-console