nowo-tech / seo-kit-bundle
Symfony SEO kit: multilingual static routes, slug SEO layers (defaults / pages / slug patterns / specific slugs), head tags, hreflang, sitemap and robots for FrankenPHP, php-fpm and Nginx.
Package info
github.com/nowo-tech/SeoKitBundle
Type:symfony-bundle
pkg:composer/nowo-tech/seo-kit-bundle
Requires
- php: >=8.2 <8.6
- nowo-tech/form-kit-bundle: ^2.13
- nowo-tech/ui-kit-bundle: ^2.17
- symfony/config: ^7.4 || ^8.0
- symfony/dependency-injection: ^7.4 || ^8.0
- symfony/form: ^7.4 || ^8.0
- symfony/framework-bundle: ^7.4 || ^8.0
- symfony/http-foundation: ^7.4 || ^8.0
- symfony/http-kernel: ^7.4 || ^8.0
- symfony/routing: ^7.4 || ^8.0
- symfony/security-core: ^7.4 || ^8.0
- symfony/security-csrf: ^7.4 || ^8.0
- symfony/translation: ^7.4 || ^8.0
- symfony/twig-bundle: ^7.4 || ^8.0
- symfony/validator: ^7.4 || ^8.0
- symfony/yaml: ^7.4 || ^8.0
- twig/extra-bundle: ^3.12
- twig/string-extra: ^3.12
- twig/twig: ^3.8
Requires (Dev)
- doctrine/doctrine-bundle: ^2.13 || ^3.0
- doctrine/orm: ^3.0
- friendsofphp/php-cs-fixer: ^3.0
- igor-php/igor-php: ^0.10.1
- nowo-tech/brand-contracts: ^1.0
- nowo-tech/phpstan-frankenphp: ^1.0
- phpstan/extension-installer: ^1.4
- phpstan/phpstan: ^2.0
- phpstan/phpstan-phpunit: ^2.0
- phpstan/phpstan-symfony: ^2.0
- phpunit/phpunit: ^10.0
- rector/rector: ^2.0
- symfony/asset: ^7.4 || ^8.0
- symfony/browser-kit: ^7.4 || ^8.0
- symfony/cache: ^7.4 || ^8.0
- symfony/console: ^7.4 || ^8.0
- symfony/phpunit-bridge: ^7.4 || ^8.0
- symfony/security-bundle: ^7.4 || ^8.0
- vincentlanglet/twig-cs-fixer: ^4.0
Suggests
- doctrine/doctrine-bundle: Registers ORM mappings when persistence is enabled
- doctrine/orm: Required when nowo_seo_kit.persistence.enabled is true (SeoSiteSettings / SeoSurface)
- nowo-tech/brand-contracts: ^1.0 — site name (and, opt-in, logo) for the head tags and JSON-LD from a BrandProviderInterface service (nowo_seo_kit.brand, spec 220)
- nowo-tech/generative-seo-kit-bundle: Generative Engine Optimization (GEO, not geolocation): AI crawler robots groups, /llms.txt, citations, nowo:generative-seo:audit
- symfony/cache: Optional cache.app for SeoSiteConfigProvider snapshots
- symfony/console: Required for nowo:seo:audit
- symfony/flex: For automatic recipe installation (config and bundles.php)
- symfony/security-bundle: Access control on admin controllers
- symfony/security-csrf: CSRF tokens for the admin forms and the X-CSRF-Token header of the JSON surface API (admin.api_csrf_protection)
Provides
None
Conflicts
- nowo-tech/brand-contracts: <1.0 || >=2.0
Replaces
None
- v1.23.0
- v1.22.0
- v1.21.0
- v1.20.0
- v1.19.0
- v1.18.0
- v1.17.0
- v1.16.1
- v1.16.0
- dev-main / 1.15.x-dev
- v1.15.0
- v1.14.1
- v1.14.0
- v1.13.0
- v1.12.1
- v1.12.0
- v1.11.1
- v1.11.0
- v1.10.2
- v1.10.1
- v1.10.0
- v1.9.0
- v1.8.1
- v1.8.0
- v1.7.0
- v1.6.0
- v1.5.0
- v1.4.3
- v1.4.2
- v1.4.1
- v1.4.0
- v1.3.1
- v1.3.0
- v1.2.0
- v1.1.0
- v1.0.0
- dev-fix/arch-bar-w0
- dev-feat/ddd-p2
- dev-feat/brand-s6
- dev-chore/symfony-security-2026-11-04
- dev-feat/table-name-prefix
This package is auto-updated.
Last update: 2026-11-11 02:13:38 UTC
README
⭐ Found this useful? Give it a star on GitHub! It helps us maintain and improve the project.
Symfony SEO kit: multilingual static routes, slug SEO layers (defaults / pages / slug patterns / specific slugs), head tags, hreflang, sitemap and robots for FrankenPHP, php-fpm and Nginx.
This bundle is FrankenPHP worker mode friendly.
Table of contents
- Features
- Installation
- Requirements
- Version information
- Demos
- Documentation
- Tests and coverage
- License
Features
- ✅ Hierarchical SEO config — defaults → slug_routes → pages → slugs → attribute → runtime
- ✅ Twig head helper —
{{ nowo_seo_head() }}with Open Graph, Twitter, JSON-LD, canonical, hreflang - ✅ Multilingual paths — locale-specific paths and translated slugs
- ✅ X-Robots-Tag — opt-in
x_robots_tag.enabled: the page's robots value as a response header (HTML, JSON, files) - ✅ Sitemap & robots —
/sitemap.xmland/robots.txtserved by Symfony; extra User-agent groups viarobots.groupsorGeoRobotsGroupsProviderInterface(GEO crawler policy: GenerativeSeoKitBundle) - ✅ Typed JSON-LD — Organization, LocalBusiness, Person, FAQPage, BlogPosting and related nodes
- ✅ Runtime overrides —
SeoRuntimefor dynamic titles from controllers - ✅ Host providers — defaults, indexability, sitemap URLs, and extra robots groups
- ✅ Optional Doctrine site settings —
persistence.enabled+SeoSiteConfigsnapshot - ✅ Audit CLI —
nowo:seo:auditwith tagged subject providers - ✅ Optional SEO admin + pencil API — site settings, surface overrides on the UiKit page contract (host layout + CSS stack from UiKit),
security.access_roles/ custom access checker, FormKit forms,OriginUrlGuard - ✅ Surface helpers —
SeoSurfaceKeys+SeoSurfaceManagerfor CMS/blog pencils - ✅ AbsoluteUrlBuilder — origin + path normalisation from
base_url - ✅ PHP 8 attribute —
#[Seo]on controllers - ✅ FrankenPHP-ready demo — single-container Symfony 8 demo
FrankenPHP: Demos use a single PHP service (FrankenPHP, no nginx). With APP_ENV=dev (default), the Docker entrypoint swaps in Caddyfile.dev — php_server without workers for comfortable local development. The baked-in production Caddyfile can use php_server { worker … }; see docs/DEMO-FRANKENPHP.md. Access the demo at http://localhost:PORT (see demo/README.md and .env.example).
Installation
composer require nowo-tech/seo-kit-bundle
Register the bundle in config/bundles.php (Flex does this automatically):
Nowo\SeoKitBundle\SeoKitBundle::class => ['all' => true],
Add to your base layout:
{{ nowo_seo_head() }}
Requirements
- PHP >= 8.2, < 8.6
- Symfony 7.4+ or 8.x
nowo-tech/form-kit-bundle^2.4 (hard dependency)
GEO (Generative Engine Optimization — not geolocation) is a companion package: nowo-tech/generative-seo-kit-bundle (llms.txt, AI crawler robots groups via this bundle’s SPI, citation index, nowo:generative-seo:audit). This kit stays classical SEO (head, sitemap, canonical, hreflang).
Version information
| Version | PHP | Symfony | Status |
|---|---|---|---|
| 1.12.x | >= 8.2 | 7.4 – 8.1+ | Stable |
| 1.11.x | >= 8.2 | 7.4 – 8.1+ | Stable |
| 1.10.x | >= 8.2 | 7.4 – 8.1+ | Stable |
| 1.9.x | >= 8.2 | 7.4 – 8.1+ | Stable |
| 1.8.x | >= 8.2 | 7.0 – 8.1+ | Stable |
| 1.7.x | >= 8.2 | 7.0 – 8.1+ | Stable |
| 1.6.x | >= 8.2 | 7.0 – 8.1+ | Stable |
| 1.5.x | >= 8.2 | 7.0 – 8.1+ | Stable |
| 1.4.x | >= 8.2 | 7.0 – 8.1+ | Stable |
| 1.3.x | >= 8.2 | 7.0 – 8.1+ | Stable |
| 1.2.x | >= 8.2 | 7.0 – 8.1+ | Stable |
| 1.1.x | >= 8.2 | 7.0 – 8.1+ | Stable |
| 1.0.x | >= 8.2 | 7.0 – 8.1+ | Stable |
Demos
make -C demo up-symfony8 # http://localhost:8050 (default PORT)
Demo extras: locale switch, / default-locale home, SEO Admin at /admin/seo. See docs/DEMO-FRANKENPHP.md.
The screenshot at the top is the demo SEO Admin. Refresh it with make -C demo/symfony8 demo-screenshots; make -C demo/symfony8 test-e2e runs the Playwright happy path (localized metadata, hreflang switch, sitemap/robots, admin).
Documentation
- Installation
- Configuration
- Usage
- Contributing
- Code of Conduct
- Changelog
- Upgrading
- Release
- Security
- Engram
- Spec-driven development
- GitHub Spec Kit
Additional documentation
- PSR evaluation (REQ-CS-007)
- Demo with FrankenPHP (includes worker mode)
- FrankenPHP worker audit (kernel not reset between requests)
- Server cookbook (Nginx, php-fpm, FrankenPHP)
- GitHub Actions CI requirements
Tests and coverage
make test
make test-coverage
- Tests: PHPUnit (
tests/Unit+ kernel integration intests/Integration) - PHP: 100% lines (2520/2520,
make test-coverage). TS/JS: N/A. Python: N/A.
License
MIT — see LICENSE.

