PHP code example of shammaa / laravel-seo

1. Go to this page and download the library: Download shammaa/laravel-seo library. Choose the download type require.

2. Extract the ZIP file and open the index.php.

3. Add this code to the index.php.
    
        
<?php
require_once('vendor/autoload.php');

/* Start to develop here. Best regards https://php-download.com/ */

    

shammaa / laravel-seo example snippets


'site' => [
    'name' => 'Your Site Name',
    'description' => 'Your site description',
    'url' => 'https://yoursite.com',
    'logo' => 'path/to/logo.jpg',
],

use Shammaa\LaravelSEO\Services\SEOService;

// In AppServiceProvider or a dedicated SEOServiceProvider
public function boot(): void
{
    SEOService::setSiteDataResolver(function () {
        $settings = cache()->remember('site_settings', 86400, function () {
            return \App\Models\Setting::first();
        });
        
        return [
            'name' => $settings->site_name ?? config('app.name'),
            'description' => $settings->site_description ?? '',
            'logo' => $settings->site_logo ?? null,
            'publisher' => $settings->publisher_name ?? $settings->site_name,
            // Social media links for sameAs in Organization schema
            'same_as' => array_filter([
                $settings->facebook_url,
                $settings->twitter_url,
                $settings->instagram_url,
                $settings->youtube_url,
                $settings->linkedin_url,
                $settings->telegram_url,
            ]),
        ];
    });
}

// In your Settings controller after update:
cache()->forget('site_settings');
cache()->forget('seo_site_data_' . app()->getLocale());

use Shammaa\LaravelSEO\Facades\SEO;

public function show(Post $post)
{
    SEO::post($post)->set();
    return view('post.show', compact('post'));
}

public function index()
{
    SEO::home()->set();
    return view('home');
}

public function show(Post $post)
{
    SEO::post($post)->set();
    return view('post.show', compact('post'));
}

public function show(Category $category)
{
    SEO::category($category)->set();
    return view('category.show', compact('category'));
}

public function show(Product $product)
{
    SEO::product($product)->set();
    return view('product.show', compact('product'));
}

public function search(Request $request)
{
    SEO::search(['query' => $request->get('q')])->set();
    return view('search.results');
}

public function show(Tag $tag)
{
    SEO::tag($tag)->set();
    return view('tag.show', compact('tag'));
}

public function show(Author $author)
{
    SEO::author($author)->set();
    return view('author.show', compact('author'));
}

public function archive(string $date)
{
    SEO::archive($date)->set();
    return view('archive.show', compact('date'));
}

public function show(Page $page)
{
    SEO::page($page)->set();
    return view('page.show', compact('page'));
}

public function show(CustomModel $model)
{
    SEO::for('custom', $model)->set();
    return view('custom.show', compact('model'));
}

public function show(Post $post)
{
    // 1. Just set the author model (Auto-detects URL/Image)
    SEO::post($post)->withAuthor($user)->set();
    
    // 2. Override Author URL and Image Field Name
    SEO::post($post)
        ->withAuthor(
            $user, 
            url: 'https://mysite.com/authors/custom-url', // Custom URL
            image: 'avatar_url' // Custom image field name in User model
        )
        ->set();

    // 3. Override Author URL and Image URL directly
    SEO::post($post)
        ->withAuthor(
            $user, 
            url: 'https://mysite.com/authors/me',
            image: 'https://mysite.com/images/me.jpg' // Direct Image URL
        )
    // 4. Use Route Name (Recommended)
    // Automatically calls route('authors.show', $user)
    SEO::post($post)
        ->withAuthor($user, 'authors.show')
        ->set();
        
    return view('post.show', compact('post'));
}

SEO::post($post)->set()->addVideo([
    'video_url' => 'https://www.youtube.com/watch?v=dQw4w9WgXcQ',
    'title' => 'My Video Title', // Optional, defaults to page title
    'description' => 'Video description', // Optional, defaults to page description
    'image' => 'https://example.com/thumb.jpg', // Optional, defaults to page image
    'uploadDate' => '2024-01-01', // Optional
]);

// In Post Model
public function getVideoUrlAttribute()
{
    // Return Youtube/Vimeo URL
    return $this->meta['video_link'] ?? null;
}

SEO::post($article)->set()->addFAQ([
    [
        'question' => 'What is this about?',
        'answer' => 'This article explains...'
    ],
    [
        'question' => 'How does it work?',
        'answer' => 'It works by...'
    ],
]);

