NewWe open-sourced 50+ Laravel packages
Custom AI apps, agents and automation — Roundly ConsultingRoundly
All packages
Tags for Laravel

Querying models

Four query scopes on every taggable model, combined freely with the rest of your query — and the same implementation behind TagsFilter, so PHP and HTTP filter identically:

// Music, Jazz, Bebop, … — descendants: matches every tag below a hierarchical one
$page = Concert::withAnyTags(['music'], 'genre', descendants: true)
    ->withAllTags(['outdoor', 'free'], 'label')
    ->withoutTags(['sold-out'], 'label')
    ->paginate();

Concert::withoutTags(type: 'genre')->count();      // concerts with no category yet
Concert::withoutTags()->count();                   // concerts with no tag at all
Concert::withTagsOf('label')->count();             // concerts with at least one label

Concert::withAnyTags([$jazz, $rock])->get();       // models carry their own type
Concert::withAllTags(['live', 'unknown'], 'label')->get();   // an unknown string matches nothing
ScopeMeaning
withAnyTags($tags, $type = null, descendants: false, within: null)Models carrying at least one of the tags.
withAllTags($tags, $type = null, descendants: false, within: null)Models carrying every one of them — each satisfied by itself or, with descendants, by a tag below it. A string that names no tag matches no model.
withoutTags($tags = [], $type = null, descendants: false, within: null)Models carrying none of them; with no tags, models with no tag of the type — or no tag at all without a type.
withTagsOf($type)Models carrying at least one tag of the type.
  • Inputs are tag models, keys or strings, like the tagging verbs. Strings resolve without creating; an unknown string matches nothing — in withAllTags that means no model.
  • A type narrows strings to that type and the match to taggings of it. Without a type, strings use the default type and models and keys carry their own.
  • Each scope is a whereIn over a taggings subquery: no join, no duplicate rows, safe to paginate.
  • The tagging pivot and the model must share one database connection — tags:doctor warns when a model lives elsewhere.

From a tag to its models

$tag->taggedModels(Concert::class) is the inverse relation, read-only like tags(); $tag->taggings() returns the raw pivot rows.

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 crypto

By 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.