PHPackages                             blackpig-creatif/replique - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. [Utility &amp; Helpers](/categories/utility)
4. /
5. blackpig-creatif/replique

ActiveLibrary[Utility &amp; Helpers](/categories/utility)

blackpig-creatif/replique
=========================

A Laravel package to add comments to models with a Filament integration

v1.0.0(1mo ago)01↓100%MITPHPPHP ^8.2CI passing

Since Mar 19Pushed 1mo agoCompare

[ Source](https://github.com/Blackpig/replique)[ Packagist](https://packagist.org/packages/blackpig-creatif/replique)[ Docs](https://github.com/blackpig/replique)[ GitHub Sponsors](https://github.com/BlackpigCreatif)[ RSS](/packages/blackpig-creatif-replique/feed)WikiDiscussions main Synced 1mo ago

READMEChangelog (1)Dependencies (14)Versions (2)Used By (0)

Réplique
========

[](#réplique)

[![Latest Version on Packagist](https://camo.githubusercontent.com/d5370d80b0047fc123d4b7f99ebbc9d717292ac87d6429c7fbb89322c37b57bb/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f762f626c61636b706967637265617469662f7265706c697175652e7376673f7374796c653d666c61742d737175617265)](https://packagist.org/packages/blackpigcreatif/replique)[![GitHub Tests Action Status](https://camo.githubusercontent.com/544ffcaec28f1ba9e5538011f1c19230849fb499e2aab9c785ecd64dba760bec/68747470733a2f2f696d672e736869656c64732e696f2f6769746875622f616374696f6e732f776f726b666c6f772f7374617475732f626c61636b706967637265617469662f7265706c697175652f72756e2d74657374732e796d6c3f6272616e63683d6d61696e266c6162656c3d7465737473267374796c653d666c61742d737175617265)](https://github.com/blackpigcreatif/replique/actions?query=workflow%3Arun-tests+branch%3Amain)[![Total Downloads](https://camo.githubusercontent.com/6075b6826796b253c98d7f3b57cbc8b27cc3f2f6a5a1027a52e4793d28839bfa/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f64742f626c61636b706967637265617469662f7265706c697175652e7376673f7374796c653d666c61742d737175617265)](https://packagist.org/packages/blackpigcreatif/replique)

Réplique adds a fully-featured, polymorphic comment system to any Laravel/Filament application. Attach threaded comments, reactions, and a moderation workflow to any Eloquent model — with a Livewire front-end component and a complete Filament admin resource out of the box.

- **Polymorphic** — any model can accept comments; commentators and reactors are likewise polymorphic
- **Threaded replies** — configurable nesting depth (flat, one level, or unlimited)
- **Reactions** — configurable reaction types (like/dislike, or any custom set)
- **Moderation** — pending/approved/rejected/spam workflow with Filament resource, relation manager, and dashboard widget
- **Anonymous support** — optional unauthenticated commenting with name and email capture
- **Text modes** — plain, escaped HTML, or Markdown (via `league/commonmark`)
- **Security** — honeypot integration, per-IP rate limiting, IP blocking, and prompt-injection sanitisation
- **Atelier integration** — optional page-builder block for Réplique's sister package [Atelier](https://github.com/blackpig-creatif/atelier)

Requirements
------------

[](#requirements)

- PHP 8.2+
- Laravel 11 or 12
- Filament v5
- Livewire v3 or v4
- `spatie/laravel-honeypot` ^4.0

Optional:

- `league/commonmark` ^2.0 — required for the Markdown text mode

Installation
------------

[](#installation)

```
composer require blackpig-creatif/replique
```

> **Important:** If you haven't already created a custom Filament theme, follow the [Filament theming docs](https://filamentphp.com/docs/styling/overview#creating-a-custom-theme) before proceeding. Réplique ships Blade views that must be picked up by Tailwind.

Add the package views to your theme's CSS source:

```
@source '../../../../vendor/blackpig-creatif/replique/resources/**/*.blade.php';
```

Publish and run the migrations:

```
php artisan vendor:publish --tag="replique-migrations"
php artisan migrate
```

Publish the config:

```
php artisan vendor:publish --tag="replique-config"
```

Optionally publish the views to customise the front-end:

```
php artisan vendor:publish --tag="replique-views"
```

Published views land in `resources/views/vendor/replique/livewire/`.

Plugin Registration
-------------------

[](#plugin-registration)

Register `RepliquePlugin` in your Filament panel provider:

```
use BlackpigCreatif\Replique\RepliquePlugin;

public function panel(Panel $panel): Panel
{
    return $panel
        ->plugins([
            RepliquePlugin::make(),
        ]);
}
```

**Available plugin options:**

```
RepliquePlugin::make()
    ->navigationGroup('Moderation')   // default: 'Comments'
    ->withDashboardWidget(),          // enable the pending-comments stats widget
```

Making a Model Commentable
--------------------------

[](#making-a-model-commentable)

Add the `#[Commentable]` attribute and `HasComments` trait to any model:

```
use BlackpigCreatif\Replique\Attributes\Commentable;
use BlackpigCreatif\Replique\Concerns\HasComments;

#[Commentable(label: 'Blog Post')]
class Post extends Model
{
    use HasComments;
}
```

The `label` parameter is optional and used for human-readable display in the admin panel. It falls back to the class basename if omitted.

Réplique automatically discovers commentable models at boot time by scanning `app_path()` for the `#[Commentable]` attribute. The result is cached indefinitely and cleared on `php artisan optimize:clear`.

**Models outside `app_path()`** (e.g. in a package) can be registered manually in the config:

```
// config/replique.php
'commentable_models' => [
    \Some\Package\Article::class => 'Article',
],
```

To refresh the cache manually:

```
php artisan replique:discover
```

Displaying Comments
-------------------

[](#displaying-comments)

Drop the Livewire component into any Blade view:

```

```

All parameters are optional and override their `config/replique.php` equivalents:

```

```

ParameterTypeDefault (config)Description`model``Model`—**Required.** The commentable model instance`title``string``'Comments'`Section heading`depth``int|null``nesting_depth``0` = flat, `1` = one reply level, `null` = unlimited; omit to use config`allow-anonymous``bool``allow_anonymous`Allow unauthenticated submissions`require-auth``bool``require_auth`Force login before commenting`require-approval``bool``require_approval`Hold new comments for moderation`text-mode``string``text_mode``plain`, `escaped_html`, or `markdown``reaction-types``array``reaction_types`Reaction labels; empty array disables reactions`sort-order``string``sort_order``asc` or `desc``sort-by``string``sort_by``created_at` or `reaction_count``per-page``int``per_page`Pagination page sizeConfiguration
-------------

[](#configuration)

```
// config/replique.php

return [

    // Anonymous commenting
    'allow_anonymous' => true,
    'require_auth'    => false,

    // Threaded replies: 0 = flat, 1 = one reply level, null = unlimited
    'nesting_depth' => 1,

    // Text processing: plain | escaped_html | markdown
    'text_mode' => 'escaped_html',

    // Moderation: hold all comments pending approval before display
    'require_approval' => false,

    // Reactions: empty array disables the feature entirely
    'reaction_types' => ['like', 'dislike'],

    // Rate limiting: max new comments per IP per minute
    'rate_limit' => 5,

    // Default sort
    'sort_order' => 'asc',  // asc | desc
    'sort_by'    => 'created_at',  // created_at | reaction_count

    // Pagination
    'per_page' => 20,

    // Strip prompt-injection patterns from submitted text
    'sanitise_injection' => true,

    'user_model'   => \App\Models\User::class,
    'table_prefix' => 'replique_',

    'filament_navigation_group' => 'Comments',

    // Manual registry supplement (see "Making a Model Commentable")
    'commentable_models' => [],

    'notifications' => [
        'on_new_comment'      => false,
        'on_approval_required' => false,
    ],

];
```

Text Modes
----------

[](#text-modes)

ModeBehaviour`plain``strip_tags()` — no formatting whatsoever`escaped_html`Tags stripped, special characters HTML-encoded — safe for output in any context`markdown`Converted via `league/commonmark`; raw HTML stripped; external links get `rel="nofollow ugc"`The `markdown` mode requires `league/commonmark`:

```
composer require league/commonmark
```

If the package is absent at runtime, Réplique falls back to `escaped_html`.

Threaded Comments
-----------------

[](#threaded-comments)

Set `nesting_depth` in the config or override per-component:

```
{{-- flat thread --}}

{{-- one reply level (default) --}}

{{-- unlimited nesting --}}

```

Depth is stored on the comment record and enforced by the Livewire component — the reply button is hidden once the maximum depth is reached.

Anonymous Comments
------------------

[](#anonymous-comments)

When `allow_anonymous` is `true` and the visitor is not authenticated, the comment form captures an optional name and email address alongside the comment text. The `require_auth` flag takes precedence: if set to `true`, anonymous posting is blocked regardless of `allow_anonymous`.

```
// config/replique.php
'allow_anonymous' => true,
'require_auth'    => false,
```

To post a comment programmatically as anonymous:

```
$post->comment('Nice article!', email: 'reader@example.com', name: 'A Reader');
```

Reactions
---------

[](#reactions)

Reactions are toggled by the Livewire component automatically. Each reaction type is a toggle: clicking once adds the reaction, clicking again removes it. One reaction per type per reactor is enforced at the database level.

To configure the available types:

```
// config/replique.php
'reaction_types' => ['like', 'dislike'],  // default
'reaction_types' => ['heart'],            // single toggle reaction
'reaction_types' => [],                   // disable entirely
```

**Programmatic access:**

```
$comment->react('like');               // toggle (adds if absent, removes if present)
$comment->reactionCount('like');       // int
$comment->reactionSummary();           // ['like' => 5, 'dislike' => 1]
```

### Reaction Icons

[](#reaction-icons)

The config value (`'like'`, `'heart'`, etc.) is purely a database identifier. The rendered icon is controlled by the publishable `reaction-icon` Blade component. Four types ship with built-in Heroicon SVGs (outline when inactive, filled when active):

KeyIcon`like`Hand thumb up`dislike`Hand thumb down`star`Star`heart`HeartAny type not in this list falls back to `ucfirst($type)` as text — so existing string-only configs continue to work.

**To use a custom SVG**, publish the component and add your type to the `$icons` map:

```
php artisan vendor:publish --tag="replique-views"
```

Then edit `resources/views/vendor/replique/components/reaction-icon.blade.php`:

```
$icons = [
    'like'   => ['outline' => '', 'solid' => ''],
    'dislike' => [...],
    'fire'   => [
        'outline' => '',
        'solid'   => '',
    ],
];
```

All SVGs use `currentColor` for both fill and stroke, so they inherit whatever text colour you apply to the button in `reactions.blade.php`. The active/inactive visual distinction is handled by swapping between the solid and outline variants — no additional CSS required.

Posting Comments Programmatically
---------------------------------

[](#posting-comments-programmatically)

The `HasComments` trait exposes a `comment()` method:

```
// Authenticated user (auto-resolved from Auth::user())
$post->comment('Great read.');

// Specific user
$post->comment('Great read.', $user);

// Anonymous
$post->comment('Great read.', email: 'anon@example.com', name: 'Anonymous');

// Reply to an existing comment
$post->comment('I agree!', parentId: $comment->id);

// Override text mode
use BlackpigCreatif\Replique\Enums\TextMode;

$post->comment('**Bold claim.**', textMode: TextMode::Markdown);
```

**Querying:**

```
$post->comments;                          // all comments (MorphMany)
$post->comments()->approved()->get();
$post->comments()->topLevel()->get();     // excludes replies
$post->comments()->pending()->get();
```

Moderation
----------

[](#moderation)

### CommentResource

[](#commentresource)

Réplique registers a full Filament resource at `Comments` (or whichever navigation group you configure). It provides:

- **Table** with status badge, text excerpt, commentator, reaction summary, IP address (hidden by default), and sortable timestamps
- **Filters** by status, commentable type, date range, and pending-only toggle; trashed filter for soft-deleted records
- **Row actions** — Approve, Reject, Mark as Spam, Reply (modal), Block IP (modal), Edit, Restore, Delete — grouped in an action menu
- **Bulk actions** — Approve, Reject, Mark as Spam, Restore, Delete all selected
- **Global search** across comment text, email, name, and IP

### CommentsRelationManager

[](#commentsrelationmanager)

Add inline comment management to any Filament resource that owns a commentable model:

```
use BlackpigCreatif\Replique\Filament\RelationManagers\CommentsRelationManager;

public static function getRelations(): array
{
    return [
        CommentsRelationManager::class,
    ];
}
```

The relation manager exposes the same moderation actions as the main resource in a compact inline table.

### PendingCommentsWidget

[](#pendingcommentswidget)

Enable the dashboard stats widget via the plugin:

```
RepliquePlugin::make()->withDashboardWidget()
```

The widget shows **Pending Review**, **Approved Today**, and **Spam Caught** counts and polls every 60 seconds.

### Comment Status Lifecycle

[](#comment-status-lifecycle)

```
pending → approved
pending → rejected
pending → spam
approved → rejected
approved → spam

```

Moderation methods are available directly on the model:

```
$comment->approve();
$comment->reject();
$comment->markAsSpam();
```

Each triggers the corresponding event (see [Events](#events)).

IP Blocking
-----------

[](#ip-blocking)

Block an IP address via the Filament admin (row action on any comment) or programmatically:

```
use BlackpigCreatif\Replique\Facades\Replique;

Replique::blockIp('1.2.3.4', reason: 'Persistent spammer');
Replique::isBlocked('1.2.3.4'); // bool
```

Blocked IPs receive a generic error on any submission attempt. The `IpBlocked` event is dispatched when a block is created.

Notifications
-------------

[](#notifications)

Réplique can notify a model's owner when a new comment is posted. Disabled by default:

```
'notifications' => [
    'on_new_comment'       => true,
    'on_approval_required' => false,
],
```

When `on_new_comment` is `true`, Réplique resolves a notifiable via one of two mechanisms:

**1. Add `notifyOnComment()` to your model:**

```
class Post extends Model
{
    use HasComments;

    public function notifyOnComment(): ?User
    {
        return $this->author; // notify whoever authored the post
    }
}
```

**2. Use a config resolver callable:**

```
// config/replique.php
'notifications' => [
    'on_new_comment' => true,
    'notifiable_resolver' => fn ($commentable) => $commentable->owner,
],
```

If neither is present, no notification is sent.

Events
------

[](#events)

EventPayloadFired when`CommentPosted``$comment`Comment saved (any status)`CommentApproved``$comment``$comment->approve()` called`CommentRejected``$comment``$comment->reject()` called`CommentMarkedAsSpam``$comment``$comment->markAsSpam()` called`ReactionToggled``$comment`, `$type`Reaction added or removed`IpBlocked``$ip`, `$reason`IP address blockedAll events are in the `BlackpigCreatif\Replique\Events` namespace and implement `SerializesModels`.

Security
--------

[](#security)

**Honeypot** — the comment form includes a hidden honeypot field via `spatie/laravel-honeypot`. Bot submissions are silently marked as spam rather than rejected, to avoid tipping off scanners.

**Rate limiting** — Réplique uses Laravel's `RateLimiter` to cap submissions per IP. Default is 5 per minute, configurable via `rate_limit`.

**IP blocking** — blocked IPs are checked on every submission. Admins can block from any comment row in the Filament resource.

**Prompt injection sanitisation** — when `sanitise_injection` is `true`, known prompt-injection patterns (`ignore previous instructions`, `system:`, `[INST]`, etc.) are silently stripped before text is stored. This guards against attempts to poison any AI-assisted moderation or search features in your application.

**HTML safety** — all text modes guard against XSS. `escaped_html` encodes output; `plain` strips all tags; `markdown` runs `league/commonmark` with `html_input: strip` and the `DisallowedRawHtmlExtension` enabled.

Artisan Commands
----------------

[](#artisan-commands)

```
# Refresh the commentable model registry cache
php artisan replique:discover
```

Run this after adding a new `#[Commentable]` model if you want the admin panel to reflect the change without waiting for `optimize:clear`.

Atelier Integration
-------------------

[](#atelier-integration)

If [Atelier](https://github.com/blackpig-creatif/atelier) is installed, Réplique automatically registers a **Comments (Réplique)** page-builder block. This lets editors drop a comments section onto any Atelier-managed page without touching a template.

See [docs/atelier-integration.md](docs/atelier-integration.md) for full details.

Testing
-------

[](#testing)

```
composer test
```

Changelog
---------

[](#changelog)

Please see [CHANGELOG](CHANGELOG.md) for recent changes.

Contributing
------------

[](#contributing)

Please see [CONTRIBUTING](.github/CONTRIBUTING.md) for details.

Security Vulnerabilities
------------------------

[](#security-vulnerabilities)

Please review [our security policy](.github/SECURITY.md) on how to report security vulnerabilities.

Credits
-------

[](#credits)

- [Blackpig Creatif](https://github.com/blackpig-creatif)
- [All Contributors](../../contributors)

License
-------

[](#license)

The MIT License (MIT). Please see [License File](LICENSE.md) for more information.

###  Health Score

39

—

LowBetter than 85% of packages

Maintenance96

Actively maintained with recent releases

Popularity2

Limited adoption so far

Community6

Small or concentrated contributor base

Maturity46

Maturing project, gaining track record

 Bus Factor1

Top contributor holds 100% of commits — single point of failure

How is this calculated?**Maintenance (25%)** — Last commit recency, latest release date, and issue-to-star ratio. Uses a 2-year decay window.

**Popularity (30%)** — Total and monthly downloads, GitHub stars, and forks. Logarithmic scaling prevents top-heavy scores.

**Community (15%)** — Contributors, dependents, forks, watchers, and maintainers. Measures real ecosystem engagement.

**Maturity (30%)** — Project age, version count, PHP version support, and release stability.

###  Release Activity

Cadence

Unknown

Total

1

Last Release

50d ago

### Community

Maintainers

![](https://www.gravatar.com/avatar/e094a144c7d16d2115fac66e49bf5013829a545f111c618ff22fe11ddf8c7bf4?d=identicon)[Blackpig](/maintainers/Blackpig)

---

Top Contributors

[![Blackpig](https://avatars.githubusercontent.com/u/1029317?v=4)](https://github.com/Blackpig "Blackpig (3 commits)")

---

Tags

laravelfilamentfilament-pluginfilamentphpBlackpigCreatifreplique

###  Code Quality

TestsPest

Static AnalysisRector

Code StyleLaravel Pint

### Embed Badge

![Health badge](/badges/blackpig-creatif-replique/health.svg)

```
[![Health](https://phpackages.com/badges/blackpig-creatif-replique/health.svg)](https://phpackages.com/packages/blackpig-creatif-replique)
```

###  Alternatives

[dotswan/filament-map-picker

Easily pick and retrieve geo-coordinates using a map-based interface in your Filament applications.

124139.3k2](/packages/dotswan-filament-map-picker)[jibaymcs/filament-tour

Bring the power of DriverJs to your Filament panels and start a tour !

12247.8k](/packages/jibaymcs-filament-tour)[schmeits/filament-character-counter

This is a Filament character counter TextField and Textarea form field for Filament v4 and v5

33184.7k6](/packages/schmeits-filament-character-counter)[defstudio/filament-searchable-input

A searchable autocomplete input for Filament forms

3212.4k](/packages/defstudio-filament-searchable-input)[asosick/filament-layout-manager

Allow users to create &amp; customize their own FilamentPHP pages composed of Livewire components

5718.8k2](/packages/asosick-filament-layout-manager)[agencetwogether/hookshelper

Simple plugin to toggle display hooks available in current page.

2312.7k](/packages/agencetwogether-hookshelper)

PHPackages © 2026

[Directory](/)[Categories](/categories)[Trending](/trending)[Changelog](/changelog)[Analyze](/analyze)
