inwebo / seo-bundle
A lightweight Symfony bundle to manage SEO metadata and breadcrumbs.
Installs: 4
Dependents: 0
Suggesters: 0
Security: 0
Stars: 1
Watchers: 0
Forks: 0
Open Issues: 0
Type:symfony-bundle
pkg:composer/inwebo/seo-bundle
Requires
- php: >=8.4
- doctrine/doctrine-bundle: ^3.0|^2.7
- doctrine/orm: ^3.0
- symfony/console: ^7.3
- symfony/event-dispatcher: ^7.3
- symfony/framework-bundle: ^7.3
- symfony/http-kernel: ^7.3
- symfony/routing: ^7.3
- symfony/twig-bundle: ^7.3
- symfony/uid: ^7.3
- twig/twig: ^3.21
Requires (Dev)
- friendsofphp/php-cs-fixer: ^3.88
- phpstan/phpstan: ^2.1
- phpunit/phpunit: ^12.4
- symfony/browser-kit: ^7.3
- symfony/yaml: ^7.3
This package is auto-updated.
Last update: 2025-10-20 13:44:54 UTC
README
A lightweight Symfony bundle to manage SEO metadata (title, description, H1) and navigational breadcrumbs with Twig-powered templating and CLI importers.
Contents
- Features
- Requirements
- Installation
- Configure your entities
- Bundle configuration
- Database/migrations
- Usage in Twig
- Importing from routes (CLI)
- Route parameters and templating
- Global variables with Bags
- Customizing the breadcrumbs template
- Troubleshooting
- License
Features
- SEO metadata service that renders title, meta description and H1 using Twig templates.
- Breadcrumbs service that renders a breadcrumb trail using a provided Twig partial.
- Both features read from your Doctrine entities; you control persistence in your app.
- Twig variables come from your controller arguments and from optional shared “bags”.
- Two console commands to import missing items from your Symfony routes.
Requirements
- PHP >= 8.4
- Symfony 7.3 (FrameworkBundle, Console, Routing, TwigBundle)
- Doctrine ORM 3.x
- Twig 3.21+
Installation
- Install the package via Composer
composer require inwebo/seo-bundle
- Symfony will auto-register the bundle (type: symfony-bundle). No manual steps needed.
Configure your entities
This bundle ships mapped superclasses you should extend to create concrete Doctrine entities in your project.
Example: App entity for breadcrumbs
<?php namespace App\Entity\Seo; use Doctrine\ORM\Mapping as ORM; use Inwebo\SeoBundle\Entity\Breadcrumb as BaseBreadcrumb; #[ORM\Entity] #[ORM\Table(name: 'seo_breadcrumb')] class Breadcrumb extends BaseBreadcrumb { #[ORM\Id] #[ORM\GeneratedValue] #[ORM\Column] protected ?int $id = null; }
Example: App entity for metadata
<?php namespace App\Entity\Seo; use Doctrine\ORM\Mapping as ORM; use Inwebo\SeoBundle\Entity\Metadata as BaseMetadata; #[ORM\Entity] #[ORM\Table(name: 'seo_metadata')] class Metadata extends BaseMetadata { #[ORM\Id] #[ORM\GeneratedValue] #[ORM\Column] protected ?int $id = null; }
Bundle configuration
Tell the bundle which FQCNs to use and optionally which routes to ignore for metadata resolution.
# config/packages/inwebo_seo.yaml inwebo_seo: breadcrumb: entity: App\Entity\Seo\Breadcrumb metadata: entity: App\Entity\Seo\Metadata excluded_routes: # metadata resolution is skipped when route name starts with any of these prefixes - _ # useful to ignore Symfony internals (e.g. _profiler, _wdt) - admin_ # example: skip your back-office
Notes
- Doctrine mapping for the bundle’s mapped superclasses is auto-prepended, so extending them is enough.
- You decide where and how to persist data (fixtures, admin UI, CLI importers below, etc.).
Database/migrations
After creating your concrete entities, generate and run a migration in your app:
php bin/console doctrine:migrations:diff php bin/console doctrine:migrations:migrate
Usage in Twig
Drop these helpers into your base layout or individual templates:
<title>{{ inwebo_seo_title() }}</title> <meta name="description" content="{{ inwebo_seo_description() }}" /> <h1>{{ inwebo_seo_h1() }}</h1> {# Render the breadcrumb trail #} {{ inwebo_seo_breadcrumbs() }}
Importing from routes (CLI)
The bundle provides commands that scan your router and create missing records so you can fill them later.
# Import missing breadcrumbs for known routes php bin/console inwebo_seo:import:breadcrumbs # alias: is:i:b # Import missing metadata for known routes php bin/console inwebo_seo:import:metadata # alias: is:i:m
- Each command prints a table of newly persisted rows or a message if nothing is needed.
- You can safely run these commands multiple times; they only create missing items.
Route parameters and templating
- All breadcrumb and metadata string fields (e.g., breadcrumb name/title, metadata title/description/h1) are rendered using Twig.
- Available Twig variables include:
- Controller arguments for the current request (by name)
- Values stored in the corresponding Bag (see below)
- You can reference route parameters by name in your templates. Example:
- Breadcrumb.name:
Category: {{ category.name }} - Breadcrumb.title:
Back to {{ category.name }} - Metadata.title:
{{ product.name }} | My Shop
- Breadcrumb.name:
Global variables with Bags
Sometimes you want to provide extra variables not present in controller arguments. Use the provided Bags.
MetadataBagprovides variables for metadata templatesBreadcrumbBagprovides variables for breadcrumb templates
Add values anywhere before rendering (e.g., in a listener or controller):
<?php use Inwebo\SeoBundle\Model\MetadataBag; use Inwebo\SeoBundle\Model\BreadcrumbBag; MetadataBag::create()::add(['siteName' => 'Acme']); BreadcrumbBag::create()::add(['locale' => 'en']);
Then in your templates stored in DB you can do:
{{ siteName }}{{ locale }}
Customizing the breadcrumbs template
The breadcrumbs HTML is rendered via the template path: @InweboSeo/_breadcrumbs.html.twig
Options to customize:
- Easiest: copy the file from
vendor/inwebo/seo-bundle/templates/_breadcrumbs.html.twiginto your app and add a Twig path with higher priority for theInweboSeonamespace, or override via the standard bundles override path if configured. - Or, keep the function and style via CSS.
Troubleshooting
- I see an exception like " is not a valid metadata object."
- Ensure you created and configured your concrete
Metadataentity and that a row exists for the current route. - Check
inwebo_seo.metadata.entityis set to your FQCN and that the route name matches.
- Ensure you created and configured your concrete
- Breadcrumbs don’t show up:
- Ensure a
Breadcrumbrow exists for the current route. Use the importer to create missing ones. - If you need parameters, set
routeParameterson the breadcrumb so URLs can be generated.
- Ensure a
- Metadata not applied on some routes:
- Use
excluded_routesconfig to skip areas like_profiler,admin_, etc.
- Use
License
GPL-3.0-or-later. See LICENSE file for details.