// In your Model
class Post extends Model
{
    use HasSEO;
    
    public function faqs()
    {
        return $this->hasMany(FAQ::class);
    }
}

// In Controller - Automatic!
SEO::post($post)->set(); // Automatically detects and adds FAQs

SEO::post($tutorial)->set()->addHowTo(
    name: 'How to Cook Kabsa',
    steps: [
        'Wash the rice thoroughly',
        'Cook the meat with spices',
        'Mix rice with meat',
        'Cook on low heat for 30 minutes'
    ],
    description: 'A simple guide to cooking traditional Kabsa',
    image: '/images/kabsa.jpg'
);

SEO::post($tutorial)->set()->addHowTo(
    name: 'How to Build a Website',
    steps: [
        [
            'name' => 'Choose a Domain',
            'text' => 'Select and register your domain name',
            'image' => '/images/step1.jpg',
            'url' => '/steps/1'
        ],
        [
            'name' => 'Set Up Hosting',
            'text' => 'Choose a hosting provider and set up your account',
            'image' => '/images/step2.jpg'
        ],
    ]
);

// In your Model
class Post extends Model
{
    use HasSEO;
    
    public function steps()
    {
        return $this->hasMany(TutorialStep::class)->orderBy('order');
    }
}

// In Controller - Automatic!
SEO::post($post)->set(); // Automatically detects and adds HowTo steps

SEO::post($review)->set()->addReview(
    itemName: 'iPhone 15',
    ratingValue: 4.5,
    bestRating: 5.0,
    reviewBody: 'A comprehensive review of the iPhone 15...',
    authorName: 'John Doe',
    datePublished: '2024-01-15'
);

// In your Model
class Post extends Model
{
    use HasSEO;
    
    public function review()
    {
        return $this->hasOne(Review::class);
    }
}

// In Controller - Automatic!
SEO::post($post)->set(); // Automatically detects and adds Review

SEO::post($event)->set()->addEvent(
    name: 'Tech Conference 2024',
    startDate: '2024-01-15T10:00:00+00:00',
    endDate: '2024-01-15T18:00:00+00:00',
    description: 'A major technology conference...',
    locationName: 'Conference Hall',
    locationAddress: 'Damascus, Syria',
    image: '/images/conference.jpg',
    organizerName: 'Tech Company',
    organizerUrl: 'https://tech-company.com'
);

// In your Model
class Post extends Model
{
    use HasSEO;
    
    public function event()
    {
        return $this->hasOne(Event::class);
    }
}

// In Controller - Automatic!
SEO::post($post)->set(); // Automatically detects and adds Event

SEO::post($article)
    ->set()
    ->addFAQ([...])
    ->addHowTo(...)
    ->addReview(...)
    ->addEvent(...);

SEO::addCourse([
    'name' => 'Laravel Advanced Techniques',
    'description' => 'Learn advanced Laravel concepts and best practices',
    'provider' => [
        'name' => 'Tech Academy',
        'url' => 'https://tech-academy.com'
    ],
    'courseCode' => 'LAR-201',
    'educationalLevel' => 'Advanced',
    'inLanguage' => 'ar',
    'image' => '/images/course.jpg',
    'hasCourseInstance' => [
        'startDate' => '2024-02-01',
        'endDate' => '2024-04-30',
        'courseMode' => 'online',
        'instructor' => [
            'name' => 'Ahmed Ali',
            'email' => '[email protected]'
        ],
        'location' => 'Online Platform'
    ],
    'aggregateRating' => [
        'ratingValue' => 4.8,
        'ratingCount' => 150
    ]
]);

SEO::addRecipe([
    'name' => 'Traditional Kabsa',
    'description' => 'Authentic Saudi Kabsa recipe with step-by-step instructions',
    'image' => '/images/kabsa.jpg',
    'prepTime' => 'PT30M', // ISO 8601 duration format
    'cookTime' => 'PT1H',
    'totalTime' => 'PT1H30M',
    'recipeYield' => '6 servings',
    'recipeCategory' => 'Main Course',
    'recipeCuisine' => 'Saudi',
    'recipeIngredient' => [
        '2 cups basmati rice',
        '1 kg chicken',
        'Kabsa spices',
        'Onions and tomatoes'
    ],
    'recipeInstructions' => [
        'Wash and soak rice for 30 minutes',
        'Cook chicken with spices',
        'Add rice and cook on low heat',
        'Serve hot with salad'
    ],
    'author' => 'Chef Fatima',
    'datePublished' => '2024-01-15',
    'nutrition' => [
        'calories' => '450',
        'fatContent' => '15g',
        'proteinContent' => '30g',
        'carbohydrateContent' => '50g'
    ],
    'aggregateRating' => [
        'ratingValue' => 4.9,
        'ratingCount' => 89
    ]
]);

