Download the PHP package codenzia/filament-comments without Composer

On this page you can find all versions of the php package codenzia/filament-comments. It is possible to download/install these versions without Composer. Possible dependencies are resolved automatically.

FAQ

After the download, you have to make one include require_once('vendor/autoload.php');. After that you have to import the classes with use statements.

Example:
If you use only one package a project is not needed. But if you use more then one package, without a project it is not possible to import the classes with use statements.

In general, it is recommended to use always a project to download your libraries. In an application normally there is more than one library needed.
Some PHP packages are not free to download and because of that hosted in private repositories. In this case some credentials are needed to access such packages. Please use the auth.json textarea to insert credentials, if a package is coming from a private repository. You can look here for more information.

  • Some hosting areas are not accessible by a terminal or SSH. Then it is not possible to use Composer.
  • To use Composer is sometimes complicated. Especially for beginners.
  • Composer needs much resources. Sometimes they are not available on a simple webspace.
  • If you are using private repositories you don't need to share your credentials. You can set up everything on our site and then you provide a simple download link to your team member.
  • Simplify your Composer build process. Use our own command line tool to download the vendor folder as binary. This makes your build process faster and you don't need to expose your credentials for private repositories.
Please rate this library. Is it a good library?

Informations about the package filament-comments

Filament Comments — Threaded discussions, channels, DMs, polls & mentions

Latest Version PHP Version Filament Tests

A full-featured commenting system for Filament v4 and v5 with threaded replies, discussion channels, Slack-style direct messages, polls, events with RSVP, emoji reactions, @mentions, notifications, watchlists, email digests, and a Tribute-powered rich-text composer — all built on Livewire 3.

Why this exists. "Add comments" is one of those innocent-sounding requests that turns into a six-week project: threading, mentions, notifications, moderation, file uploads, link previews, watch/unwatch, DMs. This package ships all of that as a polymorphic drop-in — attach it to any model and you have a Slack-grade discussion surface without leaving Filament.

Try it live: A working integration is included in the Codenzia plugins demo at /admin/demo/comments.


Features

Requirements

Dependency Version
PHP ^8.3
Laravel ^12.0
Filament ^4.0 \|\| ^5.0
Livewire ^3.0

Installation

Install via Composer:

Run the install command:

This publishes the config file and migrations. Run migrations:

Filament Shield / role-based moderation (optional)

The comment permissions listed in config/filament-comments.php are seeded into the standard Spatie permissions table — so if your app uses bezhansalleh/filament-shield (which transitively requires spatie/laravel-permission), they show up in your Shield UI automatically. No extra wiring.

If you don't use Shield or Spatie, the install command skips the permission seeding step quietly — comments, channels, mentions, and DMs all work without it. Add spatie/laravel-permission to your project later and re-run php artisan filament-comments:install to opt in.

Tailwind v4 Custom Theme

If your Filament panel uses a custom theme (Tailwind CSS v4), add the package's source paths so that utility classes are compiled:

This wildcard pattern covers all Codenzia packages at once.

Then rebuild your assets (npm run build).

Setup

Register the plugin in your panel provider:

Multi-Tenancy

The plugin is compatible with Filament multi-tenancy. It registers cleanly on a panel configured with ->tenant(...) and never crashes at boot — a problem that affects naïvely-written plugins.

