定制 druidvav/page-metadata-bundle 二次开发

按需修改功能、优化性能、对接业务系统,提供一站式技术支持

邮箱:yvsm@zunyunkeji.com | QQ:316430983 | 微信:yvsm316

druidvav/page-metadata-bundle

Composer 安装命令:

composer require druidvav/page-metadata-bundle

包简介

README 文档

README

Symfony bundle for managing page titles, meta tags, canonical URLs, Open Graph and Twitter metadata, breadcrumbs, and Schema.org JSON-LD from one request-scoped metadata object.

Requirements

  • PHP 7.4 or later
  • Symfony 5, 6, or 7
  • Twig 2.7 or later

Installation

composer require druidvav/page-metadata-bundle

When Symfony Flex is not available, register the bundle manually:

// config/bundles.php

return [
    // ...
    Druidvav\PageMetadataBundle\DvPageMetadataBundle::class => ['all' => true],
];

Render the metadata in the document head and breadcrumbs where they belong in the page body:

<head>
    {{ page_meta() }}
</head>
<body>
    {{ page_breadcrumbs() }}
</body>

page_meta() renders the title, standard meta tags, canonical link, Open Graph and Twitter tags, and structured data.

Configuration

base_url is required. All other sections are optional:

# config/packages/dv_page_metadata.yaml
dv_page_metadata:
    base_url: '%env(DEFAULT_URI)%'

    title:
        default: 'Example'
        delimiter: ' - '
        locale: null
        translation_domain: null

    meta:
        description: null
        keywords: null

    opengraph:
        site_name: 'Example'
        type: website
        image: '/default-cover.jpg'
        twitter_image: '/default-cover.jpg'
        twitter_site: '@example'

    breadcrumbs:
        listId: ''
        listClass: ''
        itemClass: ''
        linkRel: ''
        locale: null
        translation_domain: null
        viewTemplate: '@DvPageMetadata/breadcrumbs/bootstrap.html.twig'

    structured_data:
        enabled: true
        breadcrumbs: true
        nodes: { }

base_url is the canonical site root shared by metadata features that need to turn a path into an absolute URL. Values with and without a trailing slash are accepted; PageMetadata::setBaseUrl() strips trailing slashes before storing the value. A missing or empty value is rejected. Relative metadata paths such as /cover.jpg and structured-data identifiers such as /#organization are resolved against this URL; absolute URIs are left unchanged.

The locale and translation_domain configuration keys are retained by the bundle configuration. Set the active translation domain at runtime with PageMetadata::setTransDomain() when translated titles, descriptions, or breadcrumb labels are required.

Canonical URL, canonical language, Open Graph URL, and Twitter card type have no configuration defaults and are normally set per request through the PHP API.

Using PageMetadata

Inject PageMetadata into a controller, event listener, or another service:

use Druidvav\PageMetadataBundle\PageMetadata;

final class ArticleController
{
    private PageMetadata $pageMetadata;

    public function __construct(PageMetadata $pageMetadata)
    {
        $this->pageMetadata = $pageMetadata;
    }

    public function __invoke(Article $article): Response
    {
        $this->pageMetadata
            ->setTitle($article->getTitle())
            ->setDescription($article->getDescription())
            ->setImage($article->getCoverUrl())
            ->setLinkCanonical($article->getCanonicalUrl())
            ->setOgUrl($article->getCanonicalUrl())
            ->setOgTwitterCard(PageMetadata::TWITTER_CARD_SUMMARY_LARGE_IMAGE);

        // Render the response.
    }
}

Setter methods return the same PageMetadata instance and can be chained, except for setTransDomain() and setTitleDelimiter().

Setter injection trait

Autoconfigured Symfony services can use PageMetadataAwareTrait instead of constructor injection:

use Druidvav\PageMetadataBundle\PageMetadataAwareTrait;

final class ArticleController
{
    use PageMetadataAwareTrait;
}

Constructor injection is preferable when page metadata is a required dependency. The trait is useful for optional integration or existing classes where changing the constructor is inconvenient.

