PHPackages                             mulertech/seo-bundle - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. [Utility &amp; Helpers](/categories/utility)
4. /
5. mulertech/seo-bundle

ActiveSymfony-bundle[Utility &amp; Helpers](/categories/utility)

mulertech/seo-bundle
====================

Symfony bundle for SEO management: meta tags (OpenGraph, Twitter Cards), Schema.org JSON-LD structured data, sitemap XML generation, and robots.txt

v1.1.0(1w ago)166↑42.9%MITPHPPHP ^8.4CI passing

Since Apr 10Pushed 1w ago1 watchersCompare

[ Source](https://github.com/mulertech/seo-bundle)[ Packagist](https://packagist.org/packages/mulertech/seo-bundle)[ RSS](/packages/mulertech-seo-bundle/feed)WikiDiscussions main Synced 1w ago

READMEChangelog (5)Dependencies (13)Versions (6)Used By (0)

MulerTech SEO Bundle
====================

[](#mulertech-seo-bundle)

---

[![Latest Version on Packagist](https://camo.githubusercontent.com/6f127c41db03e7b511025ad8333a78b90d73d2a7f9f7eabf1fe7fdee153dffad/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f762f6d756c6572746563682f73656f2d62756e646c652e7376673f7374796c653d666c61742d737175617265)](https://packagist.org/packages/mulertech/seo-bundle)[![GitHub Tests Action Status](https://camo.githubusercontent.com/053f9e053a5aeeba02aa1353519ed72a747444262fe244d61ed72d7b7cb2269c/68747470733a2f2f696d672e736869656c64732e696f2f6769746875622f616374696f6e732f776f726b666c6f772f7374617475732f6d756c6572746563682f73656f2d62756e646c652f74657374732e796d6c3f6272616e63683d6d61696e266c6162656c3d7465737473267374796c653d666c61742d737175617265)](https://github.com/mulertech/seo-bundle/actions/workflows/tests.yml)[![GitHub PHPStan Action Status](https://camo.githubusercontent.com/16b51f8176c7f2e64a21204ff7bccbf7e407e7a35010d986727c87e80d3d1fcd/68747470733a2f2f696d672e736869656c64732e696f2f6769746875622f616374696f6e732f776f726b666c6f772f7374617475732f6d756c6572746563682f73656f2d62756e646c652f7068707374616e2e796d6c3f6272616e63683d6d61696e266c6162656c3d7068707374616e267374796c653d666c61742d737175617265)](https://github.com/mulertech/seo-bundle/actions/workflows/phpstan.yml)[![GitHub Security Action Status](https://camo.githubusercontent.com/7eca721e6153ffe44a5f7b4bc9e48ab45505663d79ef69241573c42fbc35ad23/68747470733a2f2f696d672e736869656c64732e696f2f6769746875622f616374696f6e732f776f726b666c6f772f7374617475732f6d756c6572746563682f73656f2d62756e646c652f73656375726974792e796d6c3f6272616e63683d6d61696e266c6162656c3d7365637572697479267374796c653d666c61742d737175617265)](https://github.com/mulertech/seo-bundle/actions/workflows/security.yml)[![Total Downloads](https://camo.githubusercontent.com/88563de6703562fc65a9b1530d6ff5c5f0c1170b4b3498964077dfcf2cd066b1/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f64742f6d756c6572746563682f73656f2d62756e646c652e7376673f7374796c653d666c61742d737175617265)](https://packagist.org/packages/mulertech/seo-bundle)[![Test Coverage](https://raw.githubusercontent.com/mulertech/seo-bundle/badge/badge-coverage.svg)](https://packagist.org/packages/mulertech/seo-bundle)

---

Symfony bundle for SEO management: meta tags (OpenGraph, Twitter Cards), Schema.org JSON-LD structured data, sitemap XML generation, robots.txt, and llms.txt.

Requirements
------------

[](#requirements)

- PHP 8.4+
- Symfony 6.4+ or 7.0+

Installation
------------

[](#installation)

```
composer require mulertech/seo-bundle
```

Configuration
-------------

[](#configuration)

```
# config/packages/mulertech_seo.yaml
mulertech_seo:
    default_image: '/images/og-default.webp'  # Default OG/Twitter image
    default_locale: 'fr_FR'                    # Default og:locale
    schema_org:
        organization_type: 'LocalBusiness'
        organization_description: 'Your company description'
        price_range: '€€'
        address_region: 'Normandie'
        search_action_path_template: '/blog?q={search_term_string}'
        areas_served:
            - { type: 'City', name: 'Caen' }
            - { type: 'AdministrativeArea', name: 'Normandie' }
            - { type: 'Country', name: 'France' }
        offer_names:
            - 'Web Development'
            - 'Hosting'
            - 'Maintenance'
    robots:
        disallow_paths:
            - '/admin'
            - '/login'
    llms:
        enabled: true                             # Serve the /llms.txt route
        title: 'My Company'                       # H1 (defaults to company name)
        summary: 'We build amazing web apps.'     # Blockquote summary
        notes: 'Optional intro prose.'            # Prose below the summary
        sections:                                 # Curated links, keyed by H2 heading
            Documentation:
                - { url: '/docs', title: 'Docs', description: 'Guides and references' }
            Services:
                - { url: '/services/web', title: 'Web Development' }
```

Usage
-----

[](#usage)

### 1. Implement SeoCompanyInfoProviderInterface

[](#1-implement-seocompanyinfoproviderinterface)

The bundle needs company information for meta tags and Schema.org data:

```
use MulerTech\SeoBundle\Model\SeoCompanyInfoProviderInterface;

class CompanyInfoProvider implements SeoCompanyInfoProviderInterface
{
    public function getName(): string { return 'My Company'; }
    public function getWebsite(): string { return 'https://mycompany.com'; }
    public function getEmail(): string { return 'contact@mycompany.com'; }
    public function getPhone(): string { return '+33 1 23 45 67 89'; }
    public function getPostalCode(): string { return '14000'; }
    public function getCity(): string { return 'Caen'; }
    public function getCountry(): string { return 'France'; }
    public function getSocialUrls(): array {
        return [
            'linkedin' => 'https://linkedin.com/company/mycompany',
            'github' => 'https://github.com/mycompany',
        ];
    }
}
```

Register it as a service aliased to the interface:

```
# config/services.yaml
MulerTech\SeoBundle\Model\SeoCompanyInfoProviderInterface:
    class: App\Seo\CompanyInfoProvider
```

### 2. Generate meta tags in controllers

[](#2-generate-meta-tags-in-controllers)

```
use MulerTech\SeoBundle\Service\MetaTagService;

class HomeController extends AbstractController
{
    public function index(MetaTagService $metaTagService): Response
    {
        $seo = $metaTagService->generateMetaTags([
            'title' => 'Welcome to My Company',
            'description' => 'We build amazing web applications.',
        ]);

        return $this->render('home/index.html.twig', ['seo' => $seo]);
    }
}
```

Include the meta tags template in your ``:

```
{% block seo_meta %}
    {% include '@MulerTechSeo/seo_meta.html.twig' with { seo: seo } %}
{% endblock %}
```

### 3. Schema.org JSON-LD in Twig (requires twig/twig)

[](#3-schemaorg-json-ld-in-twig-requires-twigtwig)

```
{# Organization + WebSite (global, in base.html.twig) #}
{{ schema_org_json_ld('organization') }}
{{ schema_org_json_ld('webSite') }}

{# Blog posting (in blog/show.html.twig) #}
{{ schema_org_json_ld('blogPosting', post) }}

{# Service (in service/show.html.twig) #}
{{ schema_org_json_ld('service', { title: 'Web Dev', description: 'Custom apps' }) }}

{# Breadcrumbs #}
{{ schema_org_json_ld('breadcrumbList', [
    { label: 'Home', url: path('app_home') },
    { label: 'Blog', url: null }
]) }}
```

For `blogPosting`, your entity must implement `BlogPostingSeoInterface`:

```
use MulerTech\SeoBundle\Model\BlogPostingSeoInterface;

class BlogPost implements BlogPostingSeoInterface
{
    public function getSeoTitle(): string { return $this->title; }
    public function getSeoExcerpt(): ?string { return $this->excerpt; }
    public function getSeoAuthorName(): string { return $this->author->getFullName(); }
    public function getSeoPublishedAt(): ?string { return $this->publishedAt?->toIso8601String(); }
    public function getSeoUpdatedAt(): ?string { return $this->updatedAt?->toIso8601String(); }
}
```

### 4. Sitemap (provider pattern)

[](#4-sitemap-provider-pattern)

Implement `SitemapUrlProviderInterface` for each content type:

```
use MulerTech\SeoBundle\Model\SitemapUrl;
use MulerTech\SeoBundle\Model\SitemapUrlProviderInterface;

class BlogSitemapProvider implements SitemapUrlProviderInterface
{
    public function __construct(
        private readonly BlogPostRepository $repository,
        private readonly UrlGeneratorInterface $urlGenerator,
    ) {}

    public function getUrls(): iterable
    {
        foreach ($this->repository->findPublished() as $post) {
            yield new SitemapUrl(
                loc: $this->urlGenerator->generate('app_blog_show', ['slug' => $post->getSlug()], UrlGeneratorInterface::ABSOLUTE_URL),
                priority: '0.6',
                changefreq: 'monthly',
                lastmod: $post->getUpdatedAt()?->toIso8601String(),
            );
        }
    }
}
```

Providers implementing `SitemapUrlProviderInterface` are auto-tagged and collected by the sitemap service.

### 5. llms.txt (provider pattern)

[](#5-llmstxt-provider-pattern)

The `/llms.txt` route serves a Markdown index for LLMs ([llmstxt.org](https://llmstxt.org/)). Static sections come from the `llms.sections` config; dynamic sections are contributed by implementing `LlmsSectionProviderInterface`:

```
use MulerTech\SeoBundle\Model\LlmsLink;
use MulerTech\SeoBundle\Model\LlmsSection;
use MulerTech\SeoBundle\Model\LlmsSectionProviderInterface;

class BlogLlmsProvider implements LlmsSectionProviderInterface
{
    public function __construct(
        private readonly BlogPostRepository $repository,
        private readonly UrlGeneratorInterface $urlGenerator,
    ) {}

    public function getSections(): iterable
    {
        $links = [];
        foreach ($this->repository->findPublished() as $post) {
            $links[] = new LlmsLink(
                url: $this->urlGenerator->generate('app_blog_show', ['slug' => $post->getSlug()], UrlGeneratorInterface::ABSOLUTE_URL),
                title: $post->getTitle(),
                description: $post->getExcerpt(),
            );
        }

        yield new LlmsSection('Blog', $links);
    }
}
```

Providers implementing `LlmsSectionProviderInterface` are auto-tagged; their sections are appended after the static config sections. Set `llms.enabled: false` to return a 404 for the route.

### Routes

[](#routes)

The bundle provides routes for `/sitemap.xml`, `/robots.txt`, and `/llms.txt`. Import them in your application:

```
# config/routes/mulertech_seo.yaml
mulertech_seo:
    resource: "@MulerTechSeoBundle/config/routes.yaml"
```

### 6. SEO fields trait (optional)

[](#6-seo-fields-trait-optional)

Add `metaDescription` and `metaKeywords` fields to any entity:

```
use MulerTech\SeoBundle\Model\SeoFieldsTrait;

class BlogPost
{
    use SeoFieldsTrait;
    // Adds: metaDescription, metaKeywords with getters/setters
}
```

Testing
-------

[](#testing)

```
./vendor/bin/mtdocker test-ai
```

License
-------

[](#license)

MIT

###  Health Score

46

—

FairBetter than 92% of packages

Maintenance98

Actively maintained with recent releases

Popularity13

Limited adoption so far

Community7

Small or concentrated contributor base

Maturity55

Maturing project, gaining track record

 Bus Factor1

Top contributor holds 100% of commits — single point of failure

How is this calculated?**Maintenance (25%)** — Last commit recency, latest release date, and issue-to-star ratio. Uses a 2-year decay window.

**Popularity (30%)** — Total and monthly downloads, GitHub stars, and forks. Logarithmic scaling prevents top-heavy scores.

**Community (15%)** — Contributors, dependents, forks, watchers, and maintainers. Measures real ecosystem engagement.

**Maturity (30%)** — Project age, version count, PHP version support, and release stability.

###  Release Activity

Cadence

Every ~12 days

Total

5

Last Release

12d ago

### Community

Maintainers

![](https://avatars.githubusercontent.com/u/57788787?v=4)[Sébastien Muler](/maintainers/mulertech)[@mulertech](https://github.com/mulertech)

---

Top Contributors

[![mulertech](https://avatars.githubusercontent.com/u/57788787?v=4)](https://github.com/mulertech "mulertech (12 commits)")

---

Tags

phpsymfonyJSON-LDSitemapseorobotsopengraphschema-orgmeta-tags

###  Code Quality

TestsPHPUnit

Static AnalysisPHPStan

Code StylePHP CS Fixer

Type Coverage Yes

### Embed Badge

![Health badge](/badges/mulertech-seo-bundle/health.svg)

```
[![Health](https://phpackages.com/badges/mulertech-seo-bundle/health.svg)](https://phpackages.com/packages/mulertech-seo-bundle)
```

###  Alternatives

[symfony/framework-bundle

Provides a tight integration between Symfony components and the Symfony full-stack framework

3.6k246.0M11.0k](/packages/symfony-framework-bundle)

PHPackages © 2026

[Directory](/)[Categories](/categories)[Trending](/trending)[Changelog](/changelog)[Analyze](/analyze)
