Browse documentationOpen

byrcsc/laravel-comments ยท 1.x

Quick start.

Make a post commentable, write a thread, moderate a guest comment, react, and render the section with the queries a comment list actually runs.

This walkthrough builds a comment section on a Post: an authenticated comment, a reply, a reaction, a guest comment held for moderation, and the queries that render the result.

1. Make the model commentable

use ByRcsc\LaravelComments\Concerns\HasComments;
use Illuminate\Database\Eloquent\Model;

class Post extends Model
{
    use HasComments;
}

2. Write a comment

$comment = $post->comment('Great write-up!', by: $user);

$by is any Eloquent model โ€” a user, an admin, a bot. The package stores it as a morph and never assumes it is App\Models\User.

3. Reply to it

$reply = $comment->reply('Agreed, especially the last section.', by: $teammate);

$reply->parent_id;  // the comment's key
$reply->depth();    // 1

Replies live on the same commentable as their parent and nest up to comments.max_depth, which is 3 by default. See threads and replies.

4. React to it

$comment->react('๐Ÿ‘', by: $teammate);

$comment->reactionSummary();  // ['๐Ÿ‘' => 1]

Reacting twice with the same reaction is a no-op that hands back the row that was already there, so a double tap cannot inflate a count. Reactions need an identity, so there is no guest path here. See reactions.

5. Take a guest comment

$guest = $post->commentAsGuest(
    'Where can I download the slides?',
    name: 'Jane',
    email: 'jane@example.com',
);

$guest->status;  // CommentStatus::Pending

Guest comments start pending whatever comments.default_status says. Approving anonymous content is a decision the package will not make for you. See initial status.

6. Moderate it

$guest->approve(by: $moderator);

The actor is optional and recorded on the event, not on the comment. Approving an already-approved comment returns false, writes nothing, and fires nothing. The other two transitions read the same way:

$spam->markAsSpam(by: $moderator);
$offTopic->reject(by: $moderator);

Nothing here hides the comment. Status is package state; visibility is your query. See moderation.

7. Render the thread

$threads = $post->comments()
    ->approved()
    ->topLevel()
    ->with('replies')
    ->get();

approved() is what decides what a visitor reads. topLevel() returns thread starters, and with('replies') brings each one's direct replies along โ€” nest it further (with('replies.replies')) to the depth your interface renders.

To hold announcements at the top of the list, add the pin ordering:

$threads = $post->comments()
    ->approved()
    ->topLevel()
    ->pinnedFirst()
    ->with(['replies', 'reactionCounts'])
    ->get();

Eager-loading reactionCounts renders every comment's reactions in one query for the page rather than one per comment.

8. Build a moderation queue

The package ships no queue model, because a scope is one:

$pending = Comment::query()
    ->pending()
    ->with('commentable')
    ->latest()
    ->paginate();

9. Authorize the calls

The engine's own methods never authorize anything โ€” they work in a queued job, a seeder, and a console command, where there is no authenticated actor to ask about. Enforcement belongs where your application calls the engine:

use ByRcsc\LaravelComments\Models\Comment;
use ByRcsc\LaravelComments\Policies\CommentPolicy;
use Illuminate\Support\Facades\Gate;

// A service provider
Gate::policy(Comment::class, CommentPolicy::class);

// A controller
$this->authorize('approve', $comment);
$comment->approve(by: $request->user());

The shipped policy denies every moderation ability by default. Extend it and register yours to say who moderates. See authorization.

10. Escape on output

The body is stored exactly as it arrived. So is the guest name.

{{ $comment->body }}

Blade escapes this. Anything that renders markdown or HTML has to sanitize first โ€” see rendering and safety.