Titles

setTitle() updates both the HTML page title and the Open Graph/Twitter title:

$pageMetadata->setTitle('Article title');

Titles can be composed using a configured delimiter:

use Druidvav\PageMetadataBundle\PageMetadata;

$pageMetadata
    ->setTitle('Example')
    ->addTitle('Air quality', [], PageMetadata::MODE_PREPEND);

// Air quality - Example

Available modes are:

  • PageMetadata::MODE_SET — replace all title parts;
  • PageMetadata::MODE_PREPEND — add a part before the existing title;
  • PageMetadata::MODE_APPEND — add a part after the existing title.

Use setPageTitle() and addPageTitle() when only the HTML <title> should change. Use setOgTitle() and addOgTitle() when only Open Graph and Twitter title tags should change.

Descriptions and keywords

setDescription() updates both the standard meta description and the Open Graph/Twitter description:

$pageMetadata->setDescription('Current air quality and pollution measurements.');

They can also be controlled independently:

$pageMetadata->setMetaDescription('Search result description.');
$pageMetadata->setOgDescription('Social sharing description.');

setMetaKeywords() accepts a comma-separated string, trims individual values, and removes duplicates:

$pageMetadata->setMetaKeywords('air quality, Armenia, air quality');
// air quality, Armenia

Translation

Set a translation domain before passing translation IDs:

$pageMetadata->setTransDomain('messages');

$pageMetadata->setTitle('article.page_title', [
    '%title%' => $article->getTitle(),
]);

$pageMetadata->addRouteItem('navigation.home', 'homepage');

The bundle treats lowercase identifiers containing letters, numbers, _, -, or . as translation IDs. Strings containing % are also passed through the translator. Other strings are used as provided.

An explicit translation domain can be passed to description setters:

$pageMetadata->setDescription('article.description', [], 'articles');
$pageMetadata->setMetaDescription('article.search_description', [], 'articles');
$pageMetadata->setOgDescription('article.share_description', [], 'articles');

Canonical metadata

$pageMetadata
    ->setLinkCanonical('https://example.com/en/articles/air-quality')
    ->setLinkCanonicalLang('en')
    ->setOgUrl('https://example.com/en/articles/air-quality');

The values are available in Twig through page_link_canonical(), page_link_canonical_lang(), and page_og_url().

Open Graph and Twitter

Convenience setters keep common values synchronized:

$pageMetadata->setTitle('Page title');       // HTML title and OG/Twitter title
$pageMetadata->setDescription('Summary');   // meta and OG/Twitter description
$pageMetadata->setImage($absoluteImageUrl); // OG and Twitter image

Individual fields can be changed separately:

$pageMetadata
    ->setOgType('article')
    ->setOgSiteName('Example')
    ->setOgTitle('Social title')
    ->setOgDescription('Social description')
    ->setOgImage('https://example.com/og-cover.jpg')
    ->setOgTwitterImage('https://example.com/twitter-cover.jpg')
    ->setOgTwitterSite('@example')
    ->setOgTwitterCard(PageMetadata::TWITTER_CARD_SUMMARY_LARGE_IMAGE);

Supported Twitter card constants are:

  • PageMetadata::TWITTER_CARD_SUMMARY;
  • PageMetadata::TWITTER_CARD_SUMMARY_LARGE_IMAGE.

Configure or set og:site_name when Open Graph output is used. The default metadata template renders og:type together with og:site_name.

Breadcrumbs

Add breadcrumb labels and routes in display order:

use Symfony\Component\Routing\Generator\UrlGeneratorInterface;

$pageMetadata
    ->addRouteItem('navigation.home', 'homepage')
    ->addRouteItem(
        'navigation.article',
        'article_show',
        ['slug' => $article->getSlug()],
        UrlGeneratorInterface::ABSOLUTE_PATH,
        ['%title%' => $article->getTitle()]
    );

Arguments of addRouteItem() are:

  1. label or translation ID;
  2. Symfony route name;
  3. route parameters;
  4. URL reference type, defaulting to ABSOLUTE_PATH;
  5. translation parameters for the label.

