Skip to content

Tags ​

Siteman CMS includes a robust tagging system powered by Spatie's Laravel Tags package. Tags help you organize and categorize content, making it easier for users to discover related pages and posts.

Understanding Tags ​

Tags are labels or keywords attached to pages that:

  • Group related content together
  • Enable content discovery through tag-based navigation
  • Create automatic taxonomy pages
  • Improve SEO through topical clustering
  • Provide metadata for filtering and searching

Managing Tags in the Admin Panel ​

Adding Tags to Pages ​

When creating or editing a page:

  1. Navigate to Content > Pages
  2. Create or edit a page
  3. Find the Tags field in the page form
  4. Start typing tag names:
    • Existing tags will appear as suggestions
    • Press Enter to create a new tag
    • Multiple tags can be added
  5. Save the page

Tags are created automatically when you type them - no need to pre-create tags.

Tag Auto-Complete ​

The tag field provides auto-complete functionality:

  • Type to search existing tags
  • See tag usage count
  • Select from suggestions or create new tags

Tag Index Pages ​

Create dedicated pages that display all content with a specific tag.

Creating a Tag Index Page ​

  1. Navigate to Content > Pages
  2. Click New Page
  3. Configure:
    • Title: "Tags" or "Topics"
    • Slug: "/tags"
    • Type: Select "Tag Index"
    • Published At: Current date/time
  4. Click Create

The Tag Index will display all pages tagged with tags matching the URL pattern /tags/{tag-slug}.

How Tag Index Works ​

When a user visits /tags/laravel, the Tag Index page automatically:

  • Finds all published pages with the "laravel" tag
  • Displays them in reverse chronological order
  • Provides pagination
  • Shows tag metadata

Customizing Tag Views ​

Tag Index Template ​

Create a custom view for tag index pages in your theme:

resources/views/siteman/themes/my-theme/tags/index.blade.php

Example template:

blade
<x-my-theme::layout :page="$page">
    <div class="tag-index">
        <header>
            <h1>{{ $tag->name }}</h1>
            @if($tag->description)
                <p class="description">{{ $tag->description }}</p>
            @endif
            <p class="count">{{ $pages->total() }} {{ Str::plural('post', $pages->total()) }}</p>
        </header>

        <div class="tagged-content">
            @forelse($pages as $taggedPage)
                <article class="content-preview">
                    @if($taggedPage->hasMedia('featured_image'))
                        <img src="{{ $taggedPage->getFirstMediaUrl('featured_image', 'thumb') }}"
                             alt="{{ $taggedPage->title }}">
                    @endif

                    <h2>
                        <a href="{{ $taggedPage->computed_slug }}">
                            {{ $taggedPage->title }}
                        </a>
                    </h2>

                    <div class="meta">
                        <span class="date">{{ $taggedPage->published_at->format('F j, Y') }}</span>
                        <span class="author">By {{ $taggedPage->author->name }}</span>
                    </div>

                    <div class="excerpt">
                        {{ $taggedPage->getMeta('description', Str::limit($taggedPage->content, 150)) }}
                    </div>

                    <a href="{{ $taggedPage->computed_slug }}">Read more →</a>
                </article>
            @empty
                <p>No content found with this tag.</p>
            @endforelse
        </div>

        {{ $pages->links() }}

        <footer>
            <a href="/tags" class="back">← All tags</a>
        </footer>
    </div>
</x-my-theme::layout>

All Tags Archive Page ​

Create a page listing all available tags:

blade
{{-- resources/views/siteman/themes/my-theme/tags/archive.blade.php --}}

<x-my-theme::layout :page="$page">
    <div class="tags-archive">
        <h1>Browse by Topic</h1>

        <div class="tag-cloud">
            @foreach($tags as $tag)
                <a href="/tags/{{ $tag->slug }}"
                   class="tag"
                   style="font-size: {{ $tag->pages_count * 0.2 + 1 }}rem">
                    {{ $tag->name }}
                    <span class="count">({{ $tag->pages_count }})</span>
                </a>
            @endforeach
        </div>
    </div>
</x-my-theme::layout>

Working with Tags Programmatically ​

Attaching Tags ​

php
use Siteman\Cms\Models\Page;

$page = Page::find(1);

// Attach single tag
$page->attachTag('laravel');

// Attach multiple tags
$page->attachTags(['laravel', 'php', 'tutorial']);

// Attach tag by ID
$page->attachTag(5);

Syncing Tags ​

Replace all existing tags with a new set:

php
// Remove all existing tags and add these
$page->syncTags(['laravel', 'filament']);

// Clear all tags
$page->syncTags([]);

Detaching Tags ​

php
// Remove single tag
$page->detachTag('outdated');

// Remove multiple tags
$page->detachTags(['draft', 'wip']);

// Remove all tags
$page->detachTags();

Retrieving Tags ​

php
// Get all tags for a page
$tags = $page->tags;

// Get tag names as array
$tagNames = $page->tags->pluck('name')->toArray();

// Check if page has a tag
if ($page->hasTag('laravel')) {
    // ...
}

// Check if page has any of these tags
if ($page->hasAnyTag(['laravel', 'php'])) {
    // ...
}

// Check if page has all these tags
if ($page->hasAllTags(['laravel', 'tutorial'])) {
    // ...
}

Querying Pages by Tag ​

Find Pages with Specific Tags ​

php
use Siteman\Cms\Models\Page;

