Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Likes Laravel Package

flarum/likes

Flarum Likes adds a familiar like button to every post, letting community members show appreciation with one click. It displays like counts, supports notifications for liked posts, and integrates cleanly with Flarum's permission and discussion systems.

Deep Wiki
Context7

Getting Started

flarum/likes is not a standalone Laravel package — it's the bundled "Likes" extension for Flarum, and it ships as a normal Composer dependency in a default Flarum install (composer show flarum/likes will list it). It runs on Flarum's extender/service-provider model over Illuminate components, so treat it as a reference implementation of a Flarum feature, not a library you use from a generic app.

Where to look first, in this order:

  1. extend.php — every router, serializer attribute, event listener, and notification type the extension registers. This is the map.
  2. src/Listener/SaveLikesToDatabase.php — the actual attach/detach on the post_likes pivot, plus the denormalized counter update on posts.likes.
  3. src/Event/PostWasLiked.php / PostWasUnliked.php — the two public extension points most people actually use.
  4. src/Notification/PostLikedBlueprint.php — how the "X liked your post" alert is addressed and rendered.
  5. js/src/forum/components/LikeButton.* and resources/locale/en.yml — frontend wiring and translation keys.

Minimum first use case: react to a like in your own extension. Do not edit vendor/flarum/likes; register a listener from your extension's extend.php:

use Flarum\Extend;
use Flarum\Likes\Event\PostWasLiked;
use Flarum\Likes\Event\PostWasUnliked;

return [
    (new Extend\Event())
        ->listen(PostWasLiked::class, function (PostWasLiked $e) {
            // $e->post is the liked Post; $e->user is the acting (liking) user.
            // Do not notify here — PostLikedBlueprint already does that.
        })
        ->listen(PostWasUnliked::class, function (PostWasUnliked $e) {
            // reversal logic
        }),
];

Verify the wire format with a real request — GET /api/posts/{id} returns the like count and an actor-relative "has liked" flag on the post payload.

Implementation Patterns

Event-driven side effects (the 80% case). Likes, badges, gamification, webhooks, analytics, Slack pings — all of it belongs in a PostWasLiked listener in your extension. Have the listener implement ShouldQueue and register it via (new Extend\Event())->subscribe(...); the like action is a synchronous HTTP request and a slow listener makes the button feel broken. If your listener needs the post_likes row to already exist, check whether your Flarum version honors listener priority in Extend\Event::listen() — the extension's own persistence listener is registered at load order, not "first".

Extending the API payload. The post serializer already exposes the count and an actor-specific boolean. Add derived fields rather than new endpoints:

use Flarum\Api\Serializer\PostSerializer;
use Flarum\Extend;

return [
    (new Extend\ApiSerializer(PostSerializer::class))
        ->attributes(function (PostSerializer $serializer, $post, array $attributes) {
            $attributes['likesLabel'] = $post->likes >= 1000
                ? round($post->likes / 1000, 1) . 'k'
                : (string) $post->likes;
            return $attributes;
        }),
];

If you genuinely need a list of who liked a post (the default API deliberately does not expose one), add your own relationship field or a dedicated endpoint, and gate it behind an admin/mod permission — liker identity is semi-private data.

Customizing the notification. PostLikedBlueprint is registered with the alert channel by the extension itself. Re-registering the same type from another extension will collide; the safe routes are (a) listen to Flarum\Notification\Event\Sending and mutate/suppress, or (b) bind a decorated blueprint subclass in the container. Never bypass the notification preference check — users who turned off postLiked alerts must stay opted out.

Reporting and backfills. The post_likes pivot (post_id, user_id, created_at) is a perfectly good analytics table:

DB::table('post_likes')
    ->selectRaw('DATE(created_at) AS day, COUNT(*) AS likes')
    ->groupBy('day')
    ->orderBy('day')
    ->get();

If you import likes from another forum, insert into post_likes and recompute posts.likes in the same transaction — the counter is denormalized and nothing recalculates it for you.

Frontend customization. Extend CommentPost.prototype actionItems, or subclass LikeButton and swap the item, from your extension's js/src/forum/index. New strings go under the flarum-likes.* namespace or your own; don't hardcode English in the component.

Gotchas and Tips

  • Read-only subtree split. This repo is generated from the Flarum monorepo; PRs and issues here are ignored and the next split overwrites them. Contribute upstream, and pin your fork with a VCS repository entry rather than editing vendor/.
  • The likes column is a cache, not the truth. Any manual insert/delete into post_likes (seeders, admin tools, user deletion) that skips the counter update produces permanent drift. Audit with SELECT posts.id FROM posts LEFT JOIN post_likes ON ... HAVING posts.likes <> COUNT(*) before blaming the UI.
  • Orphan rows. Verify your Flarum version cascades post_likes on user/post deletion. Older migrations did not always; orphaned pivot rows inflate counts after a recount and can break "who liked this" queries.
  • Actor-dependent serialization. The "has liked" flag is per-viewer. Never cache a serialized post payload at the CDN/proxy layer without varying by user, and never stash it in a model attribute reused across actors.
  • Don't PATCH likes. The count is guarded; the like/unlike flow goes through the extension's dedicated routes (currently POST/DELETE /api/posts/{id}/likes — confirm the exact shape in extend.php, it has changed across Flarum versions). Attempting to set the integer via the post update endpoint silently does nothing.
  • Visibility is enforced by the post lookup. The like route resolves the post through the actor's visibility scope; your custom endpoints must do the same (Post::whereVisibleTo($actor)) or you'll let users like posts in tags/discussions they can't read.
  • Rebuild after frontend changes. php flarum cache:clear for PHP/extender changes; cd js && npm run dev while developing, npm run build (or php flarum assets:publish) for production. A stale JS bundle is the most common "my LikeButton change does nothing" cause.
  • Translations are namespaced. flarum-likes.forum.post.like_link and friends; overriding one key in your locale file is safer than shadowing the whole component.
  • Testing. In HTTP tests, hit the like route with actingAs() and the JSON:API content type; the CSRF middleware is disabled in Flarum's test case. For pure logic, dispatch PostWasLiked directly — but remember the persistence listener also runs, so wrap DB assertions accordingly.
Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
middlewares/firewall
qubiqx/montapacking
nyoncode/laravel-package-console
pnscripts/filament-broadquill-lite
pnscripts/laravel-sentfold-lite
vleap/mx-sdk-laravel-internal
twidpay/utils
htetmyathlaing/scout-elasticsearch-driver
artisan-toolbox/front-awesome
ls/client-assistant
users-au/laravel-client
robertmarney/lara-hierarchial-collections
simonschaufi/rule-doc-generator
emissaoja/emissaoja
blackbricksoftware/gravityforms-civicrm-form-processor
al-rahabi/fancy-crud
jinas/dhivatar-component
mltstephane/laravel-quality
bernskiold/laravel-talentlms
bernskioldmedia/laravel-form-architect