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

Commentable Laravel Package

x-laravel/commentable

Add polymorphic, threaded comments to any Laravel model with x-laravel/commentable. Just use the trait on posts, pages, or products to get nested replies, editing, soft deletes, and configurable moderation out of the box.

View on GitHub
Deep Wiki
Context7

Getting Started

  • Start with the package contracts and traits:
    • Contracts\CanComment + Concerns\Commenter for models that author comments.
    • Contracts\HasComments + Concerns\Commentable for models that receive comments.
    • A model can use both if it both comments and receives comments.
  • Inspect the package config first. Confirm the comments connection, table, and comment model before running migrations or writing queries.
  • Add the appropriate traits to your Eloquent models and make sure the comments table exists on the configured connection. Comment keys are ULIDs, not auto-incrementing integers.
  • First practical use case: add comments to a primary model such as Post, then let a User author them. Standardize whether your app calls the receiver-side helper (comment() / addComment()) or the author-side helper, depending on trait placement and method signatures.
  • For threaded discussions, use rootComments() for top-level comments and replies() for children. For user profile/history screens, use authoredComments() and isOn() checks.

Implementation Patterns

  • Basic commenting

    • Put HasComments/Commentable on the model being commented on, e.g. Post.
    • Put CanComment/Commenter on the author model, e.g. User.
    • Use the same helper consistently across controllers/services so authorization and event behavior stay predictable.
    • Anonymous comments are supported, so design the author relationship and UI to handle a nullable commenter.
  • Replies and threading

    • Create replies through reply() / addReply() against an existing parent comment.
    • The package refuses a parent comment that belongs to another model. Enforce the same rule in form requests and UI by deriving the parent comment from the current commentable model.
    • Use rootComments() for thread roots and replies() for children. For deep threads, eager load replies to avoid N+1 queries, and consider pagination or a max display depth for very large threads.
  • Listing and checks

    • Use authoredComments() for “my comments” screens.
    • Use isOn() to check whether a comment belongs to a given model before showing actions or authorizing replies/deletes.
    • Prefer relationship queries and scopes over manually filtering by commentable type/ID.
  • Soft deletes and cleanup

    • Normal deletes are soft deletes. Decide how your UI treats soft-deleted comments and their replies.
    • Force deleting a comment deletes its replies through the foreign key. Ensure the comments table migration and database connection actually enforce that FK.
    • Comments are cleaned up when their model or commenter is deleted. Test this with your real delete strategy, especially if parent models use soft deletes.
    • Use model:prune for left-behind comments. The package schedules pruning with configurable frequency and chunk size; verify the scheduler in your app and tune chunk size for large comment tables.
  • Events

    • Listen to Events\Commented, Events\Replied, and Events\CommentDeleted for notifications, audit logs, search indexing, or moderation queues.
    • Events are dispatched after commit, so listeners/jobs can safely assume the comment exists in the database.
    • Avoid relying on events firing before the surrounding transaction commits.
  • Customization

    • If you override the comment model, update the package config and ensure the custom model implements the expected contract/extends the package model.
    • Keep connection and table aligned with your migrations. If you use a non-default connection, verify polymorphic relations and foreign keys still behave as expected.
    • If you use morph maps, keep commentable/commenter morph aliases stable before creating production data.

Gotchas and Tips

  • ULIDs everywhere

    • Do not assume integer comment IDs. Use string/ULID route parameters, validation, and tests.
    • Parent comment IDs are ULIDs; commentable/commenter IDs depend on your own models.
  • Cross-model parent comments

    • The package rejects a reply whose parent comment belongs to another model. Catch or pre-validate this in the UI; stale parent IDs from another thread are a common source of errors.
  • Anonymous comments need app-level controls

    • The package allows anonymous comments, but authorization, spam prevention, rate limiting, and moderation remain your responsibility.
    • authoredComments() will not represent anonymous comments as authored by a user.
  • Soft-delete edge cases

    • Confirm whether your “delete parent model” flow hard-deletes or soft-deletes. Cleanup behavior can differ, and leftover comments may need pruning.
    • Force-delete cascades depend on the database FK. If you use a custom table/connection or disable FK checks, test the cascade explicitly.
  • Pruning can duplicate work

    • If the package already schedules model:prune, avoid adding a second schedule entry unless you intentionally want a different cadence.
    • Run pruning in staging first and monitor chunk size; large backlogs can create long-running jobs.
  • Events after commit

    • In tests, use RefreshDatabase/DatabaseTruncation carefully when asserting after-commit events. If you use Event::fake(), verify listeners still receive expected payloads.
    • Do not dispatch dependent jobs synchronously inside the same transaction expecting the comment to be visible before commit.
  • N+1 in deep threads

    • replies() nested to any depth can produce heavy query counts. Eager load constrained reply chains or load replies per level in the UI.
    • Consider limiting display depth and lazy-loading deeper replies.
  • Debugging checklist

    • Wrong table or connection: check package config and config:clear.
    • Missing traits/contracts: confirm both sides are added where needed.
    • Reply fails: verify parent comment belongs to the same commentable model.
    • Cleanup fails: check FK constraints, connection, and whether deletes are soft vs force.
    • Events not firing: confirm transaction commit and listener registration.
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