Open source
Likes for Laravel
composer require roundly-consulting/likes-for-laravelOverview
Native likes and reactions for Laravel. Any Eloquent model can give likes, any model can receive them, and a single polymorphic likes table records who liked what — with idempotent verbs, optional typed reactions, popularity and trending ranking, single-query feed hydration and events your app can listen to. MIT-licensed and built only on Laravel’s own components plus the Roundly package toolkit — no third-party dependencies.
What you get
Any actor, any likeable
Users, teams or any Eloquent model can give likes to any other model — one polymorphic likes table records who liked what.
Idempotent verbs
like(), unlike() and toggleLike() return the is-liked-now state; repeats are no-ops and a re-like restores the old row.
Typed reactions
Opt into love, wow or your own set via an allowlist, and switch a reaction in place with a clean ReactionChanged event.
Feeds without N+1
withLikedState() and withLikesCount() hydrate the viewer’s state and counts for a whole page in a single query.
Weighted & trending ranking
Rank by a weighted reaction score or recency-boosted trending activity — portable SQL for SQLite, MySQL and PostgreSQL.
Events & opt-in broadcasting
Liked, Unliked and ReactionChanged fire only on real changes and can broadcast over Laravel Echo when you turn it on.
Testing toolkit
A recording Likes::fake(), acting-actor helpers, Pest matchers and a model factory for your own test suite.
Documentation
Installation
Install via Composer, then publish and run the likes migration — publish the config first for UUID or ULID keys or a custom table name.
Configuration
Every config key and its default — model, table, key type, reactions, actor resolver, weights, trending and broadcasting.
Database schema & key types
The single polymorphic likes table, soft deletes, UUID/ULID key types and swapping in your own Like model.
Models & traits
Add HasLikes to models that can be liked and GivesLikes to actors; the relations, the Likeable contract and the Like model.
The Likes facade
One-line likes as the signed-in user, the actor()/as() builder, the Likes::for() read handle and custom actor resolution.
DI and actions
Skip the facade: inject LikeManager or call a single-purpose action with a LikeData DTO — the facade method → action map.
Liking, unliking & toggling
Idempotent like, unlike and toggle through the Likes facade or the model trait, returning the is-liked-now state, plus bulk likeMany().
Checking state & counting
Check whether an actor liked a model and count likes with Likes::has() and Likes::for() — live or from an eager-loaded count.
Query scopes
Order by like count, filter to what an actor liked or didn’t, and hydrate likes_count — all composable, all typed.
Feed hydration (no N+1)
withLikedState() adds is_liked and liked_reaction for the viewer to a whole feed page in one query — guest-safe.
Weighted score & trending
Rank by a weighted reaction score or recency-boosted trending activity, with portable SQL across SQLite, MySQL and PostgreSQL.
Typed reactions
Turn plain likes into typed reactions — love, wow, laugh or your own set — guarded by a config allowlist.
Switching reactions
react() keeps one active reaction per actor and item, switching it in place and firing only ReactionChanged.
Reaction breakdown
Likes::for()->summary() returns totals, per-type counts, the top reaction and the viewer’s own reaction for reaction bars.
What an actor liked
likedItems() and likesOf() return a real MorphToMany of the models an actor likes — eager-loadable and paginatable.
Blade directive
The @liked conditional renders the right heart state for the current or an explicit actor and reaction type.
JSON API output
LikeResource and toLikeArray() return the like count, the viewer’s state and the per-reaction breakdown as JSON.
Events
Liked, Unliked and ReactionChanged fire only on real changes, one event per change — plus an optional persisted counter column.
Broadcasting
Opt-in broadcasting of Liked, Unliked and ReactionChanged over Laravel Echo on likes.{morph}.{id} channels.
Exceptions
InvalidReactionTypeException, NoAuthenticatedActorException and their shared LikesException base.
Testing
Likes::fake() records every like, unlike and reaction while still writing rows — plus acting-actor helpers, Pest matchers and a Like factory.
Requirements
PHP 8.4+, Laravel 12 or 13, and the Roundly package toolkit — no PHP extensions or third-party packages.
Show your open-source love
This package is free and MIT-licensed. If it saves you time, a one-off donation or a Patreon membership keeps it maintained, tested and documented.
More ways to support, including cryptoBy donating, you agree to our donation terms.
Want this built into your product?
We integrate our packages into custom Laravel and AI builds. Tell us what you're working on and we'll reply within 48 hours.