Render the default breadcrumb namespace with:

{{ page_breadcrumbs() }}

Template options can be overridden for one rendering:

{{ page_breadcrumbs({
    listId: 'page-breadcrumbs',
    listClass: 'mb-4',
    itemClass: 'text-secondary',
    linkRel: 'nofollow'
}) }}

The default template contains Bootstrap 4/5-compatible markup. A Bootstrap 3 variant is available at @DvPageMetadata/breadcrumbs/bootstrap3.html.twig. A custom template receives the configured options and a breadcrumbs array containing Breadcrumb objects with text and url properties.

Breadcrumb namespaces are supported by getNsBreadcrumbs() and by the rendering function's namespace option. Adding items to a custom namespace requires extending PageMetadata and using its protected addBreadcrumbToNs() method. The public addRouteItem() method adds to the default namespace.

Structured data

The bundle renders Schema.org data as one JSON-LD object containing a single @context and an @graph with all configured and dynamic nodes.

Static nodes

Site-wide nodes can be configured once:

dv_page_metadata:
    base_url: '%env(DEFAULT_URI)%'

    structured_data:
        enabled: true
        breadcrumbs: true
        nodes:
            organization:
                '@type': Organization
                '@id': '/#organization'
                name: Example
                url: '/'
                logo: '/logo.jpg'

            website:
                '@type': WebSite
                '@id': '/#website'
                name: Example
                url: '/'
                publisher:
                    '@id': '/#organization'
                inLanguage: [en, fr]

The YAML keys organization and website are internal node names. They are not included in the generated JSON-LD.

Dynamic nodes

Add page-specific data through PageMetadata:

$pageMetadata->setStructuredData('article', [
    '@type' => 'BlogPosting',
    '@id' => $article->getCanonicalUrl() . '#article',
    'headline' => $article->getTitle(),
    'description' => $article->getDescription(),
    'datePublished' => $article->getPublishedAt(),
    'dateModified' => $article->getModifiedAt(),
    'publisher' => [
        '@id' => 'https://example.com/#organization',
    ],
]);

Calling setStructuredData() with the same internal name replaces the previous node without changing its graph position. This can be used to override a node loaded from configuration.

The node-level @context key is removed because the bundle owns the graph context. Other Schema.org properties remain generic, so the API can represent any current or future Schema.org type.

Date and value normalization

Any DateTimeInterface value is converted recursively to DATE_ATOM ISO 8601 format:

$pageMetadata->setStructuredData('event', [
    '@type' => 'Event',
    'startDate' => new DateTimeImmutable('2026-08-01 10:00:00+04:00'),
    'subEvent' => [
        'startDate' => new DateTime('2026-08-01 12:00:00+04:00'),
    ],
]);

Structured values may contain strings, integers, floats, booleans, null, nested arrays, and DateTimeInterface instances. Strings starting with / or # are resolved against base_url; absolute URIs and other strings are preserved. Unsupported objects or resources cause an InvalidArgumentException whose message includes the property path.

Removing and reading nodes

$pageMetadata->removeStructuredData('article');
$pageMetadata->clearStructuredData();

$namedNodes = $pageMetadata->getStructuredData();
$graph = $pageMetadata->getStructuredDataGraph();
$graphWithoutBreadcrumbs = $pageMetadata->getStructuredDataGraph(false);

getStructuredData() preserves internal names. getStructuredDataGraph() returns the sequential array used as @graph and optionally appends generated breadcrumb data.

BreadcrumbList

When structured_data.breadcrumbs is enabled and the default namespace contains at least two breadcrumbs, the bundle appends a BreadcrumbList node automatically. Relative breadcrumb paths use the global base_url; the current request is not used to determine the host.

Rendering and escaping

Structured data is included automatically by page_meta():

{{ page_meta() }}

page_structured_data() is available for custom head templates that render individual metadata functions instead of calling page_meta():

<title>{{ page_title() }}</title>
{{ page_structured_data() }}