SEO::addJobPosting([
    'title' => 'Senior Laravel Developer',
    'description' => 'We are looking for an experienced Laravel developer...',
    'datePosted' => '2024-01-15',
    'validThrough' => '2024-03-15',
    'employmentType' => ['FULL_TIME', 'CONTRACTOR'],
    'hiringOrganization' => [
        'name' => 'Tech Company',
        'sameAs' => 'https://tech-company.com',
        'logo' => 'https://tech-company.com/logo.png'
    ],
    'jobLocation' => [
        'address' => [
            'streetAddress' => '123 Main Street',
            'addressLocality' => 'Damascus',
            'addressRegion' => 'Damascus',
            'postalCode' => '12345',
            'addressCountry' => 'SY'
        ]
    ],
    'baseSalary' => [
        'currency' => 'USD',
        'value' => [
            'minValue' => 50000,
            'maxValue' => 80000
        ]
    ],
    'jobBenefits' => ['Health Insurance', 'Remote Work', 'Flexible Hours'],
    'qualifications' => [
        'Bachelor\'s degree in Computer Science',
        '5+ years Laravel experience'
    ],
    'skills' => ['Laravel', 'PHP', 'MySQL', 'Vue.js']
]);

SEO::addLocalBusiness([
    'businessType' => 'Restaurant', // or 'LocalBusiness', 'Store', etc.
    'name' => 'Al-Sham Restaurant',
    'description' => 'Authentic Syrian cuisine in the heart of Damascus',
    'address' => [
        'streetAddress' => 'Al-Maliki Street',
        'addressLocality' => 'Damascus',
        'addressRegion' => 'Damascus',
        'postalCode' => '12345',
        'addressCountry' => 'SY'
    ],
    'geo' => [
        'latitude' => 33.5138,
        'longitude' => 36.2765
    ],
    'telephone' => '+963-11-1234567',
    'email' => '[email protected]',
    'url' => 'https://alsham-restaurant.com',
    'logo' => '/images/logo.png',
    'image' => ['/images/interior1.jpg', '/images/interior2.jpg'],
    'openingHours' => [
        'Mo-Fr 10:00-22:00',
        'Sa-Su 12:00-23:00'
    ],
    'priceRange' => '$$',
    'paymentAccepted' => ['Cash', 'Credit Card', 'Mobile Payment'],
    'servesCuisine' => ['Syrian', 'Middle Eastern'],
    'menu' => 'https://alsham-restaurant.com/menu',
    'aggregateRating' => [
        'ratingValue' => 4.7,
        'ratingCount' => 234
    ]
]);

SEO::addSoftwareApplication([
    'name' => 'My Awesome App',
    'description' => 'A productivity app that helps you organize your tasks',
    'applicationCategory' => 'ProductivityApplication',
    'operatingSystem' => ['Android', 'iOS'],
    'offers' => [
        'price' => '0',
        'priceCurrency' => 'USD',
        'availability' => 'https://schema.org/InStock'
    ],
    'aggregateRating' => [
        'ratingValue' => 4.5,
        'ratingCount' => 1250
    ],
    'screenshot' => [
        '/images/screenshot1.png',
        '/images/screenshot2.png'
    ],
    'image' => '/images/app-icon.png',
    'url' => 'https://myapp.com',
    'softwareVersion' => '2.1.0',
    'datePublished' => '2023-01-01'
]);

SEO::addBook([
    'name' => 'The Art of Laravel',
    'description' => 'A comprehensive guide to Laravel framework',
    'author' => [
        ['name' => 'John Doe'],
        ['name' => 'Jane Smith']
    ],
    'isbn' => '978-0-123456-78-9',
    'datePublished' => '2024-01-01',
    'publisher' => [
        'name' => 'Tech Books Publishing',
        'url' => 'https://techbooks.com'
    ],
    'bookFormat' => 'Hardcover',
    'numberOfPages' => 350,
    'image' => '/images/book-cover.jpg',
    'url' => 'https://example.com/book',
    'inLanguage' => 'en',
    'genre' => ['Technology', 'Programming']
]);

