tags-for-laravel maintained by roundly-consulting
Tags for Laravel
Typed taxonomies for any Eloquent model: flat labels or nested category trees, single- or multi-select, curated or free-form, global or tenant-scoped, and translatable in every locale — with autocomplete, usage counts and query scopes that never N+1.
Installation
Requires PHP 8.4, Laravel 12 or 13, and PostgreSQL 12+ or MySQL 8.0.23+.
composer require roundly-consulting/tags-for-laravel
php artisan vendor:publish --tag="tags-migrations"
php artisan migrate
Tag names are stored per locale: make sure your app locale is in translatable.locales (default en, sk).
Usage
Make a model taggable:
use Illuminate\Database\Eloquent\Model;
use RoundlyConsulting\Tags\Concerns\HasTags;
use RoundlyConsulting\Tags\Contracts\Taggable;
final class Concert extends Model implements Taggable
{
use HasTags;
}
Declare your types, build a tree, tag, query and suggest:
use RoundlyConsulting\Tags\Facades\Tags;
// Declare your tag types once, in a service provider
Tags::define('genre')->hierarchical()->single(); // a curated category tree, one per model
Tags::define('label')->max(5); // free-form labels, up to five
// Build the tree (names are translatable; a plain string is the current locale)
$music = Tags::type('genre')->make(['en' => 'Music', 'sk' => 'Hudba'])->color('#f24e29')->create();
$jazz = Tags::type('genre')->make('Jazz')->under($music)->create();
// Tag any model that uses HasTags
$concert->syncTags($jazz, 'genre');
$concert->attachTags(['Live', 'Outdoor'], 'label'); // unknown labels are created on the fly
// Query: "music" also matches everything under it
Concert::withAnyTags(['music'], 'genre', descendants: true)->get();
Concert::withAllTags(['live', 'outdoor'], 'label')->get();
// Read without N+1
foreach (Concert::with('tags')->get() as $concert) {
echo $concert->tagOf('genre')?->name; // Jazz
echo $concert->tagsOf('label')->pluck('name')->join(', '); // Live, Outdoor
}
// Autocomplete and popularity
Tags::type('label')->suggest('liv'); // prefix matches first, in every locale
Tags::type('label')->popular(10);
Documentation
The full documentation — configuration, every feature and its API, and testing — lives on our website: roundly-consulting.com/open-source/docs/tags-for-laravel
Release notes are in CHANGELOG.md. To contribute, see the contributing guide.
Support our work
This package is free and open source, built and maintained by Roundly Consulting. If it saves you time, please consider supporting our open-source work — a one-time donation, a monthly pledge on Patreon or a crypto donation helps fund maintenance, new features and new packages.
License
The MIT License (MIT). See LICENSE.md.