Open source
Comments for Laravel
composer require roundly-consulting/comments-for-laravelOverview
Polymorphic comments for Laravel. Any Eloquent model can receive comments and any model can write them — with threaded replies, a pending/approved/hidden moderation workflow, a blocklist filter, @mentions, thread locks and a discoverable Comments facade. Likes, report-a-comment moderation and media attachments come built in through sibling Roundly packages. MIT-licensed, with no third-party runtime dependencies beyond Laravel and those packages.
What you get
Comment on anything
Any model receives comments and any model writes them — plus anonymous guest comments, all in one polymorphic table.
Threaded replies
Replies link to their parent and stay on the root subject, with a depth limit that also bounds eager-loading.
Moderation built in
Pending, approved and hidden states, an approval queue, bulk moderation and a word or regex blocklist.
Likes & reports
Rank threads by most-liked or trending, and auto-hide comments once a report is upheld or a threshold is crossed.
Attachments & inline media
A private attachments bucket per comment, with [media:UUID] tokens rendered as responsive images or links.
Mentions & locks
@handles parsed and resolved to your models, plus locks for a whole subject or the thread under one comment.
Facade, DI or actions
One Comments facade, the injectable CommentsManager or single actions — and a recording Comments::fake() plus a drop-in JSON resource.
Documentation
Installation
Install via Composer, publish and run the migrations — including the sibling packages’ — and optionally publish config and translations.
Configuration
Every config key and its default — model, key type, approval, limits, blocklist, mentions, authorization, auto-moderation and media.
Preparing your models
Add HasComments to models that receive comments and GivesComments to authors — or swap in your own Comment model.
The Comments facade
The whole API in one place — a fluent write builder, edits, moderation, site-wide and scoped queries, subject and thread locks, and fake().
DI and actions
Inject CommentsManager for the same API without static calls, or run one of ten action classes directly from a job or your own action.
Writing comments
Write comments through the fluent Comments facade, a typed DTO or the author trait — with body, lock and blocklist checks on every write.
Editing, deleting & restoring
Edit a comment’s body, soft-delete and restore it — edits are re-validated, lock-checked and re-scanned for mentions.
Threaded replies
Replies link to their parent and stay on the root subject; depth is capped by max_depth, which also bounds eager-loading.
Reading & counting comments
Read comments through model relations or the fluent CommentQuery — filters, ordering, pagination, escape hatches and N+1-free counts.
Moderation
Pending, approved and hidden states, an optional approval queue, moderation scopes and bulk approve, hide or delete.
Spam & blocklist filter
Reject, hold or hide comments that match banned words or regular expressions — no external service needed.
@mentions
Parse @handles on every write and edit, store them, and resolve them to your models — CommentMentioned fires once per person, after approval.
Locking threads
Lock a subject’s whole comment section, or the whole thread under one comment, to stop new and edited comments.
Likes & ranking
Like, upvote and react to comments via Likes for Laravel, then rank threads by most-liked or trending with per-viewer state in one query.
Reporting & auto-moderation
Let users and guests report comments via Reports for Laravel, build moderation queues, and auto-hide comments on upheld reports.
Attachments & inline media
Attach files to a comment’s own bucket via Media Library for Laravel, and embed them in the body with [media:UUID] tokens.
Authorization
Opt in to gate every mutation — writes, edits, deletes, restores, moderation and locks — through a Comment policy, starting from the bundled one.
API resources
Return comments as JSON with CommentResource — nested replies, author and status, plus likes and attachments when loaded.
Events
Eight lifecycle events — created, updated, deleted, approved, hidden, thread locked and unlocked, and mentioned — for notifications and audits.
Exceptions & messages
Every failure is a typed CommentsException with a translatable message — catch the base class, or handle each case.
Testing
Comments::fake() records every mutation while still running it, with an assert per verb — plus factory states and AssertsComments.
Requirements
PHP 8.4+, Laravel 12 or 13, and the sibling Roundly packages Composer installs for you.
Show your open-source love
This package is free and MIT-licensed. If it saves you time, a one-off donation or a Patreon membership keeps it maintained, tested and documented.
More ways to support, including cryptoBy donating, you agree to our donation terms.
Want this built into your product?
We integrate our packages into custom Laravel and AI builds. Tell us what you're working on and we'll reply within 48 hours.