SEO::addMovie([
    'name' => 'The Great Adventure',
    'description' => 'An epic journey through time and space',
    'image' => '/images/movie-poster.jpg',
    'datePublished' => '2024-01-15',
    'director' => [
        ['name' => 'Director Name']
    ],
    'actor' => [
        ['name' => 'Actor One'],
        ['name' => 'Actor Two']
    ],
    'genre' => ['Action', 'Adventure', 'Sci-Fi'],
    'duration' => 'PT2H30M',
    'aggregateRating' => [
        'ratingValue' => 8.5,
        'ratingCount' => 5000,
        'bestRating' => 10.0
    ],
    'contentRating' => 'PG-13',
    'productionCompany' => [
        ['name' => 'Production Company']
    ],
    'countryOfOrigin' => ['US'],
    'inLanguage' => ['en', 'ar']
]);

SEO::addPodcast([
    'name' => 'Tech Talk Podcast',
    'description' => 'Weekly discussions about technology and innovation',
    'image' => '/images/podcast-cover.jpg',
    'author' => [
        'name' => 'Podcast Host',
        'email' => '[email protected]'
    ],
    'publisher' => [
        'name' => 'Podcast Network',
        'url' => 'https://podcast-network.com'
    ],
    'url' => 'https://example.com/podcast',
    'inLanguage' => 'ar',
    'category' => ['Technology', 'Business'],
    'episode' => [
        'name' => 'Episode 1: Getting Started',
        'description' => 'In this episode, we discuss...',
        'datePublished' => '2024-01-15',
        'duration' => 'PT30M',
        'episodeNumber' => 1
    ],
    'aggregateRating' => [
        'ratingValue' => 4.6,
        'ratingCount' => 120
    ]
]);

SEO::addVideo([
    'name' => 'Tutorial Video',
    'description' => 'Learn how to use Laravel SEO package',
    'video_url' => 'https://youtube.com/watch?v=...',
    'image' => '/images/video-thumbnail.jpg',
    'duration' => 'PT15M30S',
    'contentUrl' => 'https://example.com/video.mp4',
    'uploadDate' => '2024-01-15',
    'interactionStatistic' => [
        [
            '@type' => 'InteractionCounter',
            'interactionType' => 'https://schema.org/WatchAction',
            'userInteractionCount' => 10000
        ],
        [
            '@type' => 'InteractionCounter',
            'interactionType' => 'https://schema.org/LikeAction',
            'userInteractionCount' => 500
        ]
    ]
]);

// In config/seo.php
'geo_targeting' => [
    'enabled' => true,
    'country' => 'SY',
    'region' => 'SY-DI', // Damascus
    'placename' => 'Damascus',
    'latitude' => 33.5138,
    'longitude' => 36.2765,
],

// In config/seo.php
'social' => [
    'pinterest' => [
        'verify' => 'your-pinterest-verification-code',
    ],
],

// In config/seo.php
'performance' => [
    'prefetch' => [
        '/next-page',
        '/related-article',
    ],
    'prerender' => [
        '/important-page',
    ],
    'modulepreload' => [
        [
            'href' => '/js/app.js',
            'type' => 'module',
        ],
    ],
    'preload' => [
        [
            'href' => '/css/critical.css',
            'as' => 'style',
            'onload' => "this.onload=null;this.rel='stylesheet'", // Critical CSS
        ],
    ],
],



namespace App\Models;

use Illuminate\Database\Eloquent\Model;
use Shammaa\LaravelSEO\Traits\HasSEO;

class Post extends Model
{
    use HasSEO;
    
    // Define relationships
    public function writer()
    {
        return $this->belongsTo(Writer::class);
    }
    
    public function categories()
    {
        return $this->belongsToMany(Category::class);
    }
    
    public function tags()
    {
        return $this->belongsToMany(Tag::class);
    }
    
    public function faqs()
    {
        return $this->hasMany(FAQ::class)->orderBy('order');
    }
    
    public function steps()
    {
        return $this->hasMany(TutorialStep::class)->orderBy('order');
    }
    
    public function review()
    {
        return $this->hasOne(Review::class);
    }
    
    public function event()
    {
        return $this->hasOne(Event::class);
    }
}

public function show(Post $post)
{
    // That's it! The library does everything automatically
    SEO::post($post)->set();
    
    return view('posts.show', compact('post'));
}

