coolsam/nested-comments

Add Nested comments/replies to filament forms, infolists and resources

v1.0.0 2025-04-22 10:43 UTC

This package is auto-updated.

Last update: 2025-04-22 10:58:35 UTC


README

Latest Version on Packagist GitHub Tests Action Status GitHub Code Style Action Status GitHub PHPStan Action Status Total Downloads

This package allows you to incorporate comments and replies in your Filament forms, infolists, pages, widgets etc, or even simply in your livewire components. Comment replies can be nested as deep as you want, using the Nested Set data structure. Additionally, the package comes with a Reactions feature to enable your users to react to any of your models (e.g comments or posts) with selected emoji reactions.

image

Installation

You can install the package via composer:

composer require coolsam/nested-comments

Run the installation command and follow the prompts:

php artisan nested-comments:install

Adjust the configuration file as necessary, then run migrations.

`That's it! You are now ready to add nested comments

Usage: Comments

At the very basic level, this package is simply a Livewire Component that takes in a model record which is commentable. Follow the following steps to prepare your model to be commentable or reactable:

  1. Add the HasComments trait to your model
use Coolsam\NestedComments\Traits\HasComments;

class Conference extends Model
{
    use HasComments;

    // ...
}
  1. If you would like to be able to react to your model directly as well, add the HasReactions trait to your model
use Coolsam\NestedComments\Traits\HasReactions;

class Conference extends Model
{
    use HasReactions;

    // ...
}
  1. You can now access the comments and reactions of your model in the following ways

Using the Comments Infolist Entry

public static function infolist(Infolist $infolist): Infolist
    {
        return $infolist
            ->schema([
                Section::make('Basic Details')
                    ->schema([
                        TextEntry::make('name'),
                        TextEntry::make('start_date')
                            ->dateTime(),
                        TextEntry::make('end_date')
                            ->dateTime(),
                        TextEntry::make('created_at')
                            ->dateTime(),
                    ]),
                
                // Add the comments entry
                \Coolsam\NestedComments\Filament\Infolists\CommentsEntry::make('comments'),
            ]);
    }

image

Using the Comments Widget inside a Resource Page (e.g EditRecord)

As long as the resource page interacts with the record, the CommentsWidget will resolve the record automatically.

class EditConference extends EditRecord
{
    protected static string $resource = ConferenceResource::class;

    protected function getHeaderActions(): array
    {
        return [
            Actions\ViewAction::make(),
            Actions\DeleteAction::make(),
        ];
    }

    protected function getFooterWidgets(): array
    {
        return [
            \Coolsam\NestedComments\Filament\Widgets\CommentsWidget::class,
        ];
    }
}

image

Using the Comments Widget in a custom Filament Page (You have to pass $record manually)

// NOTE: It's up to you how to get your record, as long as you pass it to the widget
public function getRecord(): ?Conference
{
    return Conference::latest()->first();
}

protected function getFooterWidgets(): array
{
    return [
        CommentsWidget::make(['record' => $this->getRecord()])
    ];
}

Using the Comments Page Action in a Resource Page (which interacts with $record)

namespace App\Filament\Resources\ConferenceResource\Pages;

use App\Filament\Resources\ConferenceResource;
use Coolsam\NestedComments\Filament\Actions\CommentsAction;
use Filament\Actions;
use Filament\Resources\Pages\ViewRecord;
use Illuminate\Database\Eloquent\Model;

class ViewConference extends ViewRecord
{
    protected static string $resource = ConferenceResource::class;

    protected function getHeaderActions(): array
    {
        return [
            CommentsAction::make()
                ->badgeColor('danger')
                ->badge(fn(Model $record) => $record->getAttribute('comments_count')),
            Actions\EditAction::make(),
        ];
    }
}

image

image

Using the Comments Page Action in a custom Filament Page (You have to pass $record manually)

In this case you will have to pass the record attribute manually.

protected function getHeaderActions(): array
{
    return [
        CommentsAction::make()
            ->record($this->getRecord()) // Define the logic for getting your record e.g in $this->getRecord()
            ->badgeColor('danger')
            ->badge(fn(Model $record) => $record->getAttribute('comments_count')),
        Actions\EditAction::make(),
    ];
}

Using the Comments Table Action

public static function table(Table $table): Table
{
    return $table
        ->columns([
            // ... Columns
        ])
        ->actions([
            \Coolsam\NestedComments\Filament\Tables\Actions\CommentsAction::make()
                ->button()
                ->badgeColor('danger')
                ->badge(fn(Conference $record) => $record->getAttribute('comments_count')),
            // ... Other actions
        ]);
}

image

Using the Comments Blade Component ANYWHERE!

This unlocks incredible possibilities. It allows you to render your comments even in your own frontend blade page. All you have to do is simply pass the commentable $record to the blade component

$record = Conference::find(1); // Get your record from the database then,

<x-nested-comments::comments :record="$record"/>

Alternatively, you could use the Livewire component if you prefer.

$record = Conference::find(1); // Get your record from the database then,

<livewire:nested-comments::comments :record="$record"/>

Mentions

The package uses Filament TipTap Editor which supports mentions. You can mention users in your comments by typing @ followed by the user's name. The package will automatically resolve the user and send them a notification. You can customize how to fetch mentions by changing the .closures.getMentionsUsing closure in the config file. Two sample methods have been included in the main class for getting all users in the DB or only users that have been mentioned in the current thread (default). Customize this however you wish.

Get only users mentioned in the current thread:

[
    'getMentionsUsing' => fn (
            string $query,
            Model $commentable
        ) => app(\Coolsam\NestedComments\NestedComments::class)->getCurrentThreadUsers($query, $commentable),
]

Get all users from your database

[
    'getMentionsUsing' => 'getMentionsUsing' => fn (string $query, Model $commentable) => app(\Coolsam\NestedComments\NestedComments::class)->getUserMentions($query),
]

image

Usage: Emoji Reactions

This package also allows you to add emoji reactions to your models. You can use the HasReactions trait to add reactions to any model. The reactions are stored in a separate table, and you can customize the reactions that are available via the configuration file. The Comments model that powers the comments feature described above already uses emoji reactions.

In order to start using reactions for your model, add the HasReactions trait to your model. You can then use the reactions method to get the reactions for the model.

use Coolsam\NestedComments\Traits\HasReactions;

class Conference extends Model
{
    use HasReactions;

    // ...
}

The above trait adds the react() method to your model, allowing you to toggle a reaction for the model. You can also use the reactions method to get the reactions for the model.

$conference = Conference::find(1);
$comference->react('👍'); // React to the conference with a thumbs up emoji

You can also use the reactions method to get the reactions for the model.

$conference = Conference::find(1);
$reactions = $conference->reactions; // Get the reactions for the conference

Other useful methods include

/**
* @var \Illuminate\Database\Eloquent\Model&\Coolsam\NestedComments\Concerns\HasReactions $conference
 */
$conference = Conference::find(1);
$conference->total_reactions; // Get the total number of reactions for the conference
$conference->reactions_counts; // Get the no of reactions for each emoji for the model
$conference->my_reactions; // Get the reactions for the current user
$conference->emoji_reactors // Get the list of users who reacted to the model, grouped by emoji
$conference->isAllowed('👍') // check if the app allows the user to react with the specified emoji
$conference->reactions_map // return the map of all the reactions for the model, grouped by emoji. This tells you the number of reactions for each emoji, and whether the current user has reacted with that emoji

To interact with the methods above with ease within and even outside Filament, this package comes with the following handy components:

Reactions Infolist Entry

use Coolsam\NestedComments\Filament\Infolists\ReactionsEntry;

public static function infolist(Infolist $infolist): Infolist
{
    return $infolist
        ->schema([
            Section::make('Basic Details')
                ->schema([
                    TextEntry::make('name'),
                    TextEntry::make('start_date')
                        ->dateTime(),
                    TextEntry::make('end_date')
                        ->dateTime(),
                    TextEntry::make('created_at')
                        ->dateTime(),
                        // Add the reactions entry
                    ReactionsEntry::make('reactions')->columnSpanFull(),
                ])->columns(4),
        ]);
}

image

Reactions Blade Component

Just include the blade component anywhere in your blade file and pass the model record to it.

$record = Conference::find(1); // Get your record from the database then,

In your view:

<x-nested-comments::reactions :record="$record"/>

Reactions Livewire Component

Similar to the blade component, you can use the Livewire component anywhere in your Livewire component and pass the model record to it.

$record = Conference::find(1); // Get your record from the database then,

In your view:

<livewire:nested-comments::reaction-panel :record="$record"/>

The two components can be used anywhere, in resource pages, custom pages, actions, form fields, widgets, livewire components or just plain blade views. Here is a sample screenshot of how the components will be rendered: image

Package Customization

You can customize the package by changing most of the default values in the config file after publishing it.

Testing

composer test

Open Source Dependencies

This package uses the following awesome open source packages, among many others under the hood:

I am grateful for the work that has been put into these packages. They have made it possible to build this package in a short time.

Changelog

Please see CHANGELOG for more information on what has changed recently.

Contributing

Please see CONTRIBUTING for details.

Security Vulnerabilities

Please review our security policy on how to report security vulnerabilities.

Credits

License

The MIT License (MIT). Please see License File for more information.