Do not call both page_meta() and page_structured_data() in the same document, because page_meta() already includes the JSON-LD block.

JSON is encoded with Unicode and URLs left readable, while HTML-sensitive characters are escaped to prevent values such as </script> from leaving the JSON-LD script element.

Autotext integration

The optional meniam/autotext package can generate title, description, and keyword variants:

composer require meniam/autotext

Available methods are:

$pageMetadata->setTitleAutotext($title, [], $stableId);
$pageMetadata->setMetaDescriptionAutotext($description, [], $stableId);
$pageMetadata->setMetaKeywordsAutotext($keywords, [], $stableId);

The optional stable ID controls deterministic variant selection according to the Autotext package behavior. When the optional package is not installed, calling any Autotext method throws a LogicException containing the installation command instead of causing a missing-class error.

Twig functions

Function Result
page_meta() Complete metadata HTML, including structured data
page_breadcrumbs(options = {}) Rendered breadcrumb HTML
page_structured_data() JSON-LD script for custom metadata templates
page_title() Composed HTML page title
page_description(default = null) Meta description or supplied default
page_keywords(default = null) Meta keywords or supplied default
page_link_canonical() Canonical URL
page_link_canonical_lang() Canonical language value
page_og_type() Open Graph type
page_og_url() Open Graph URL
page_og_site_name() Open Graph site name
page_og_image() Open Graph image
page_og_title() Composed Open Graph/Twitter title
page_og_description() Open Graph/Twitter description
page_twitter_image() Twitter image
page_twitter_site() Twitter account
page_twitter_card() Twitter card type

Custom templates

The built-in templates are:

  • @DvPageMetadata/meta.html.twig — complete metadata output;
  • @DvPageMetadata/structured_data.html.twig — JSON-LD script wrapper;
  • @DvPageMetadata/breadcrumbs/bootstrap.html.twig — Bootstrap 4/5 breadcrumbs;
  • @DvPageMetadata/breadcrumbs/bootstrap3.html.twig — Bootstrap 3 breadcrumbs.

Configure breadcrumbs.viewTemplate to use an application template. Symfony's standard bundle template overriding mechanism can also be used to customize metadata output globally.

Testing

Install development dependencies and run:

composer install
composer test

druidvav/page-metadata-bundle 适用场景与选型建议

druidvav/page-metadata-bundle 是一款 基于 PHP 开发的 Composer 扩展包,目前已累计 5.93k 次下载、GitHub Stars 达 0, 最近一次更新时间为 2017 年 06 月 30 日, 在 PHP 生态内属于活跃度较高的组件。

我们在过去多个企业项目中使用过 druidvav/page-metadata-bundle 或与其功能相近的方案,如果你在选型或落地过程中遇到问题,例如 版本兼容、二次改造、私有化封装、与内部系统对接、生产 BUG 排查,欢迎联系我们协助评估。

围绕 druidvav/page-metadata-bundle 我们能提供哪些服务?
定制开发 / 二次开发

基于 druidvav/page-metadata-bundle 在你已有业务上做功能扩展、字段裁剪、UI 适配、与内部账号 / 权限 / 日志系统的深度对接。

BUG 修复 & 性能优化

线上偶发问题、内存泄漏、慢查询、并发异常等排查修复;针对高流量场景做缓存、队列、索引层面的调优。

项目外包 & 长期维护

承接完整的项目从需求 → 设计 → 开发 → 上线 → 长期运维;也可按月提供技术保姆服务。

yvsm@zunyunkeji.com QQ:316430983 微信:yvsm316 西安尊云信息科技 · 专注 PHP / Go / 分布式系统研发

统计信息

  • 总下载量: 5.93k
  • 月度下载量: 0
  • 日度下载量: 0
  • 收藏数: 0
  • 点击次数: 4
  • 依赖项目数: 0
  • 推荐数: 0

GitHub 信息

  • Stars: 0
  • Watchers: 2
  • Forks: 0
  • 开发语言: PHP

其他信息

  • 授权协议: MIT
  • 更新时间: 2017-06-30