class Post extends Model
{
    use HasSEO;

    /**
     * Define field names in your Model
     */
    protected function getSEOFieldMap(): array
    {
        return [
            'title' => ['title', 'name', 'headline'], // Try these fields in order
            'description' => ['content', 'text', 'description', 'excerpt'],
            'image' => ['photo', 'image', 'thumbnail', 'cover'],
            'published_at' => ['created_at', 'published_at', 'publish_date'],
            'modified_at' => ['updated_at', 'modified_at', 'last_updated'],
        ];
    }

    /**
     * Define relationship names in your Model
     */
    protected function getSEORelationships(): array
    {
        return [
            'writer' => 'author',        // If relationship name is 'author' instead of 'writer'
            'categories' => 'categories',
            'tags' => 'tags',
            'faqs' => 'faqs',
            'steps' => 'tutorial_steps',  // If relationship name is different
            'review' => 'product_review',
            'event' => 'event_data',
        ];
    }
}

class Article extends Model
{
    use HasSEO;

    protected function getSEOFieldMap(): array
    {
        return [
            'title' => ['headline', 'article_title'], // Different fields
            'description' => ['summary', 'article_summary'],
            'image' => ['cover_image', 'featured_image'],
            'published_at' => ['publish_date', 'published_on'],
            'modified_at' => ['last_modified', 'updated_on'],
        ];
    }

    protected function getSEORelationships(): array
    {
        return [
            'writer' => 'author',           // Different relationship name
            'categories' => 'sections',     // Different relationship name
            'tags' => 'keywords',          // Different relationship name
            'faqs' => 'questions',         // Different relationship name
            'steps' => 'instructions',     // Different relationship name
            'review' => 'rating',          // Different relationship name
            'event' => 'event_info',       // Different relationship name
        ];
    }
}

class Post extends Model
{
    use HasSEO;

    /**
     * (Optional) Customize relationships to be loaded automatically
     */
    public function getSEORelationshipsToLoad(): array
    {
        $relationships = parent::getSEORelationshipsToLoad();
        
        // Example: If Post is tutorial type, ensure steps are loaded
        if ($this->type === 'tutorial') {
            $relationships[] = 'steps';
        }
        
        // Example: If Post is review type, ensure review is loaded
        if ($this->type === 'review') {
            $relationships[] = 'review';
        }
        
        return array_unique($relationships);
    }
}

class Post extends Model
{
    use HasSEO;

    // Customize FAQ extraction
    public function getSEOFAQs(): array
    {
        return $this->faqs()
            ->where('is_active', true)
            ->orderBy('order')
            ->get()
            ->map(function($faq) {
                return [
                    'question' => $faq->question,
                    'answer' => $faq->answer,
                ];
            })
            ->toArray();
    }

    // Customize HowTo Steps extraction
    public function getSEOHowToSteps(): array
    {
        return $this->steps()
            ->where('published', true)
            ->orderBy('order')
            ->get()
            ->map(function($step) {
                return [
                    'name' => $step->title,
                    'text' => $step->content,
                    'image' => $step->getImageUrl(), // Custom method
                ];
            })
            ->toArray();
    }

    // Customize Review extraction
    public function getSEOReview(): ?array
    {
        if (!$this->review) {
            return null;
        }

        return [
            'itemName' => $this->review->product->name,
            'ratingValue' => $this->review->rating,
            'bestRating' => 5.0,
            'reviewBody' => $this->review->content,
            'authorName' => $this->writer->name,
            'datePublished' => $this->created_at->toIso8601String(),
        ];
    }
}

'multilingual' => [
    'enabled' => true,
    'locales' => ['ar', 'en', 'fr'],
    'default_locale' => 'ar',
    'x_default' => true,
],

use Shammaa\LaravelSEO\Builders\MultilingualBuilder;

// In AppServiceProvider or a custom Service Provider
public function boot(): void
{
    MultilingualBuilder::urlGeneratorUsing(function (string $locale, $model, string $currentUrl): string {
        // If your model exposes a localized URL, prefer that:
        if ($model && method_exists($model, 'getLocalizedUrl')) {
            return $model->getLocalizedUrl($locale);
        }

        // Example fallback that rewrites the path segment
        return str_replace('/en/', "/{$locale}/", $currentUrl);
    });
}

