Installation:
composer require ayrel/seo-bundle
Register the bundle in config/bundles.php (Symfony 4+) or AppKernel.php (Symfony 3):
Ayrel\SeoBundle\AyrelSeoBundle::class => ['all' => true],
First Use Case:
Add the @Seo annotation to a controller method to dynamically generate SEO tags:
use Ayrel\SeoBundle\Annotation\SeoAnnotation;
class PageController extends Controller
{
/**
* @Route("/about", name="about")
* @Seo({
* "title": "About Us | {{_route}}",
* "description": "Learn about our company"
* })
*/
public function aboutAction()
{
return $this->render('about.html.twig');
}
}
_route (route name), _controller (FQCN), and any ParamConverter entities (e.g., {{product.title}}).Verify Output:
Inspect the rendered HTML to confirm <title> and <meta> tags are dynamically populated.
@Seo annotations for granular control over individual routes. Example:
@Seo({
"title": "{{user.name}}'s Profile",
"og:image": "{{asset('images/profile/' ~ user.avatar)}}"
})
~ (null) in annotations to inherit defaults from config.yml:
# config/packages/ayrel_seo.yaml
ayrel_seo:
default:
title: "My Site | {_route}"
description: "Default description for all pages"
config/seo.yml:
homepage:
title: "Welcome to {{app.name}}"
description: "Discover our services"
blog_post:
title: "{{post.title}} | {{app.name}}"
description: "{{post.excerpt}}"
og:title: "{{post.title}}"
blog_post for /blog/{slug}).@Seo({
"title": "{{product.name}} - Price: {{product.price}}€",
"description": "{{product.shortDescription}}"
})
public function showAction(Product $product)
_request to access query params or session data:
search:
title: "Results for '{{_request.query.search}}'"
Ayrel\SeoBundle\Twig\SeoTwigStrategy to add custom filters.og:) and Twitter Card (twitter:) tags in the same config:
product:
og:title: "{{product.title}}"
og:description: "{{product.description}}"
og:image: "{{asset('images/' ~ product.image)}}"
twitter:card: "summary_large_image"
if in patterns (via {% if %} or {{ ... ? 'yes' : 'no' }}):
article:
title: "{{article.published ? article.title : 'Draft: ' ~ article.title}}"
Route Name Mismatches:
homepage). Ensure @Route names in controllers match the YAML keys.@Route(name="exact_match") explicitly.Circular References:
{{product.category.parent.name}} where parent is lazy-loaded).{{ product.category ? product.category.name : 'Uncategorized' }}.Asset Paths in SEO Tags:
{{asset('image.jpg')}} may break if the asset pipeline changes.ayrel_seo.asset_base_url in config.yml.Annotation Parsing Issues:
@Seo annotation isn’t properly imported.use statement is at the top of the file:
use Ayrel\SeoBundle\Annotation\SeoAnnotation as Seo;
Caching Headaches:
php bin/console cache:clear
Inspect Request Attributes: Dump available variables in a controller to debug Twig patterns:
public function debugAction(Request $request)
{
dd($request->attributes->all());
}
Override Twig Strategy: Create a custom strategy to log or modify SEO data:
// src/Twig/SeoDebugStrategy.php
class SeoDebugStrategy extends SeoTwigStrategy
{
public function render($template, array $context)
{
error_log("SEO Context: " . print_r($context, true));
return parent::render($template, $context);
}
}
Register it in services.yaml:
services:
Ayrel\SeoBundle\Twig\SeoTwigStrategy:
alias: App\Twig\SeoDebugStrategy
Fallback Values:
Use {{ var|default('fallback') }} in Twig patterns to handle missing data:
product:
title: "{{product.title|default('No Title')}}"
Custom Variables: Add global variables to SEO contexts via an event subscriber:
// src/EventListener/SeoListener.php
class SeoListener implements EventSubscriber
{
public static function getSubscribedEvents()
{
return [
KernelEvents::CONTROLLER => 'onKernelController',
];
}
public function onKernelController(ControllerEvent $event)
{
$request = $event->getRequest();
$request->attributes->set('_app_name', 'MyApp');
}
}
Now use {{_app_name}} in SEO patterns.
Dynamic Route Matching: Extend the route matcher to support regex or custom logic:
// src/AyrelSeoBundle/DependencyInjection/Configuration.php
// Override the route resolver logic
Environment-Specific SEO: Use Symfony’s parameter system to switch SEO rules by environment:
# config/packages/dev/ayrel_seo.yaml
ayrel_seo:
default:
title: "Dev Mode: {_route}"
public function indexAction()
{
$seo = [
'title' => $this->renderSeoTitle(),
'description' => $this->renderSeoDescription(),
];
return $this->render('index.html.twig', ['seo' => $seo]);
}
How can I help you explore Laravel packages today?