maize-tech/laravel-markable
Laravel Markable adds markable features like likes, bookmarks, favorites, and reactions to any Eloquent model. Install via composer, publish the migrations you need, and start tracking user interactions with simple traits.
Markable trait + mark model covers any entity, you can ship "save for later" on courses, "like" on posts, and "reaction" on comments from a single dependency. That makes it cheap to sequence engagement features incrementally instead of committing to a monolithic "social layer" epic.allowed_values (including wildcard * and BackedEnum classes as of 3.0.0) makes the reaction palette a config change. You can A/B test a 3-emoji palette against a 6-emoji palette, or scope different palettes per mark type, without a deploy-cycle negotiation with engineering.whereHasLike($user) / whereHasReaction($user, 'heart') scopes make "things I've saved/liked/reacted to" and "things this cohort reacted to" cheap to build — directly enabling personalization, digest emails, and re-engagement campaigns.Like::count($model)) but is not an analytics or aggregation layer. This is useful as a boundary-setting decision: engagement counters live here; funnels, cohorts, and time-series belong in your warehouse/event pipeline.Adopt it when:
$marks array, and published migrations.Look elsewhere — or budget for significant wrapping — when:
Dependents: 0 figure is a weak signal for app-level packages (few packages depend on them by nature) but should be read as: limited third-party evidence of long-term stability. 3.0.0 landed in April 2026 with a breaking major, which is a normal but real upgrade cost.Diligence items before committing: confirm the supported Laravel/PHP matrix against composer.json (changelogs show Laravel 10 and 11 support added; verify 12), confirm cascade-delete behavior on your own model deletions (1.0.1/1.0.2 addressed this, but re-verify on your schema), and confirm the JSON metadata column is sufficient for your attributes rather than needing first-class columns with indexes.
For executives — the one-paragraph version:
We have a recurring class of features — likes, saves, favorites, reactions — that every product team ends up hand-building, and that none of our customers buy us for. maize-tech/laravel-markable is a small, MIT-licensed, actively maintained Laravel package that provides that plumbing out of the box: one trait, published migrations, and a clean API for adding, removing, toggling, checking, and counting marks across any entity in our app. Adopting it converts a multi-sprint engagement epic into days of integration work, with no licensing cost and no vendor lock-in — it's a thin layer over our own database, so the exit cost if we ever outgrow it is low. The trade-offs are honest ones: it doesn't handle analytics, notifications, rate limiting, or high-volume counter caching, so we'd scope those as explicit follow-ons rather than assume them. Recommendation: adopt for engagement mechanics, keep our analytics and abuse-prevention in our own stack, and treat the dependency as replaceable.
For engineering — why this is the right shape:
It's an idiomatic Laravel package, not a framework. A Markable trait plus a $marks array registers marks on a model; each mark gets its own table (explicit, documented perf trade-off: fast per-mark queries), keyed by user_id + morphs('markable') + nullable value + JSON metadata + timestamps. The API is static and readable — Like::add/remove/toggle/has/count — with optional metadata payloads. Reaction values are validated against allowed_values in config, support a * wildcard, and accept BackedEnum cases for type safety (3.0.0). Eloquent relations (->likes, ->likers with value as pivot) and dynamic scopes (whereHasLike, whereHasReaction) mean we compose engagement into existing queries instead of bolting on a second data path. Custom marks are a migration plus a class extending Mark. Our integration work: publish only the migrations we need, add the trait to target models, and decide where moderation/throttling and any event dispatch must be layered on — those are our responsibility, not the package's. Budget accordingly: roughly a day to integrate, plus scoped work for abuse controls and any downstream eventing.
How can I help you explore Laravel packages today?