// ⚠️ WARNING: This will break 'php artisan config:cache'
'url_generator' => function($locale, $model, $currentUrl) {
    if ($model && method_exists($model, 'getLocalizedUrl')) {
        return $model->getLocalizedUrl($locale);
    }
    return str_replace('/en/', "/{$locale}/", $currentUrl);
},

'reading_time' => [
    'enabled' => true,
    'words_per_minute' => 200, // Average reading speed
    'translations' => [
        'en' => ':minutes min read',
        'ar' => ':minutes دقيقة قراءة',
        'fr' => ':minutes min de lecture',
        'es' => ':minutes min de lectura',
        'de' => ':minutes Min. Lesezeit',
        'it' => ':minutes min di lettura',
        'pt' => ':minutes min de leitura',
        'ru' => ':minutes мин. чтения',
        'zh' => ':minutes 分钟阅读',
        'ja' => ':minutes 分で読める',
        // Add your custom translations
        'custom_locale' => ':minutes custom text',
    ],
],

'reading_time' => [
    'translations' => [
        'en' => ':minutes minutes',
        'ar' => ':minutes دقيقة',
        'custom' => 'Takes :minutes minutes to read',
    ],
],

use Shammaa\LaravelSEO\Helpers\ReadingTimeCalculator;

$minutes = ReadingTimeCalculator::calculate($content, 200);
// Returns: 5 (minutes)

$iso8601 = ReadingTimeCalculator::toIso8601($content);
// Returns: "PT5M"

$formatted = ReadingTimeCalculator::format(
    $content, 
    200, 
    'ar', 
    config('seo.reading_time.translations')
);
// Returns: "5 دقيقة قراءة" (or custom translation from config)

use Shammaa\LaravelSEO\Services\SEOService;

// In your AppServiceProvider or a dedicated service provider
public function boot(): void
{
    SEOService::ampUrlGeneratorUsing(function ($model): string {
        if (is_object($model) && method_exists($model, 'route')) {
            return $model->route() . '/amp';
        }
        return route('amp.post', $model->slug ?? '');
    });
}

'amp' => [
    'enabled' => true,
    'url_generator' => null, // Keep null, use SEOService::ampUrlGeneratorUsing() instead
],

'rss' => [
    'enabled' => true,
    'url' => '/feed',
],

public function show(Tag $tag)
{
    // Your pagination logic
    $articles = $tag->posts()->paginate(15);

    SEO::tag($tag)
        ->withPagination($articles) // 👈 Pass paginator here
        ->set();
        
    return view('tag.show', compact('tag', 'articles'));
}

'pagination' => [
    'enabled' => true,
    
    // Canonical URL for paginated pages points to self (?page=2)
    // /articles?page=2 → canonical: /articles?page=2
    'canonical_to_first' => false,
    
    // Paginated pages get "noindex, follow" to prevent duplicate content
    'noindex_pagination' => false, // Set to true if you want noindex on /page/2
],

class Post extends Model
{
    public function previous()
    {
        return static::where('id', '<', $this->id)
            ->orderBy('id', 'desc')
            ->first();
    }
    
    public function next()
    {
        return static::where('id', '>', $this->id)
            ->orderBy('id', 'asc')
            ->first();
    }
}

'performance' => [
    'dns_prefetch' => [
        'cdn.example.com',
        'fonts.googleapis.com',
    ],
    'preconnect' => [
        'https://fonts.googleapis.com',
        'https://fonts.gstatic.com',
    ],
    'preload' => [
        [
            'href' => '/fonts/main.woff2',
            'as' => 'font',
            'type' => 'font/woff2',
        ],
        [
            'href' => '/images/hero.jpg',
            'as' => 'image',
        ],
    ],
],

'mobile' => [
    'theme_color' => '#ffffff',
    'apple_mobile_web_app' => [
        'enabled' => true,
        'status_bar_style' => 'default', // default, black, black-translucent
        'title' => 'My App',
    ],
    'manifest' => '/manifest.json',
],

'security' => [
    'content_security_policy' => "default-src 'self'",
    'referrer_policy' => 'strict-origin-when-cross-origin',
    'x_frame_options' => 'SAMEORIGIN', // DENY, SAMEORIGIN, ALLOW-FROM
    'x_content_type_options' => 'nosniff',
],

'analytics' => [
    'ga4' => [
        'measurement_id' => 'G-XXXXXXXXXX', // Google Analytics 4
    ],
    'gtm' => [
        'container_id' => 'GTM-XXXXXXX', // Google Tag Manager
    ],
    'yandex' => [
        'counter_id' => '12345678', // Yandex Metrica
    ],
    'facebook' => [
        'pixel_id' => '123456789012345', // Facebook Pixel
    ],
],

