tomatophp/tomato-category
Tomato Category is a category management package for TomatoPHP/Laravel apps, offering nested, sortable categories with an admin interface, API endpoints, and easy integration for organizing content across your projects.
Feature scoping — ship taxonomy now, cheaply. The package provides a working categories/tags/types system that attaches polymorphically to any Eloquent model, plus the admin CRUD and forms. The decision it unblocks is "do we build categorization into this release?" — and the answer becomes yes-at-low-cost for CMS content, product catalogs, document tagging, help-center topics, or internal asset classification, without commissioning a new schema or admin surface.
Build vs. buy for admin tooling. Treat it as an adopt-and-vendor accelerator, not a platform dependency. It replaces roughly one to two weeks of migrations, models, controllers, and forms — but only inside the Splade/TomatoPHP admin stack. Outside that stack the buy case collapses; a thin bespoke taxonomy model is cheaper than porting this one.
Stack standardization. Its value is a data point in the larger question of whether to standardize on TomatoPHP/Splade for internal admin. If Splade is already the admin layer, this is a near-free add-on. If it isn't, this package alone must never be the reason to adopt the stack.
Roadmap sequencing — validate faceted filtering before paying for search. The type discriminator (category vs. tag vs. type) is a cheap way to prove users actually filter by taxonomy before committing budget to Meilisearch, Typesense, or Elastic. Learn demand first, buy the index second.
Maintenance-ownership decision. Zero stars, zero dependents, and no release since June 2024 makes adoption a fork-and-own call. That reframes the roadmap line item from "integrate a package" to "vendor the code, assign a named owner, set a review date." Budget the owner; that is the real cost.
Blast-radius control. Best suited to internal admin panels, back-office tooling, and MVP prototypes where ripping it out later is contained. State explicitly that it does not belong on customer-facing or revenue-critical paths — don't leave that to engineering judgment.
Locale and content-ops scope. Categories can be translatable, supporting multi-language content plans — but confirm it before promising: translation depends on spatie/laravel-translatable being wired up, and per-locale labels are not a full translation workflow.
Consider it when:
Look elsewhere when:
spatie/laravel-tags plus a resource is the lighter, better-supported bet.kalnoy/nestedset), adjacency lists with real tree operations, translated term management, term merging, or audit trails.To executives: This is a small, MIT-licensed accelerator that gives us categories, tags, and types for any content type in our admin panel — roughly one to two weeks of build for the cost of an afternoon's install. It is the cheapest possible way to test whether taxonomy-driven navigation and filtering are worth investing in before we pay for a search backend. The trade-off is explicit: nobody else maintains it, so we own it. That means a named engineer, a pinned version, and a scheduled review — a contained, reversible bet we should keep off revenue-critical surfaces.
To engineering: Read it before you trust it. It is a schema + trait + resource bundle, not a framework: Category model with a string type discriminator, a polymorphic pivot, and a trait over morphToMany. Five files — models, migrations, traits, config, admin resource — de-risk the whole thing in about fifteen minutes. Do three things on day one: enforce a morph map so class renames don't orphan pivot rows, define typed relationships (tags(), categories()) on our own models instead of scattering where('type', ...), and wrap it behind our own interface so swapping to spatie/laravel-tags later stays a contained change. Pin the exact version, add the missing cascade constraints yourself, and write one pivot feature test as our canary for the fork we should assume is coming.
How can I help you explore Laravel packages today?