Why this matters. Filament boots the panel (and therefore every plugin's boot()) before the tenant is identified by middleware. A plugin that eagerly calls Page::getUrl() or queries records during boot() throws Missing required parameter [tenant] on every request — including the tenant-less login page. This plugin avoids that by:

The lazy navigation needs no configuration — it is automatic and behaviour is identical for single-tenant panels (the full channel/DM sidebar is rendered exactly as before).

Built-in tenant scoping (opt-in)

For single-database, column-based tenancy the plugin can confine comments and channels to the current tenant for you. It is off by default (the plugin stays tenant-agnostic); enable it in config:

When enabled:

The resolver. Leave tenant_resolver null to use Filament's current panel tenant (Filament::getTenant()?->getKey()) — the zero-config path for Filament tenancy. To integrate another tenancy strategy (or your own "current tenant" service), set it to a callable or — for config:cache safety — an invokable class string that returns the tenant key:

The default tenant column is a nullable unsignedBigInteger. If your tenant key is a UUID/string, publish your own migration for the column instead and keep tenant_column pointed at it.

Database-per-tenant needs none of this — each tenant already has its own comments/comment_channels tables; leave tenancy.enabled off.

Enabling on an app that already has comments. The scope filters by the tenant key, and rows created before you enabled tenancy have a NULL key — so once the scope is active they match no tenant and become invisible to everyone. If you're turning this on for existing data, backfill the tenant column first (assign each existing comment/channel to its owner tenant) in the same migration or a one-off command, before enabling the scope. Fresh installs have nothing to backfill.

Known limitation under tenancy

While a tenant is pending (the brief window during boot before the tenant resolves), the per-channel and per-DM sidebar quick-links are omitted. Channels and conversations remain fully reachable through the All Channels and All Conversations pages, which are scoped at render time. Single-tenant panels are unaffected.

Usage

Adding Comments to a Model

Add the HasComments trait to any model:

Then use the Blade component in your views:

Or add comments programmatically:

Discussion Channels

The plugin automatically registers two Filament pages:

Channels appear in the sidebar navigation automatically.

Direct Messages

The plugin supports Slack-style direct messages — both 1-on-1 and group conversations. DMs appear in their own collapsible sidebar group.

The plugin registers a Direct Messages page where users can:

Sidebar shortcuts ("+ New Channel" / "+ New Message") auto-open the create modal for quick access. These are permission-aware and hidden when the user lacks the required permission.

Starting a DM Programmatically

This is safe to call multiple times — it returns the existing DM with the exact same set of members if one already exists.

Sidebar MRU Limits

Control how many channels and DMs appear in the sidebar to prevent it from becoming too tall:

Set to null to show all items. The "All" link always appears for accessing the full list.

Navigation Groups

Channels and Direct Messages each get their own collapsible sidebar group. Customize the labels:

Permissions

The plugin uses Spatie Permission for authorization and works seamlessly with Filament Shield.

Configuration

Each action maps to a Spatie permission name in config/filament-comments.php:

Set any permission to null to allow all authenticated users. Set to a string to require that Spatie permission. Pages return 403 when the user lacks the view_* permission.

Seeding Permissions

The install command (filament-comments:install) can seed these permissions for you. You can also call it programmatically in your seeders:

This is safe to call multiple times — it uses firstOrCreate.

Using with Filament Shield

Shield auto-generates page-level permissions (e.g. View:ManageChannelsPage) but does not discover action-level permissions like create_comment_channel. You need to seed these separately via the install command or your seeder, then assign them to roles in Shield's role editor.

Authorization Logic

Checking Permissions Programmatically

Comment Types

Text Comments

Standard rich text comments with mention support.

Poll Comments

Create polls with a question and multiple options. Users vote directly in the comment thread.

Event Comments

Schedule events with title, date/time, and description. Users can RSVP with Going, Maybe, or Not Going.

Choosing which types the composer offers

The composer's + menu offers every structured type by default. Narrow it where the extras are noise — a design-review panel has no use for "schedule a meeting" in the box where somebody is describing a misaligned button:

Slug Menu label
vote Poll
event Event
meeting Meeting
todo Checklist
survey Survey
risk Risk

text is not in the list: it is the composer itself, not a choice inside it.

An empty array removes the + control entirely and leaves a plain comment box; attachment buttons are unaffected. Unknown slugs are ignored rather than fatal, and the menu keeps the package's own order however you write the array.

One page can differ from the installation:

Pass null (or omit it) for "whatever the config says"; pass [] for "none".

This closes a door, never the data. Comments already posted as an event or a survey keep rendering as one, keep their stored type, and are never filtered out of a thread. Removing a type stops people creating more of it — nothing else. The rule is also enforced server-side: setCommentType() refuses a type the installation does not offer, so a hidden menu entry is not the only thing standing between a caller and an unwanted type.

Mention System

Configure mention triggers for different entity types:

Trigger Entity Config Key
@ Users mentionable
# Channels channel_mentionable
$ Projects project_mentionable
% Tasks task_mentionable

Comment Moderation

Upgrading from 0.3.1? There is nothing to do. Moderation is inert until you register a resolver: both settings below default to null, no config republish is needed, and an installation that configures nothing posts, replies and renders exactly as it did before. The one behaviour that changed is called out at the end of this section.

By default, new comments are auto-approved. To require manual moderation everywhere:

When false, new comments have is_approved = false and stay out of the thread until approved.

Deciding per post, not per installation

auto_approve is one boolean for the whole install. A review workflow usually needs something narrower — hold this person's comments on this record, let everyone else through. Register a resolver:

Both resolvers accept a closure or — so config:cache keeps working — the name of an invokable class:

Leave auto_approve_resolver at null and it is never consulted: approval falls back to auto_approve, exactly as before.

Who sees what is held

A held comment renders to its own author, marked Pending approval — a comment its writer cannot see reads as a post that failed. Everyone else sees nothing. To let a moderator see and act on everyone's held comments, say who a moderator is:

It defaults to null, so nobody is a moderator until you say so. (This is separate from permissions.moderate_comment, which only grants retagging someone else's comment.) A moderator gets inline publish / turn-down controls on each held comment; turning one down deletes it, and CommentItem::rejectComment() is the single method to override if you would rather keep the row.

For your own screens:

approved() and the replies() relation are unchanged — both still mean "published, whoever is looking". visibleTo() is the per-viewer rule, asked for by name.

The one thing that is not a no-op

If your app already sets auto_approve => false, authors now see their own held comments where they previously saw nothing. That is the point — it is the bug this release fixes. The rule is only ever a superset of approved(): it never hides a row that used to render, and with auto_approve at its default true there is nothing unapproved for it to add.

Composer Appearance

Customize the composer background color to match your app's theme:

Accepts any valid CSS color value (hex, rgb, hsl, etc.).

When show_settings is true, a cog icon appears in the composer toolbar allowing users to pick from preset background colors. The choice is saved in localStorage.

Reactions

Users can react to comments with emoji. One reaction per user per comment. Customize available reactions:

Quick Comments (Lightweight Preview + Composer)

A lightweight, embeddable comment preview with a quick reply composer — designed for modals, sidebars, and cards where the full CommentsComponent would be too heavy or cause Livewire nesting issues.

Prop Type Default Description
record Model required Any model using HasComments
limit int 3 Number of recent comments to show
viewAllUrl ?string null URL for the "View all" link

Features:

Or use the Livewire component directly:

Pinning Comments

Pin an important comment to the top of a discussion. Only one pinned comment per commentable — pinning a new one automatically unpins the previous.

Resolving Threads

Mark root comment threads as resolved to keep discussions clean. Resolved threads collapse by default and show a green "Resolved by {user}" badge.

Priorities

Any comment can carry a priority, so a long thread can be read blocker-first instead of newest-first. The composer shows a chip strip; the chosen priority renders as a colored chip on the posted comment, and appears in the email digest.

Priorities are plain strings, not a PHP enum, so you can rename or re-scale the vocabulary without forking the package. Three ship by default:

Key Label Color
blocker Blocker danger
must Must fix warning
nice Nice to have gray
null (no priority) —

The key order in config is the precedence order. The first key sorts first; comments with no priority — and comments carrying a key you later removed — always sort last.

label may be a translation key (as the shipped defaults are) or a literal string. color is any Filament color name — chips render through Filament's badge component, so a custom color works without being safelisted in your Tailwind theme.

Querying:

Filtering by a priority outside the vocabulary matches nothing rather than degrading to "every comment".

On a comment:

The value is normalized on every write path: anything outside the current vocabulary is stored as null, so the column can never hold something the UI cannot render.

Who can set it: anyone posting a comment sets it in the composer. Afterwards, the comment's author can always re-prioritise it; anyone else needs the permission named in permissions.moderate_comment (default null — author only).

Tags

Free-form per-comment labels, with autocomplete drawn from tags already used nearby.

Tags are normalized on write, whatever the path: whitespace collapsed, blanks dropped, each tag truncated to max_length, duplicates removed case-insensitively (first casing seen wins), and the list truncated to max_per_comment. An empty list stores as NULL, so "no tags" has exactly one representation.

Autocomplete scope. By default suggestions come from every comment on the same commentable_type — that is what makes autocomplete useful on a record that has no tags of its own yet. Narrow or widen it with a closure, or (for config:cache safety) an invokable class string:

Querying:

Each comment is returned once even when it matches several tags. Filtering by an empty or blank tag matches nothing.

On a comment:

Storage tradeoff (worth knowing before you scale). Tags live in a JSON column on the comment row, not in a tags table with a pivot. The only query shapes the plugin needs are "carries tag X" and "carries any of X, Y", both expressible as whereJsonContains, and there is no tag entity to name, describe, merge or own. The cost is that a JSON column cannot be B-tree indexed per value, so tag filtering is a scan. That is the right shape for per-record comment volumes; if you filter tags across millions of comments, promote tags to their own table in your app.

Setting priority and tags in code

Both are fillable, and HasComments::comment() / commentAsUser() take an optional attribute array:

Priorities and tags in your own UI

Both composers wire the controls for you — embed <livewire:filament-comments::comments> or <livewire:filament-comments::quick-comments> and the triage row appears in the composer, with chips on the rendered comments. Nothing to configure.

To place the controls in a surface of your own, the two Blade partials are public:

Add the ManagesTriage trait to your component for priorityOptions(), tagsEnabled(), prioritiesEnabled(), maxTagsPerComment() and canTriageComment().

Turning either feature off hides its control and refuses the write — but never erases values already stored, so flipping the flag back on brings them back intact.

Bookmarks

Personal bookmarks let users save comments for quick reference. Bookmarks are private — not visible to other users.

Watching Discussions

Users can watch any commentable model to get notified on ALL new comments, not just @mentions. A bell icon toggles watch state.

Link Comments to Tasks

When commenting in a project discussion, users can link a comment to a specific task. The comment displays a small task reference card that links to the task detail page.

Configure the task model in config:

Email Digest

Optional daily email digest of unread comments for watchers. Disabled by default.

Register the command in your scheduler:

The digest groups unread comments by source (task, project, channel) and only sends if there are new items in the last 24 hours.

Code Syntax Highlighting

Code blocks in comments (<pre><code>) are automatically syntax-highlighted using highlight.js. Supports PHP, JavaScript, Python, SQL, HTML, CSS, Go, Java, JSON, YAML, XML, C++, Markdown, and more.

Highlighting is applied on initial render and after Livewire updates. Uses the github-dark theme by default.

Checklists

Comments support interactive checklists using the [ ] / [x] syntax. Checklist items render as clickable checkboxes that toggle their state via Livewire.

Write in your comment:

Clicking a checkbox updates the comment body in the database. Available to the comment author and other project members.

Link Previews

URLs in comments are automatically enriched with Open Graph metadata cards showing title, description, image thumbnail, and domain.

Security

Comment bodies are stored as HTML and rendered unescaped, so the package sanitizes them at render time via Comment::safeHtml() (backed by Codenzia\FilamentComments\Support\CommentSanitizer, built on symfony/html-sanitizer). Scripts, inline event handlers and javascript: URLs are stripped; safe rich-text markup, tribute-mention spans, language-* code classes and checklist tokens are preserved.

If you render comment content in your own Blade views, never echo $comment->comment with {!! !!} — use {!! $comment->safeHtml() !!} (or escape with {{ }} for plain text).

Configuration

Publish the config file:

Key configuration options:

User avatars

User pickers (@mentions, DM recipients, channel members) resolve each person's avatar in priority order — this is how an app supplies its own avatars:

  1. Filament's HasAvatar contract. If your User model implements Filament\Models\Contracts\HasAvatar, its getFilamentAvatarUrl() is used — the same avatar Filament's own UI shows. This is the recommended way.
  2. The configured column/accessor (mentionable.column.avatar, default profile_photo_path). It may hold a full URL, or a path resolved against mentionable.avatar_disk (default public).
  3. A generated initials avatar (ui-avatars.com), so a bare users table (just id / name / email) still renders something sensible.

The package never assumes the avatar column exists: if it isn't a real column on your users table it is skipped (queries never error) and resolution falls through to the next step. This is centralized in Codenzia\FilamentComments\Support\Mentionables — avatarUrl() resolves the URL and selectColumns() builds a safe SELECT that only references real columns.

Database Schema

The package creates seven tables:

Table Purpose
comments Main comments with polymorphic relation, threading, type, approval, pin, resolve, link previews, priority, tags
comment_channels Discussion channels and DMs with type, visibility, icon, project association
comment_channel_members Channel membership pivot table
comment_channel_reads Read tracking per channel per user
comments_reactions Emoji reactions per user per comment
comment_bookmarks Personal bookmarks per user per comment
comment_watches Polymorphic watch subscriptions per user per model

Models

Comment

CommentBookmark

CommentWatch

CommentChannel

Events

Event Dispatched When
CommentAdded New comment created
CommentDeleted Comment removed
UserMentioned User mentioned in a comment
EventAddedToCalendar Event comment added to calendar

Traits

Trait Purpose
HasComments Add to any model to enable commenting + watching
ExtractsMentions Parse HTML for tribute mentions
HasMentionable Build mentionable lists from config

HasComments now includes watch/unwatch support:

License

This package is dual-licensed:

See LICENSE.md for full terms.


All versions of filament-comments with dependencies

PHP Build Version
Package Version
Requires php Version ^8.3
filament/filament Version ^4.0 || ^5.0
spatie/laravel-package-tools Version ^1.15.0
symfony/html-sanitizer Version ^7.0 || ^8.0
Composer command for our command line client (download client) This client runs in each environment. You don't need a specific PHP version etc. The first 20 API calls are free. Standard composer command

The package codenzia/filament-comments contains the following files

Loading the files please wait ...