'image_rendering' => [
    'loading' => 'lazy', // lazy, eager
    'decoding' => 'async', // async, sync, auto
    'fetchpriority' => null, // high, low, auto (for important images)
],

use Shammaa\LaravelSEO\Contracts\SiteSettingsContract;

class Setting extends Model implements SiteSettingsContract
{
    public static function getSeoSettings(): array
    {
        $settings = static::first();
        
        return [
            'name'        => $settings->site_name,
            'description' => $settings->site_description,
            'logo'        => $settings->logo,
        ];
    }
}

use Shammaa\LaravelSEO\Services\SEOService;

public function boot(): void
{
    SEOService::resolveSiteUsing(fn() => \App\Models\Setting::getSeoSettings());
}

'site' => [
    'name' => 'Your Site Name',
    'description' => 'Your site description',
    'url' => 'https://yoursite.com',
    'logo' => 'path/to/logo.jpg',
    'publisher' => 'Publisher Name',
],

'image_route' => [
    'name' => 'image', // Route name
    'og_size' => '1200x630',
    'twitter_size' => '1200x630',
    'linkedin_size' => '1200x627',
    'logo_size' => '265x85',
],

'social' => [
    'twitter' => [
        'card_type' => 'summary_large_image',
        'site' => '@yourhandle',
        'creator' => '@yourhandle',
    ],
    'facebook' => [
        'app_id' => 'your-app-id',
    ],
],

'organization' => [
    'name' => 'Your Organization',
    'alternate_name' => 'Alternate Name',
    'description' => 'Organization description',
    'same_as' => [
        'https://www.facebook.com/yourpage',
        'https://twitter.com/yourhandle',
    ],
    'contact_point' => [
        'email' => '[email protected]',
        'contact_type' => 'customer service',
    ],
],

'defaults' => [
    'fallbacks' => [
        'post_title' => 'Post',
        'category_name' => 'Category',
        'category_description' => 'Latest news in :name category',
        'search_title' => 'Search results for: :query - :site',
        'search_description' => 'Find news and articles about: :query',
    ],
],

// Controller
use Shammaa\LaravelSEO\Facades\SEO;

public function show(Post $post)
{
    // Basic SEO setup
    SEO::post($post)->set();
    
    // Add FAQ if article has questions
    if ($post->has_faq) {
        SEO::addFAQ([
            ['question' => 'What is this?', 'answer' => 'This is...'],
            ['question' => 'How does it work?', 'answer' => 'It works by...'],
        ]);
    }
    
    // Add HowTo if it's a tutorial
    if ($post->is_tutorial) {
        SEO::addHowTo(
            name: $post->title,
            steps: $post->steps->pluck('content')->toArray(),
            description: $post->description,
            image: $post->image
        );
    }
    
    // Add Review if it's a review article
    if ($post->is_review && $post->rating) {
        SEO::addReview(
            itemName: $post->reviewed_item,
            ratingValue: $post->rating,
            bestRating: 5.0,
            reviewBody: $post->review_content,
            authorName: $post->writer->name ?? null
        );
    }
    
    return view('posts.show', compact('post'));
}

// Model
class Post extends Model
{
    use HasSEO;
    
    protected function getSEOFieldMap(): array
    {
        return [
            'title' => ['title', 'name'],
            'description' => ['content', 'text'],
            'image' => ['photo', 'image'],
            'published_at' => ['created_at', 'published_at'],
            'modified_at' => ['updated_at', 'modified_at'],
        ];
    }
    
    protected function getSEORelationships(): array
    {
        return [
            'writer' => 'writer',
            'categories' => 'categories',
            'tags' => 'tags',
            'faqs' => 'faqs',
            'steps' => 'steps',
            'review' => 'review',
            'event' => 'event',
        ];
    }
    
    public function faqs()
    {
        return $this->hasMany(FAQ::class)->orderBy('order');
    }
    
    public function steps()
    {
        return $this->hasMany(TutorialStep::class)->orderBy('order');
    }
    
    public function review()
    {
        return $this->hasOne(Review::class);
    }
    
    public function event()
    {
        return $this->hasOne(Event::class);
    }
}

