Installation:
composer require rtconner/laravel-tagging
php artisan vendor:publish --provider="Conner\Tagging\Providers\TaggingServiceProvider"
php artisan migrate
tagging table exists in your database.First Use Case:
Extend a model with the Taggable trait:
use Conner\Tagging\Taggable;
class Article extends Model
{
use Taggable;
}
Article instance:$article = new Article();
$article->tag('laravel');
$article->tag('php');
$article->save();
Where to Look First:
database/migrations/ for the tagging table structure.tag(), untag(), tags(), etc.Tagging Models:
// Add tags (creates or syncs)
$model->tag('tag1')->tag('tag2')->save();
// Sync tags (replaces existing)
$model->syncTags(['tag1', 'tag2']);
// Detach tags
$model->untag('tag1');
Querying Tagged Models:
// Find models with a specific tag
$articles = Article::tagged('laravel')->get();
// Find models with multiple tags (AND logic)
$articles = Article::tagged(['laravel', 'php'])->get();
// Find models with any of these tags (OR logic)
$articles = Article::whereAnyTag(['laravel', 'php'])->get();
Tag Management:
// Get all tags for a model
$tags = $model->tags;
// Get raw tag names (slugs)
$tagNames = $model->tagNames;
// Get tag count
$count = $model->tagCount;
Global Tag Operations:
// Get all tags used in the system
$allTags = \Conner\Tagging\Tag::all();
// Find models tagged with a specific tag globally
$models = \Conner\Tagging\Tag::findByName('laravel')->models;
Form Handling:
syncTags() in form submissions to avoid duplicate tags:
$request->validate(['tags' => 'required|array']);
$model->syncTags($request->tags);
API Responses:
return $model->load('tags')->toArray();
public function getTagsAttribute()
{
return $this->tags->pluck('name');
}
Admin Panels:
tagged() scopes to filter records in admin interfaces (e.g., Laravel Nova, Filament).Seeding:
syncTags():
$article = Article::create(['title' => 'Test']);
$article->syncTags(['seed', 'test']);
Caching:
$popularTags = Cache::remember('popular-tags', now()->addHours(1), function () {
return Tag::withCount('models')->orderBy('models_count', 'desc')->take(10)->get();
});
Case Sensitivity:
"Laravel" and "laravel" are treated as the same tag.Tag::findByName() with exact slugs if case sensitivity is required.Duplicate Tags:
tag() adds tags without checking for duplicates. Use syncTags() to avoid duplicates.$uniqueTags = array_unique($request->tags);
$model->syncTags($uniqueTags);
Performance with Large Datasets:
tagged() can be slow on tables with millions of records.tagging pivot table:
Schema::table('tagging', function (Blueprint $table) {
$table->index(['tag_id', 'taggable_id']);
});
Tag Deletion:
untag() or syncTags() to clean up.Model Polymorphism:
taggable column in the tagging table matches your models' morphKey.Tag Not Found:
tagged() returns no results, verify the tag slug exists in the tags table.Tag::findByName('tag-slug')->toSql() to check the query.Pivot Table Issues:
tagging pivot table for errors.dd($model->tags) after saving to inspect the relationship.Slug Conflicts:
Tag::boot()) may cause conflicts.getSlugFromName() method if needed:
use Conner\Tagging\Tag;
class CustomTag extends Tag
{
public static function getSlugFromName($name)
{
return Str::slug($name, '-').'-custom';
}
}
Custom Tag Model:
Tag model to add fields (e.g., color, description):
class Tag extends Conner\Tagging\Tag
{
protected $casts = ['color' => 'string'];
}
Tag Validation:
Tag model:
use Illuminate\Database\Eloquent\Model;
class Tag extends Conner\Tagging\Tag
{
protected static function boot()
{
parent::boot();
static::creating(function ($tag) {
$tag->name = Str::title($tag->name);
});
}
}
Custom Scopes:
Taggable trait:
use Conner\Tagging\Taggable;
class Article extends Model
{
use Taggable;
public function scopePopular($query)
{
return $query->whereHas('tags', function ($q) {
$q->orderBy('tags.created_at', 'desc');
})->limit(10);
}
}
Tag Events:
tagged, untagged):
use Conner\Tagging\Events\Tagged;
Tagged::listen(function ($model, $tag) {
Log::info("Model {$model->id} was tagged with {$tag->name}");
});
Localization:
getNameAttribute():
public function getNameAttribute($value)
{
return __($value);
}
How can I help you explore Laravel packages today?