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 writtenPinning 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
| Method | Event |
|---|---|
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.