// Controller - That's it!
public function show(Post $post)
{
    SEO::post($post)->set(); // Automatically detects and loads everything!
    
    return view('posts.show', compact('post'));
}

// Extract FAQs from relationship
if ($post->faqs && $post->faqs->isNotEmpty()) {
    $faqs = $post->faqs->map(function($faq) {
        return [
            'question' => $faq->question,
            'answer' => $faq->answer,
        ];
    })->toArray();
    
    SEO::addFAQ($faqs);
}

// Extract HowTo steps from relationship
if ($post->steps && $post->steps->isNotEmpty()) {
    $steps = $post->steps->map(function($step) {
        return [
            'name' => $step->title,
            'text' => $step->content,
            'image' => $step->image,
        ];
    })->toArray();
    
    SEO::addHowTo($post->title, $steps);
}

// Extract Review from model
if ($post->review) {
    SEO::addReview(
        itemName: $post->review->product_name,
        ratingValue: $post->review->rating,
        bestRating: 5.0,
        reviewBody: $post->review->content,
        authorName: $post->review->author->name ?? null,
        datePublished: $post->review->created_at->toIso8601String()
    );
}

// Extract Event from model
if ($post->event) {
    SEO::addEvent(
        name: $post->title,
        startDate: $post->event->start_date->toIso8601String(),
        endDate: $post->event->end_date?->toIso8601String(),
        description: $post->description,
        locationName: $post->event->location_name,
        locationAddress: $post->event->location_address,
        image: $post->image,
        organizerName: $post->event->organizer->name ?? null,
        organizerUrl: $post->event->organizer->url ?? null
    );
}

SEO::post($article)->set();

SEO::product($product)->set();

// For articles
SEO::post($article)->set();

// For products
SEO::product($product)->set();

   SEO::post($post)->set(); // Must call set() first
   

   protected function getSEOFieldMap(): array
   {
       return [
           'title' => ['your_field_name'], // Add your field names
       ];
   }
   

   protected function getSEORelationships(): array
   {
       return [
           'writer' => 'your_relationship_name', // Add your relationship names
       ];
   }
   

   'reading_time' => [
       'enabled' => true,
   ],
   

   // Model should have 'content' attribute
   $post->content; // Should exist
   

   use Shammaa\LaravelSEO\Traits\HasSEO;
   

   public function faqs() {
       return $this->hasMany(FAQ::class);
   }
   

   // The library automatically loads relationships
   // But you can manually load if needed:
   $post->load('faqs', 'steps', 'review', 'event');
   

// ❌ DON'T DO THIS (breaks config:cache)
'url_generator' => function($locale, $model, $currentUrl) {
    return $url;
},

// ✅ DO THIS INSTEAD (works with config:cache)
// In AppServiceProvider::boot()
use Shammaa\LaravelSEO\Builders\MultilingualBuilder;

MultilingualBuilder::urlGeneratorUsing(function (string $locale, $model, string $currentUrl): string {
    if ($model && method_exists($model, 'getLocalizedUrl')) {
        return $model->getLocalizedUrl($locale);
    }
    return str_replace('/en/', "/{$locale}/", $currentUrl);
});

class Post extends Model
{
    use HasSEO;
}

protected function getSEOFieldMap(): array
{
    return [
        'title' => ['title', 'name'],
        // ... your fields
    ];
}

// In Controller
$post->load(['writer', 'categories', 'tags', 'faqs', 'steps']);

'cache_ttl' => 86400, // 24 hours in seconds

'performance' => [
    'dns_prefetch' => ['cdn.example.com'],
    'preconnect' => ['https://fonts.googleapis.com'],
],
bash
php artisan vendor:publish --tag=seo-config
blade
<head>
    {!! SEO::render() !!}
    {!! $customSchemas ?? '' !!}
</head>
bash
php artisan seo:test-schema
php artisan seo:test-schema https://example.com
php artisan seo:test-schema --format=table
bash
php artisan seo:health-check
blade
{{-- resources/views/layouts/app.blade.php --}}
<!DOCTYPE html>
<html lang="{{ app()->getLocale() }}">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    
    {{-- SEO Meta Tags --}}
    {!! SEO::render() !!}
    
    {{-- Custom Schemas (JSON-LD) --}}
    {!! $customSchemas ?? '' !!}
</head>
<body>
    {{-- Breadcrumb Navigation --}}
    @if(isset($breadcrumbs))
        @
bash
   php artisan config:clear
   
bash
php artisan config:clear