›
›
›
  1. docs
  2. ›
  3. byrcsc/laravel-comments
1.x
Browse documentationOpenClose

Getting started

  • Introduction
  • Installation and setup
  • Quick start

Core concepts

  • Commentable models
  • Threads and replies
  • Moderation
  • Initial status
  • Pinning
  • Reactions
  • Edits and revisions
  • Attachments
  • Deleting comments

Operations

  • Comment counts
  • Events and listeners
  • Reply notifications
  • Authorization
  • Rendering and safety

Reference

  • Configuration
  • Console commands
  • Testing
  • Troubleshooting

Getting started

  • Introduction
  • Installation and setup
  • Quick start

Core concepts

  • Commentable models
  • Threads and replies
  • Moderation
  • Initial status
  • Pinning
  • Reactions
  • Edits and revisions
  • Attachments
  • Deleting comments

Operations

  • Comment counts
  • Events and listeners
  • Reply notifications
  • Authorization
  • Rendering and safety

Reference

  • Configuration
  • Console commands
  • Testing
  • Troubleshooting

byrcsc/laravel-comments · 1.x

Introduction.

Laravel Comments adds threaded, moderated discussion to Eloquent models.

Posts may need public discussion, tickets may need internal notes, and orders may need staff remarks. Building each feature separately repeats storage, threading, moderation, and history logic.

Laravel Comments adds those capabilities to any Eloquent model through one trait. Posts, orders, tickets, and invoices can share the same polymorphic comment tables.

The package stores comments and their state. Your application keeps ownership of its UI, rendering, users, and moderation policy.

RequirementSupported versions
PHP8.3, 8.4
Laravel12.x, 13.x

The package follows semantic versioning: upgrading within 1.x is safe. Source and issues live at github.com/byrcsc/laravel-comments.

What the package stores

A comment belongs to one already-persisted commentable record and is written by a commentator, any Eloquent model, or by a guest identified only by a name and an email address. Exactly one of the two, never both.

Comments form threads through parent_id. Each one carries a moderation status, and accumulates reactions, revisions, and attachments.

What the package does not do

Two boundaries shape everything else, and both are worth knowing before you write a line:

Status is package state, not visibility. A comment is pending, approved, rejected, or spam. The package records transitions and fires events; what a visitor sees is decided by your queries, and the approved() scope is the tool for making that decision.

The body is stored verbatim. No sanitization, no markdown, no rendering. Escape or render on output. Treat every body, every guest name, and every guest email as untrusted input, see rendering and safety.

The package also owns no routes, no controllers, and no views beyond one mail template. It never authorizes its own methods, and it never resolves an authenticated user on your behalf.

What is included

  • A HasComments trait that makes any model commentable in one line, with comment() and commentAsGuest() write methods.
  • Threads through reply() and replyAsGuest(), with a configurable depth limit and a depth() walk.
  • Moderation: approve(), reject(), and markAsSpam(), each idempotent and each firing exactly one event per real state change, plus scopes for every status.
  • Initial status resolution from config, with a DecidesCommentStatus hook on the commentable that beats it. Guests start pending whatever the default says.
  • Reactions with database-enforced deduplication, a configurable allowlist, and a grouped-count relation that renders a whole thread in one query.
  • Automatic edit history: every body change stamps edited_at and files an append-only revision holding what the comment said before.
  • Attachment rows for files your application already stored, plus an attachImage() convenience that runs the framework's image pipeline.
  • Pinning, independent of moderation, with a pinnedFirst() ordering scope that behaves the same on MySQL, PostgreSQL, and SQLite.
  • Soft deletes with readable tombstones, and force deletes that take the whole reply subtree through the database's cascade.
  • An opt-in denormalized comments count on the commentable's own table, maintained in atomic increments, with comments:recount as the repair tool.
  • One shipped notification, somebody replied to your comment, off by default, at most once per reply, never sent to a guest.
  • Eighteen lifecycle events under one base class, a publishable CommentPolicy, factories for all four models, and a Comments::fake() recorder for your own test suite.

A first comment

Add the trait to the model that receives comments, and write one:

use ByRcsc\LaravelComments\Concerns\HasComments;
use Illuminate\Database\Eloquent\Model;

class Post extends Model
{
    use HasComments;
}

$comment = $post->comment('Great write-up!', by: $user);

$comment->reply('Agreed, especially the last section.', by: $teammate);

Adding the trait is the whole integration. There is no registration step, no service to bind, and no configuration you have to touch first.

Design boundaries

Four decisions explain most of the API.

One identity per comment. A comment names a commentator model or a guest, never both and never neither. A guest is a name and an email, stored as given and verified by nothing, which is why guests cannot react and are never notified.

Idempotent transitions. Approving an approved comment writes nothing and fires nothing. Pinning a pinned comment does the same. One event means one real state change, which is what counts and notifications downstream are built on.

Model events are the seam. Edit history, the depth limit, the length limit, and count maintenance all ride Eloquent's model events. Anything that goes around them, saveQuietly(), the query builder, raw SQL, goes around these too.

The application owns the files. An attachment is a row of metadata about a file your application stored. The package never opens it, never checks it is there, and never deletes it.

What to read next

  • Installation and setup to create the comment tables and add the trait to a model.
  • Quick start to write, reply to, moderate, and render comments.
  • Rendering and safety to handle stored comment and guest input safely.
NextInstallation and setup
View source

On this page

  1. What the package stores
  2. What the package does not do
  3. What is included
  4. A first comment
  5. Design boundaries
  6. What to read next