Installation:
composer require astina/seo-bundle:dev-master
Add the bundle to app/AppKernel.php:
new Astina\Bundle\SeoBundle\AstinaSeoBundle(),
Enable Routing (optional for admin UI):
# app/config/routing.yml
astina_seo:
resource: "@AstinaSeoBundle/Resources/config/routing.yml"
Secure the route in app/config/security.yml (e.g., restrict to ROLE_ADMIN).
First Use Case:
Render meta tags in a Twig template (e.g., base.html.twig):
{{ seo_meta_tags(app.request) }}
This fetches PageMetaData for the current route and renders <title>, <meta description>, and <meta keywords>.
Define PageMetaData Entities:
Create a PageMetaData entity (e.g., via Doctrine) with fields:
// src/Acme/AppBundle/Entity/PageMetaData.php
/**
* @ORM\Entity(repositoryClass="Acme\AppBundle\Repository\PageMetaDataRepository")
*/
class PageMetaData {
// @ORM\Id, @ORM\Column, etc.
private $title;
private $description;
private $keywords;
private $route; // e.g., "homepage", "product_show"
}
Configure Global Defaults (optional):
# app/config.yml
astina_seo:
global_defaults:
title: "My App"
description: "Default description"
keywords: "laravel, seo"
Override Meta Tags per Route:
seo_meta_tags:
{{ seo_meta_tags(app.request, "Custom Title", {"description": "Custom desc"}) }}
PageMetaData entity (e.g., via a form in an admin panel).Admin Integration:
/seo/{route}) to CRUD PageMetaData entries.{{ seo_meta_tags(app.request, null, {}, " - Page " ~ pageNumber) }}
PageMetaDataRepository to fetch metadata by route pattern:
$metaData = $repo->findOneBy(['route' => $request->get('_route')]);
kernel.request to preload metadata for performance:
// src/Acme/AppBundle/EventListener/SeoListener.php
public function onKernelRequest(GetResponseEvent $event) {
$request = $event->getRequest();
$metaData = $this->get('astina_seo.page_metadata')->findForRequest($request);
// Cache or preprocess...
}
Route Mismatches:
PageMetaData by exact route name (e.g., homepage). Use wildcards (*) or generic routes (e.g., product_show) sparingly to avoid conflicts.product_show_{id}).Missing Entities:
PageMetaData exists for a route, the bundle falls back to global defaults. Test edge cases (e.g., 404 pages) to ensure defaults render correctly.null check in Twig:
{% if seo_meta_tags(app.request) is not empty %}
{{ seo_meta_tags(app.request) }}
{% endif %}
Caching Issues:
PageMetaData.php bin/console cache:clear or implement a cache invalidation event.Twig Template Overrides:
seo_meta_tags function assumes a specific Twig template structure. Overriding it requires extending the bundle’s TwigExtension.AstinaSeoBundle/Resources/views/PageMetaData/meta_tags.html.twig to your theme.public function onKernelRequest(GetResponseEvent $event) {
$request = $event->getRequest();
$metaData = $this->get('astina_seo.page_metadata')->findForRequest($request);
if (!$metaData) {
$this->logger->debug('No SEO metadata for route: ' . $request->get('_route'));
}
}
{{ dump(app.request.get('_route')) }}
Custom Metadata Fields:
Extend the PageMetaData entity and override the Twig template to include additional tags (e.g., Open Graph):
<!-- templates/AcmeBundle/PageMetaData/meta_tags.html.twig -->
{% extends 'AstinaSeoBundle::meta_tags.html.twig' %}
{% block meta_tags %}
{{ parent() }}
<meta property="og:image" content="{{ metaData.ogImage }}" />
{% endblock %}
Dynamic Metadata Generation: Use a controller event subscriber to generate metadata on-the-fly (e.g., for product pages):
public function onKernelController(FilterControllerEvent $event) {
$metaData = new PageMetaData();
$metaData->setTitle($product->getName());
$metaData->setDescription($product->getShortDescription());
$event->getRequest()->attributes->set('astina_seo.metadata', $metaData);
}
Multi-Language Support:
Store translations in PageMetaData (e.g., via Gedmo Translatable) and pass the locale to seo_meta_tags:
{{ seo_meta_tags(app.request, null, {}, null, app.request.locale) }}
How can I help you explore Laravel packages today?