// Pages with any of these tags
$pages = Page::withAnyTags(['laravel', 'php'])
    ->published()
    ->get();

// Pages with all of these tags
$pages = Page::withAllTags(['laravel', 'tutorial'])
    ->published()
    ->get();

// Pages without these tags
$pages = Page::withoutTags(['draft', 'archived'])
    ->published()
    ->get();

Get Tag with Pages Count ​

php
use Spatie\Tags\Tag;

// Get all tags with page count
$tags = Tag::has('pages')
    ->withCount('pages')
    ->orderBy('pages_count', 'desc')
    ->get();

// Get popular tags (5 most used)
$popularTags = Tag::withCount('pages')
    ->orderBy('pages_count', 'desc')
    ->take(5)
    ->get();

Tag Model ​

The Tag model includes these useful methods and attributes:

php
use Spatie\Tags\Tag;

$tag = Tag::findFromString('laravel');

// Properties
$tag->name;        // Display name (e.g., "Laravel")
$tag->slug;        // URL-friendly slug (e.g., "laravel")
$tag->type;        // Tag type (default: null)
$tag->order_column; // Sort order

// Relationships
$tag->pages;       // All pages with this tag

// Methods
$tag->scopeContaining($query, $name); // Search tags

Tag Types ​

Organize tags into different types (taxonomies):

php
// Add tags with specific types
$page->attachTag('laravel', 'technology');
$page->attachTag('beginner', 'level');
$page->attachTag('2024', 'year');

// Query by tag type
$techTags = Tag::where('type', 'technology')->get();

// Get tags by type from page
$techTags = $page->tagsWithType('technology');

Displaying Tags in Templates ​

Tag List ​

blade
{{-- Simple tag list --}}
<div class="tags">
    @foreach($page->tags as $tag)
        <a href="/tags/{{ $tag->slug }}" class="tag">
            {{ $tag->name }}
        </a>
    @endforeach
</div>

Tag Cloud ​

blade
{{-- Tag cloud with size based on usage --}}
@php
    $tags = \Spatie\Tags\Tag::withCount('pages')->get();
    $maxCount = $tags->max('pages_count');
@endphp

<div class="tag-cloud">
    @foreach($tags as $tag)
        @php
            $size = ($tag->pages_count / $maxCount) * 2 + 0.8; // Scale between 0.8 and 2.8rem
        @endphp
        <a href="/tags/{{ $tag->slug }}"
           class="tag"
           style="font-size: {{ $size }}rem">
            {{ $tag->name }}
        </a>
    @endforeach
</div>
blade
@if($page->tags->isNotEmpty())
    @php
        $relatedPages = \Siteman\Cms\Models\Page::withAnyTags($page->tags->pluck('name'))
            ->where('id', '!=', $page->id)
            ->published()
            ->take(3)
            ->get();
    @endphp

    @if($relatedPages->isNotEmpty())
        <aside class="related-posts">
            <h3>Related Articles</h3>
            <ul>
                @foreach($relatedPages as $relatedPage)
                    <li>
                        <a href="{{ $relatedPage->computed_slug }}">
                            {{ $relatedPage->title }}
                        </a>
                    </li>
                @endforeach
            </ul>
        </aside>
    @endif
@endif

Tag Slug Generation ​

Tags automatically generate URL-friendly slugs:

php
$page->attachTag('Laravel & PHP'); // Creates slug: "laravel-php"
$page->attachTag('Web Development'); // Creates slug: "web-development"

Slugs are:

  • Lowercase
  • Spaces replaced with hyphens
  • Special characters removed
  • Unique per tag

Tag Management Best Practices ​

  1. Consistent Naming: Use consistent capitalization (e.g., "Laravel" not "laravel")
  2. Avoid Redundancy: Don't use both "php" and "PHP"
  3. Specific over General: "Laravel 11" is better than just "Laravel" for version-specific content
  4. Limit Tag Count: Use 3-7 tags per page for optimal organization
  5. Create Tag Guidelines: Document your tagging strategy for contributors
  6. Review Periodically: Merge similar tags and remove unused ones

Sitemap Integration ​

Include tagged pages in your sitemap:

php
// In your sitemap controller
$tags = Tag::has('pages')->get();

foreach ($tags as $tag) {
    $sitemap->add(
        url("/tags/{$tag->slug}"),
        $tag->updated_at,
        '0.6',
        'weekly'
    );
}

SEO Considerations ​

  • Tag Meta Descriptions: Add descriptions to tag pages for better SEO
  • Canonical URLs: Ensure tag pages have canonical URLs
  • No-Index: Consider no-indexing tags with very few pages
  • Structured Data: Add structured data for better search visibility

Advanced Tag Features ​

Custom Tag Attributes ​

Extend the Tag model to add custom attributes:

php
// Migration
Schema::table('tags', function (Blueprint $table) {
    $table->string('description')->nullable();
    $table->string('color')->nullable();
    $table->string('icon')->nullable();
});

// Usage
$tag = Tag::findFromString('laravel');
$tag->update([
    'description' => 'All about Laravel framework',
    'color' => '#FF2D20',
    'icon' => 'laravel-icon.svg',
]);

Tag Translations ​

For multi-language sites, use Spatie's Laravel Tags Translation features.

  • Blog - Organize blog posts with tags
  • Page Types - Understanding Tag Index page type
  • Themes - Customize tag page appearance

Released under the MIT License.