Installation:
composer require ahc/twigseobundle
Register the bundle in config/app.php under extra.bundles:
AhmetCelikezer\TwigSeoBundle\AhmetCelikezerTwigSeoBundle::class => ['all' => true],
Enable in Twig:
Ensure Twig is configured in config/app.php and the bundle is auto-discovered (Laravel 5.5+).
First Use Case: In a Twig template, generate SEO meta tags dynamically:
{{ seo_title('My Page Title') }}
{{ seo_description('A concise description for SEO') }}
{{ seo_keywords('keyword1, keyword2') }}
Check config/packages/ahmet_celikezer_twig_seo.yaml (auto-generated) for default settings like:
ahmet_celikezer_twig_seo:
default_seo_group: 'default' # Fallback group
groups: # Custom groups (see Implementation Patterns)
default: { title: 'Default', description: 'Default SEO' }
Basic SEO Tags: Use built-in Twig functions for common meta tags:
{# Title #}
{{ seo_title('Laravel SEO Best Practices') }}
{# Description #}
{{ seo_description('Learn how to optimize Laravel apps for search engines') }}
{# Open Graph #}
{{ seo_open_graph_title('Laravel SEO') }}
{{ seo_open_graph_description('SEO guide for Laravel developers') }}
{{ seo_open_graph_image('/images/seo-guide.png') }}
Grouped SEO:
Define reusable SEO groups in config/packages/ahmet_celikezer_twig_seo.yaml:
groups:
blog_post:
title: '{{ post.title }} | {{ site_name }}'
description: '{{ post.excerpt }}'
keywords: '{{ post.tags|join(', ') }}'
og_type: 'article'
og_url: '{{ post.url }}'
Render in Twig:
{{ seo_group('blog_post', { post: post, site_name: 'My Blog' }) }}
Dynamic Context: Pass variables to Twig functions for dynamic content:
{% set product = get_product('123') %}
{{ seo_title(product.name ~ ' - ' ~ site_name) }}
{{ seo_description(product.description|truncate(160)) }}
Conditional SEO: Use Twig logic to toggle SEO tags:
{% if is_homepage %}
{{ seo_title('Welcome to ' ~ site_name) }}
{% else %}
{{ seo_title(page_title ~ ' | ' ~ site_name) }}
{% endif %}
@twig directives:
@twig({{ seo_title('Dynamic Title') }})
// In a service provider
$this->app->singleton('seo.groups', function () {
return Cache::remember('seo.groups', 3600, function () {
return config('ahmet_celikezer_twig_seo.groups');
});
});
Configuration Bugs:
1.0.0 (use 1.0.1+). The initial release had a critical config bug.default_seo_group exists in the groups array.Twig Version Mismatch:
Dynamic Content Escaping:
|raw for unescaped HTML (e.g., {{ seo_canonical(url)|raw }}).product.name) to avoid XSS:
{{ seo_title(product.name|e('html_attr')) }}
Group Overrides:
seo_group() calls overwrite earlier ones. Use seo_merge_group() (if available) for additive behavior.Deprecated Methods:
seoPage() was removed in 1.0.0. Use seo_group() instead.<head> section to verify tags. Use browser dev tools (e.g., Chrome’s "Elements" tab).{{ dump(_context.get('ahmet_celikezer_twig_seo')) }}
config match Twig calls (case-sensitive):
groups:
blog_post: { ... } {# Correct #}
# blogPost: { ... } {# Fails #}
Custom Twig Functions: Extend the bundle by creating a custom Twig extension:
// app/Extensions/CustomSeoExtension.php
namespace App\Extensions;
use Twig\Extension\AbstractExtension;
use Twig\TwigFunction;
class CustomSeoExtension extends AbstractExtension
{
public function getFunctions()
{
return [
new TwigFunction('seo_twitter_card', [$this, 'getTwitterCard']),
];
}
public function getTwitterCard($type)
{
return '<meta name="twitter:card" content="' . $type . '">';
}
}
Register in config/packages/twig.yaml:
twig:
extensions:
- App\Extensions\CustomSeoExtension
Override Default Tags:
Replace or extend default SEO tags by redefining the seo_group in config:
groups:
default:
title: 'Custom Title'
description: 'Custom Description'
# Add missing tags (e.g., Twitter Cards)
twitter_card: 'summary_large_image'
Event Listeners: Listen for SEO-related events (if the bundle emits them) to modify tags dynamically:
// app/Listeners/ModifySeoTags.php
namespace App\Listeners;
use AhmetCelikezer\TwigSeoBundle\Event\SeoEvent;
class ModifySeoTags
{
public function handle(SeoEvent $event)
{
$event->setTitle('Modified: ' . $event->getTitle());
}
}
Register in EventServiceProvider:
protected $listen = [
'ahmet_celikezer.twig_seo.seo' => [
\App\Listeners\ModifySeoTags::class,
],
];
Localization:
Use Twig’s trans filter for multilingual SEO:
{{ seo_title(trans('seo.title.page', { title: page_title })) }}
How can I help you explore Laravel packages today?