daddl3/seo-tool-bundle
Composer 安装命令:
composer require daddl3/seo-tool-bundle
包简介
All in One Symfony Seo Bundle
README 文档
README
All-in-One Symfony SEO Bundle — Meta Tags, Open Graph, Schema.org, Breadcrumbs, Google Tag Manager, Meta Pixel, and full Profiler support.
Requirements: PHP 8.5+, Symfony 8.x
Installation
composer require daddl3/seo-tool-bundle
Symfony Flex registers the bundle automatically. If not:
// config/bundles.php
return [
Daddl3\SeoToolBundle\SeoBundle::class => ['all' => true],
];
Configuration
All options in config/packages/seo.yaml:
seo:
# Schema.org — inject JSON-LD into <head>
schema:
enabled: true
cache_ttl: 604800 # Cache in seconds (default: 1 week)
# Meta Tags — global default values
meta_tags:
title: 'My Website'
description: 'Default description'
keywords: ['symfony', 'seo']
# Open Graph — global default values
open_graph:
title: 'My Website'
description: 'Default description'
sitename: 'My Website'
url: 'https://example.com'
type: 'website'
# Google Tag Manager
google_tag_manager:
enabled: true
tag_manager_id: 'GTM-XXXXXX'
# Meta Pixel (Facebook)
meta_pixel:
enabled: true
pixel_id: '1234567890'
Features
Meta Tags
In the Controller
use Daddl3\SeoToolBundle\Metas\MetaTagsManagerInterface;
class ProductController extends AbstractController
{
public function show(MetaTagsManagerInterface $meta): Response
{
$meta
->setTitle('Product Name')
->setDescription('Short product description')
->setKeywords(['product', 'shop', 'symfony'])
->setCanonical('https://example.com/product')
->setRobots(['index', 'follow'])
->setAuthor('John Doe')
->setViewPort('width=device-width, initial-scale=1')
->setCharacterEncoding('UTF-8')
->setCopyright('2025 Example Inc.')
->setContentType('text/html; charset=UTF-8')
->setContentSecurityPolicy("default-src 'self'")
->setSubject('E-Commerce')
->setXUACompatible()
->setCustomMetaTag('theme-color', '#ffffff')
;
return $this->render('product/show.html.twig');
}
}
In a Twig Template
{{ meta_tags(
title: 'Product Name',
description: 'Short description',
keywords: ['product', 'shop'],
canonical: 'https://example.com/product',
robots: ['index', 'follow']
) }}
Values from the controller and the template are merged. Template values override controller values.
Include in the Base Template
<head>
{{ meta_tags() }}
</head>
Output
<meta charset="UTF-8" />
<title>Product Name</title>
<meta name="description" content="Short product description" />
<meta name="keywords" content="product, shop, symfony" />
<meta name="robots" content="index, follow" />
<link rel="canonical" href="https://example.com/product" />
<meta name="author" content="John Doe" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
All Available Methods
| Method | Description |
|---|---|
setTitle(string) | Page title (<title>) |
setDescription(string) | Meta description |
setKeywords(array) | Meta keywords |
setCanonical(string) | Canonical URL |
setRobots(array) | Robots directives (index, follow, noindex, …) |
setAuthor(string) | Author |
setViewPort(string) | Viewport |
setCharacterEncoding(string) | Character encoding (default: UTF-8) |
setCopyright(string) | Copyright notice |
setSubject(string) | Page subject |
setContentType(string) | Content type |
setContentSecurityPolicy(string) | CSP header |
setAlternate(string, string) | Alternate link (href, media) |
setXUACompatible() | IE compatibility mode (IE=edge) |
setDefaultStyle(string) | Default stylesheet |
setCustomMetaTag(string, string) | Custom meta tag (name, content) |
Open Graph
In the Controller
use Daddl3\SeoToolBundle\OpenGraph\OpenGraphManagerInterface;
class ArticleController extends AbstractController
{
public function show(OpenGraphManagerInterface $og): Response
{
$og
->setTitle('Article Title')
->setDescription('Description for social media')
->setImage('https://example.com/image.jpg')
->setImageAltText('Image description')
->setUrl('https://example.com/article')
->setType('article')
->setLocale('en_US')
->setAlternateLocale('de_DE')
->setSiteName('My Website')
;
return $this->render('article/show.html.twig');
}
}
In a Twig Template
{{ open_graph(
title: 'Article Title',
description: 'Description for social media',
imageUrl: 'https://example.com/image.jpg',
url: 'https://example.com/article',
type: 'article'
) }}
Include in the Base Template
<head>
{{ open_graph() }}
</head>
Output
<meta property="og:title" content="Article Title" />
<meta property="og:description" content="Description for social media" />
<meta property="og:image" content="https://example.com/image.jpg" />
<meta property="og:url" content="https://example.com/article" />
<meta property="og:type" content="article" />
<meta property="og:site_name" content="My Website" />
OG Image
Extended image metadata with og:image:* tags.
Controller:
use Daddl3\SeoToolBundle\OpenGraph\OGImageManagerInterface;
public function show(OGImageManagerInterface $ogImage): Response
{
$ogImage
->setUrl('https://example.com/og.jpg')
->setSecureUrl('https://example.com/og.jpg')
->setType('image/jpeg')
->setWidth('1200')
->setHeight('630')
->setAlt('Image description')
;
}
Twig:
{{ og_image(
url: 'https://example.com/og.jpg',
type: 'image/jpeg',
width: '1200',
height: '630',
alt: 'Image description'
) }}
Output:
<meta property="og:image" content="https://example.com/og.jpg" />
<meta property="og:image:secure_url" content="https://example.com/og.jpg" />
<meta property="og:image:type" content="image/jpeg" />
<meta property="og:image:width" content="1200" />
<meta property="og:image:height" content="630" />
<meta property="og:image:alt" content="Image description" />
OG Video
Controller:
use Daddl3\SeoToolBundle\OpenGraph\OGVideoManagerInterface;
public function show(OGVideoManagerInterface $ogVideo): Response
{
$ogVideo
->setUrl('https://example.com/video.mp4')
->setSecureUrl('https://example.com/video.mp4')
->setType('video/mp4')
->setWidth('1280')
->setHeight('720')
;
}
Twig:
{{ og_video(url: 'https://example.com/video.mp4', type: 'video/mp4', width: '1280', height: '720') }}
Output:
<meta property="og:video" content="https://example.com/video.mp4" />
<meta property="og:video:secure_url" content="https://example.com/video.mp4" />
<meta property="og:video:type" content="video/mp4" />
<meta property="og:video:width" content="1280" />
<meta property="og:video:height" content="720" />
OG Audio
Controller:
use Daddl3\SeoToolBundle\OpenGraph\OGAudioManagerInterface;
public function show(OGAudioManagerInterface $ogAudio): Response
{
$ogAudio
->setUrl('https://example.com/audio.mp3')
->setSecureUrl('https://example.com/audio.mp3')
->setType('audio/mpeg')
;
}
Twig:
{{ og_audio(url: 'https://example.com/audio.mp3', type: 'audio/mpeg') }}
Output:
<meta property="og:audio" content="https://example.com/audio.mp3" />
<meta property="og:audio:secure_url" content="https://example.com/audio.mp3" />
<meta property="og:audio:type" content="audio/mpeg" />
OG Article
Controller:
use Daddl3\SeoToolBundle\OpenGraph\OGArticleManagerInterface;
public function show(OGArticleManagerInterface $ogArticle): Response
{
$ogArticle
->setPublishedTime(new \DateTime('2025-01-15'))
->setModifiedTime(new \DateTime('2025-06-01'))
->setAuthor('John Doe')
->setSection('Technology')
->setTags(['symfony', 'php', 'seo'])
;
}
Twig:
{{ og_article(
author: 'John Doe',
section: 'Technology',
tags: ['symfony', 'php', 'seo']
) }}
Output:
<meta property="article:published_time" content="..." />
<meta property="article:modified_time" content="..." />
<meta property="article:author" content="John Doe" />
<meta property="article:section" content="Technology" />
<meta property="article:tag" content="symfony" />
<meta property="article:tag" content="php" />
<meta property="article:tag" content="seo" />
Twitter Cards
Twitter Cards are added via the OpenGraphManager:
$og->addTwitterCardProperty('card', 'summary_large_image');
$og->addTwitterCardProperty('site', '@myWebsite');
$og->addTwitterCardProperty('creator', '@author');
$og->addTwitterCardProperty('title', 'Article Title');
$og->addTwitterCardProperty('description', 'Description for Twitter');
Output:
<meta property="twitter:card" content="summary_large_image" />
<meta property="twitter:site" content="@myWebsite" />
<meta property="twitter:creator" content="@author" />
Structured Properties
For og:video:*, og:audio:*, and og:image:* inline in the OG block:
$og->addStructuredProperty('video', 'secure_url', 'https://example.com/video.mp4');
$og->addStructuredProperty('image', 'width', '1200');
Output:
<meta property="og:video:secure_url" content="https://example.com/video.mp4" />
<meta property="og:image:width" content="1200" />
For music:
$og->addMusicProperty('musician', 'https://example.com/artist');
Schema.org (Rich Results)
First enable it in the configuration:
seo:
schema:
enabled: true
cache_ttl: 604800
The schema is automatically injected as <script type="application/ld+json"> into the <head>.
In the Controller
use Daddl3\SeoToolBundle\Schema\SchemaInterface;
class ArticleController extends AbstractController
{
public function show(SchemaInterface $schema): Response
{
$article = $schema->article()
->name('My Article')
->setDescription('Article description')
->url('https://example.com/article')
;
$schema->render($article);
return $this->render('article/show.html.twig');
}
}
Output
<script type="application/ld+json">
{
"@context": "https://schema.org",
"@type": "Article",
"name": "My Article",
"description": "Article description",
"url": "https://example.com/article"
}
</script>
Nested Objects
$person = $schema->person()
->name('John Doe')
->url('https://example.com/john')
;
$org = $schema->organization()
->name('Example Inc.')
->url('https://example.com')
;
$schema->render(
$schema->article()
->name('My Article')
->setDescription('...')
);
Supported Schema Types
| Category | Types |
|---|---|
| Thing | thing(), person(), organization(), place(), event(), action() |
| CreativeWork | creativeWork(), article(), blogPosting(), socialMediaPosting(), blog(), course(), thesis(), website(), mediaObject(), imageObject(), textObject() |
| WebPage | webPage(), aboutPage(), contactPage(), faqPage(), itemPage(), checkoutPage(), profilePage(), searchResultPage(), collectionPage(), mediaGallery(), imageGallery(), webPageElement() |
| Organization | organization(), localBusiness(), library(), radioStation(), travelAgency() |
| Place | place(), administrativeArea(), country() |
| Intangible | jobPosting(), occupation(), breadcrumbList(), listItem(), itemList(), definedTerm(), specialty(), speakableSpecification(), monetaryAmount(), propertyValue(), offer() |
| Other | service(), audience(), postalAddress(), educationOccupationalCredential() |
Breadcrumb
In the Controller
use Daddl3\SeoToolBundle\Breadcrumb\BreadcrumbManagerInterface;
class BlogController extends AbstractController
{
public function show(BreadcrumbManagerInterface $breadcrumb): Response
{
$breadcrumb
->addItem('Home', 'https://example.com')
->addItem('Blog', 'https://example.com/blog')
->addItem('My Article') // last item without URL = active
;
return $this->render('blog/show.html.twig');
}
}
Render in the Template
{{ seo_breadcrumb() }}
Output (Bootstrap)
<ol class="breadcrumb">
<li class="breadcrumb-item"><a href="https://example.com">Home</a></li>
<li class="breadcrumb-item"><a href="https://example.com/blog">Blog</a></li>
<li class="breadcrumb-item active">My Article</li>
</ol>
Customize CSS Classes
$breadcrumb->setOptions([
'list_class' => 'breadcrumb',
'list_item_class' => 'breadcrumb-item',
'active_item' => 'active',
]);
Google Tag Manager
Configuration (automatically on all pages)
seo:
google_tag_manager:
enabled: true
tag_manager_id: 'GTM-XXXXXX'
Automatically injects the GTM code into <head> and <body>.
Programmatically per Request
use Daddl3\SeoToolBundle\Seo\GoogleTagManager\TagManagerInterface;
public function index(TagManagerInterface $tagManager): Response
{
$tagManager->enableGoogleTagManager('GTM-XXXXXX');
return $this->render('index.html.twig');
}
Meta Pixel (Facebook)
Configuration (automatically on all pages)
seo:
meta_pixel:
enabled: true
pixel_id: '1234567890'
Programmatically per Request
use Daddl3\SeoToolBundle\Seo\MetaPixel\MetaPixelInterface;
public function index(MetaPixelInterface $metaPixel): Response
{
$metaPixel->enableMetaPixel('1234567890');
return $this->render('index.html.twig');
}
Symfony Profiler
A full SEO profiler is available in dev mode.
Toolbar shows the status of all features at a glance:
| Feature | Green | Yellow | Red |
|---|---|---|---|
| Meta Tags | set | — | not set |
| Open Graph | set | — | not set |
| Twitter Cards | set | not set | — |
| OG Image / Video / Audio / Article | set | not set | — |
| Schema.org | type name | not set | — |
| Breadcrumb | number of items | 0 items | — |
| Google GTM | GTM ID | not configured | — |
| Meta Pixel | Pixel ID | not configured | — |
Profiler panel shows for each page:
- Overview of all features with status
- All set meta tags in detail
- Open Graph tags (base, Twitter Cards, Structured Properties, Music)
- Separate panels for OG Image, Video, Audio, Article Manager
- Schema.org JSON-LD preview
- Breadcrumb items as a table
- Google Tag Manager ID
- Meta Pixel ID
daddl3/seo-tool-bundle 适用场景与选型建议
daddl3/seo-tool-bundle 是一款 基于 PHP 开发的 Composer 扩展包,目前已累计 100 次下载、GitHub Stars 达 0, 最近一次更新时间为 2026 年 03 月 31 日, 在 PHP 生态内属于活跃度较高的组件。
它主要适用于以下技术方向: 「seo」 「Symfony Bundle」 「symfony seo」 等业务场景。在实际项目中,围绕这些方向常见需要落地的问题包括:接口对接、性能调优、并发安全、与既有框架(Laravel / ThinkPHP / Yii / Webman 等)的兼容适配,以及生产环境的日志埋点与稳定性保障。
我们在过去多个企业项目中使用过 daddl3/seo-tool-bundle 或与其功能相近的方案,如果你在选型或落地过程中遇到问题,例如 版本兼容、二次改造、私有化封装、与内部系统对接、生产 BUG 排查,欢迎联系我们协助评估。
基于 daddl3/seo-tool-bundle 在你已有业务上做功能扩展、字段裁剪、UI 适配、与内部账号 / 权限 / 日志系统的深度对接。
线上偶发问题、内存泄漏、慢查询、并发异常等排查修复;针对高流量场景做缓存、队列、索引层面的调优。
承接完整的项目从需求 → 设计 → 开发 → 上线 → 长期运维;也可按月提供技术保姆服务。
与 daddl3/seo-tool-bundle 相关的其它包
同方向 / 同关键字的高下载量 PHP Composer 包推荐,方便对比选型:
2lenet/EasyAdminPlusBundle
The bundle for easy using json-rpc api on your project
Provide a way to secure accesses to all routes of an symfony application.
Help to manage meta data on Laravel Eloquent model
DMS Meetup API Bundle, enables Meetup API clients in services
Statamic Fine Seo addon
统计信息
- 总下载量: 100
- 月度下载量: 0
- 日度下载量: 0
- 收藏数: 0
- 点击次数: 10
- 依赖项目数: 0
- 推荐数: 0
其他信息
- 授权协议: MIT
- 更新时间: 2026-03-31