Weave Code
Code Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Laravel Tags Laravel Package

spatie/laravel-tags

Add flexible tagging to Laravel Eloquent models with the HasTags trait. Create, attach, detach, and query tags with ease, with built-in support for tag types, translations, and sorting—ideal for organizing content across your app.

View on GitHub
Deep Wiki
Context7

Getting Started

Minimal Setup

  1. Installation

    composer require spatie/laravel-tags
    php artisan migrate
    
    • Publishes tags and taggables tables automatically.
  2. Apply Trait Add HasTags to any Eloquent model:

    use Spatie\Tags\HasTags;
    
    class Article extends Model
    {
        use HasTags;
    }
    
  3. First Use Case Attach tags during model creation:

    $article = Article::create([
        'title' => 'Getting Started with Laravel Tags',
        'tags' => ['laravel', 'tags', 'spatie']
    ]);
    
    • Tags are auto-created if they don’t exist.

Implementation Patterns

Core Workflows

  1. Tag Management

    • Attach/Detach: Use attachTag(), detachTag(), or bulk methods (attachTags(), detachTags()).
      $article->attachTag('new-tag');
      $article->detachTag('old-tag');
      
    • Sync: Replace all tags with syncTags() or scoped types:
      $article->syncTags(['updated', 'tags']);
      $article->syncTagsWithType(['categories'], 'type');
      
  2. Querying Models by Tags

    • Scope Models: Use query builder scopes for flexible filtering:
      // Models with ANY of these tags
      Article::withAnyTags(['laravel', 'php'])->get();
      
      // Models with ALL tags
      Article::withAllTags(['laravel', 'tags'])->get();
      
      // Models without specific tags
      Article::withoutTags(['deprecated'])->get();
      
      // Scoped by tag type
      Article::withAnyTagsOfType('categories')->get();
      
  3. Tag Types

    • Assign tags to custom types (e.g., categories, topics):
      $article->attachTag('backend', 'categories');
      $article->tagsWithType('categories'); // Retrieve typed tags
      
  4. Translations

    • Localize tag names via setTranslation():
      $tag = Tag::findOrCreate('tag');
      $tag->setTranslation('name', 'fr', 'étiquette');
      $tag->save();
      
      // Fetch translated tags
      $article->tagsTranslated('fr');
      
  5. Sorting

    • Manually order tags using order_column:
      $tag1 = Tag::findOrCreate('first');
      $tag2 = Tag::findOrCreate('second');
      $tag1->swapOrder($tag2); // Swap positions
      

Integration Tips

  1. Form Handling

    • Use syncTags() in form submissions to avoid duplicate tags:
      $request->validate(['tags' => 'array']);
      $article->syncTags($request->tags);
      
  2. API Responses

    • Eager-load translated tags for consistency:
      return Article::with(['tagsTranslated' => function ($query) {
          $query->withTranslation('name');
      }])->find($id);
      
  3. Admin Panels

    • Leverage hasTag() for conditional UI:
      @if($article->hasTag('featured'))
          <span class="badge">Featured</span>
      @endif
      
  4. Testing

    • Seed tags in tests:
      $tag = Tag::findOrCreate('test-tag');
      $article = Article::factory()->create()->attachTag($tag);
      

Gotchas and Tips

Pitfalls

  1. Tag Creation Race Conditions

    • findOrCreate() may create duplicate tags if called concurrently. Use transactions or firstOrCreate() with unique constraints:
      Tag::firstOrCreate(['name' => 'tag'], ['slug' => Str::slug('tag')]);
      
  2. Tag Type Scope Confusion

    • withAnyTagsOfType() requires exact type matches. Typos (e.g., 'category' vs 'categories') return empty results.
  3. Translation Overwrites

    • Translations are stored per-tag. Updating a translation for one locale doesn’t affect others.
  4. PostgreSQL JSON Limitations

    • Translations rely on JSON fields. Ensure your PostgreSQL version supports jsonb operations.
  5. Dynamic Table Names

    • If using polymorphic taggables, ensure the taggable_type column matches your model’s fully qualified class name.

Debugging Tips

  1. Query Logs

    • Enable Laravel’s query logging to inspect scope queries:
      DB::enableQueryLog();
      Article::withAnyTags(['laravel'])->get();
      dd(DB::getQueryLog());
      
  2. Tag Existence

    • Verify tags exist before attaching:
      if (!$article->hasTag('missing-tag')) {
          $article->attachTag('missing-tag');
      }
      
  3. Type-Specific Issues

    • Check for typos in tag types:
      $article->tagsWithType('categories'); // Correct
      $article->tagsWithType('category');  // Returns empty
      
  4. Slug Conflicts

    • Customize the slugger in config/tags.php to avoid collisions:
      'slugger' => function ($name) {
          return Str::slug($name, '-', [' ']);
      },
      

Extension Points

  1. Custom Tag Models

    • Extend the Tag model to add fields (e.g., color):
      class Tag extends \Spatie\Tags\Tag
      {
          protected $fillable = ['color'];
      }
      
  2. Event Listeners

    • Hook into tag events (e.g., TagCreated):
      Tag::created(function ($tag) {
          // Log or notify when a new tag is created
      });
      
  3. Custom Scopes

    • Add reusable scopes to the HasTags trait:
      public function scopePopular($query)
      {
          return $query->withCount('taggables')->orderByDesc('taggables_count');
      }
      
  4. Validation Rules

    • Validate tag inputs in Form Requests:
      public function rules()
      {
          return [
              'tags' => 'required|array',
              'tags.*' => 'string|max:50',
          ];
      }
      
  5. Caching

    • Cache frequent tag queries (e.g., popular tags):
      Cache::remember('popular-tags', now()->addHours(1), function () {
          return Tag::withCount('taggables')->orderByDesc('taggables_count')->take(10)->get();
      });
      
Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
codraw/framework-extra-bundle
codraw/messenger
codraw/security
codraw/mailer
codraw/contracts
codraw/profiling
codraw/dependency-injection
codraw/tester
codraw/core
nexmo/api-specification
capell-app/block-library
axium/identity
cetria/laravel-dummy-models
cetria/reflection-helper
agropredict/sso-auth-bundle
evolvestudio/spam-protection
datacore/hub-sdk
develia/commons
cuci/prototurk-sdk
cuci/prototurk-sdk-symfony