Search by

roundly-consulting / tags-for-laravel

mihaliak

Typed taxonomies for any Eloquent model: flat or nested, single- or multi-select, curated or free-form, tenant-scoped and translatable, with autocomplete, usage counts and query scopes.

Package info

github.com/roundly-consulting/tags-for-laravel

Homepage

Documentation

pkg:composer/roundly-consulting/tags-for-laravel

Fund package maintenance!

Patreon

Statistics

Installs: 30

Dependents: 1

Suggesters: 0

Stars: 1

Open Issues: 0

1.0.1 2026-10-20 08:21 UTC

This package is auto-updated.

Last update: 2026-10-20 08:24:15 UTC


README

Tags for Laravel — Roundly open source

Latest release Tests Code style Donate Patreon Crypto

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.

Donate to Roundly open source Become a patron on Patreon Donate crypto: BTC, ETH, BNB or SOL

License

The MIT License (MIT). See LICENSE.md.