Browse documentationOpen

byrcsc/laravel-comments · 1.x

Pinning.

Hold comments at the top of a thread, order a listing with pinnedFirst(), and keep pins independent of moderation.

Pinning holds a comment at the top of its thread — a pinned answer, an announcement, a correction from the author. It is a timestamp on the comment and an ordering scope, and nothing else.

Pin and unpin

$comment->pin(by: $moderator);
$comment->unpin(by: $moderator);

The actor is optional and recorded on the event, not on the comment. Both methods return whether anything moved:

$comment->pin();  // true
$comment->pin();  // false — already pinned, nothing written

Pinning a pinned comment leaves the original pinned_at alone, so its position in the thread does not shuffle under a second click.

Order a listing

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

pinnedFirst() orders pinned comments first, most recently pinned among them, then everything else oldest first — which is the order a thread reads in.

The null handling is spelled out rather than left to the driver: MySQL and SQLite sort nulls first, PostgreSQL sorts them last, and a listing whose order depends on the engine is a bug waiting for a migration.

To read only the pinned ones — a "pinned answers" strip above the thread:

$post->comments()->approved()->pinned()->get();

Several pins at once

The engine enforces no ceiling. A product that pins three announcements is not doing anything wrong, so the limit belongs in your controller:

$post->comments()->pinned()->each->unpin();

$comment->pin(by: $request->user());

Independent of moderation

A pinned comment keeps whatever status it had, and moderating one leaves its pin alone. The two never move each other, and pinning records no revision and does not stamp edited_at — it changes what the package knows about the comment, not what its author wrote.

Nothing stops you pinning a pending comment. Whether a pinned comment is visible is still decided by your query.

Events

MethodEvent
pin()CommentPinned
unpin()CommentUnpinned

Both extend CommentPinChanged and carry the comment and the actor. Neither fires when nothing moved, so one event means one real change — which is what an activity feed downstream is built on.

use ByRcsc\LaravelComments\Events\CommentPinned;
use ByRcsc\LaravelComments\Events\CommentUnpinned;
use ByRcsc\LaravelComments\Events\CommentPinChanged;
use Illuminate\Support\Facades\Event;

Event::listen(
    [CommentPinned::class, CommentUnpinned::class],
    fn (CommentPinChanged $event) => $this->logPinChange($event->comment, $event->actor),
);

Authorization

pin and unpin are abilities on the shipped CommentPolicy, and both deny by default. See authorization.