umanit / seo-bundle
在 Doctrine 实体上提供 SEO 功能。
Requires
- php: ^8.1
- ext-json: *
- doctrine/doctrine-bundle: ^2.0
- doctrine/doctrine-migrations-bundle: ^3.0
- doctrine/orm: ^2.7
- ramsey/uuid: ^4.1
- spatie/schema-org: ^3.2
- symfony/form: ^6.4|^7.0
- symfony/twig-bundle: ^6.4|^7.0
- twig/extra-bundle: ^3.0
- twig/twig: ^3.0
Requires (Dev)
- phpunit/phpunit: ^7.5|^9.5
- rector/rector: ^1.0
- symfony/phpunit-bridge: ^5.1|^5.2
README
此包为任何模型实体添加 SEO 功能。
功能
- 访问旧 URL 时的 301 重定向
- SEO 元数据(标题和描述)
- 规范 URL
- Schema.org
- 面包屑导航
- 网站地图
安装
$ composer require umanit/seo-bundle
配置
需要在您的 Twig 配置中声明模板,在其他模板之前。您必须在这两个选项中选择一个
twig: # ... form_themes: - '@UmanitSeo/sylius/form/fields.html.twig' # OR - '@UmanitSeo/sonata/form/fields.html.twig' - ...
您可以通过创建 umanit_seo.yaml
配置文件来进一步配置您的包。以下是包提供的默认配置
# Default configuration for extension with alias: "umanit_seo" umanit_seo: # Historize URLs of entities which implements HistorizableUrlModelInterface url_historization: enabled: true # Redirect code used by UrlRedirectorSubscriber redirect_code: 301 # Cache service used to store entities dependencies. **MUST** implements \Symfony\Contracts\Cache\CacheInterface cache_service: cache.app # Defines the default templates used to render breadcrumbs templates: breadcrumb_json_ld: '@UmanitSeo/breadcrumb/breadcrumb.json-ld.html.twig' breadcrumb_microdata: '@UmanitSeo/breadcrumb/breadcrumb.microdata.html.twig' breadcrumb_rdfa: '@UmanitSeo/breadcrumb/breadcrumb.rdfa.html.twig' metadata: form_type: # Automaticaly add a SeoMetadataType on FormType which handled an entity which implements HasSeoMetadataInterface add_seo_metadata_type: true # FQCN of the FormType used to renders SEO Metadata fields class_fqcn: Umanit\SeoBundle\Form\Type\SeoMetadataType # Injects Google Code Prettify when rendering breadcrumb and schema.org in FormType. inject_code_prettify: true default_title: 'Umanit Seo - Customize this default title to your needs.' title_prefix: '' title_suffix: '' default_description: 'Umanit Seo - Customize this default description to your needs.'
用法
基本用法
为了正常工作,SeoBundle 必须能够为给定实体生成 URL。为此,umanit_seo.routable
服务使用处理器来处理实体。
处理器是一个实现 Umanit\SeoBundle\Handler\Routable\RoutableHandlerInterface
的服务。一个 supports
方法表示服务是否可以处理给定的实体,一个 process
方法通过返回一个 Umanit\SeoBundle\Model\Route
对象来完成工作。
Umanit\SeoBundle\Model\Route
对象有一个 name
属性,这是访问实体的路由名称,还有一个 parameters
属性,用于构建路由。
您必须在您的实体上实现 Umanit\SeoBundle\Model\RoutableModelInterface
接口,并创建一个处理器来处理它。
<?php declare(strict_types=1); namespace App\Entity; use Doctrine\ORM\Mapping as ORM; use Umanit\SeoBundle\Model\RoutableModelInterface; #[ORM\Entity] class Page implements RoutableModelInterface { // ... }
<?php declare(strict_types=1); namespace App\Seo\Routable; use App\Entity\Page; use Umanit\SeoBundle\Handler\Routable\RoutableHandlerInterface; use Umanit\SeoBundle\Model\RoutableModelInterface; use Umanit\SeoBundle\Model\Route; class PageHandler implements RoutableHandlerInterface { public function supports(RoutableModelInterface $entity): bool { return $entity instanceof Page; } public function process(RoutableModelInterface $entity): Route { return new Route('app_page_show', ['slug' => $entity->getSlug()]); } }
SeoBundle 现在将能够从实体生成 URL。如果您更改了页面的 slug,旧 URL 将重定向到新 URL。
如果您想自己生成 URL,可以像以下示例那样操作
{{ path('app_page_show', { 'slug': my_page.slug }) }}"
现在您可以这样做
{{ path(my_page) }}
注意: 您可以使用 canonical()
函数而不传递任何实体,SeoBundle 将自动解析与当前访问路由关联的实体并从中生成 URL。
通常,您希望直接在主布局中使用 canonical()
函数。
SEO 元数据
在您的模板中使用 seo_metadata(your_entity)
twig 函数。
SeoBundle 将自动找到实体中最相关的字段来推断标题和描述。
同样,seo_metadata()
可以不传递任何实体使用。
管理元数据
为了管理 SEO 元数据,您需要再次调整您的实体。
使您的实体实现 HasSeoMetadataInterface
并使用 SeoMetadataTrait
<?php declare(strict_types=1); namespace App\Entity; use Umanit\SeoBundle\Doctrine\Model\SeoMetadataTrait; use Umanit\SeoBundle\Model\HasSeoMetadataInterface; use Umanit\SeoBundle\Model\RoutableModelInterface; class Page implements RoutableModelInterface, HasSeoMetadataInterface { use SeoMetadataTrait; // ... }
如果配置 umanit_seo.metadata.form_type.add_seo_metadata_type
未禁用,则处理您的实体的所有表单将自动具有一个新的 SeoMetadataType
表单类型。
这将添加一个包含两个字段(title
和 description
)的子表单。
注意: 可以使用 umanit_seo.metadata.form_type.class_fqcn
定制表单类型类。
Schema.org 实现
为了生成有效的 schema.org json 微数据,SeoBundle 必须能够处理给定的实体。为此,umanit_seo.schemable
服务使用处理器来处理实体。
处理器是一个实现 Umanit\SeoBundle\Handler\Schemable\SchemableHandlerInterface
的服务。一个 supports
方法表示服务是否可以处理给定的实体,一个 process
方法通过返回一个 Spatie\SchemaOrg\BaseType
对象来完成工作。
由库 spatie/schema-org 提供的 Spatie\SchemaOrg\BaseType
对象。
您必须在您的实体上实现接口 Umanit\SeoBundle\Model\SchemableModelInterface
并创建一个处理程序来处理它。
<?php declare(strict_types=1); namespace App\Entity; use Doctrine\ORM\Mapping as ORM; use Umanit\SeoBundle\Model\SchemableModelInterface; #[ORM\Entity] class Page implements SchemableModelInterface { // ... }
<?php declare(strict_types=1); namespace App\Seo\Schemable; use App\Entity\Page; use Spatie\SchemaOrg\BaseType; use Spatie\SchemaOrg\Schema; use Umanit\SeoBundle\Handler\Schemable\SchemableHandlerInterface; use Umanit\SeoBundle\Model\SchemableModelInterface; class PageHandler implements SchemableHandlerInterface { public function supports(SchemableModelInterface $entity): bool { return $entity instanceof Page; } /** * @param Page $entity */ public function process(SchemableModelInterface $entity): BaseType { return Schema::mensClothingStore() ->name($entity->getName()) ->url($entity->getSlug()) ->contactPoint(Schema::contactPoint()->areaServed('Worldwide')) ; } }
接下来,在您的布局底部添加 twig 函数 seo_schema_org()
。
该函数将格式化并显示当前实体根据您的定义的 JSON 模式。
<script type="application/ld+json"> { "@context": "https:\/\/schema.org", "@type": "MensClothingStore", "name": "Test", "email": "test@umanit.fr", "contactPoint": { "@type": "ContactPoint", "areaServed": "Worldwide" } } </script>
面包屑导航
您可以轻松地以 3 种不同的格式生成面包屑;Microdata
、RDFa
或 JSON-LD
,如 规范 所述。为此,umanit_seo.breadcrumbable
服务使用处理程序来处理实体。
处理程序是一个实现了 Umanit\SeoBundle\Handler\Breadcrumbable\BreadcrumbableHandlerInterface
的服务。一个 supports
方法表示服务是否可以处理给定的实体,一个 process
方法通过返回一个 Umanit\SeoBundle\Model\Breadcrumb
对象来完成工作。
Umanit\SeoBundle\Model\Breadcrumb
对象有一个 format
属性,它是前面提到的一个,以及一个 items
属性,它是一个包含 Umanit\SeoBundle\Model\BreadcrumbItem
的数组。每个 BreadcrumbItem
都有一个 label
属性和一个可选的 url
属性。
您必须在您的实体上实现接口 Umanit\SeoBundle\Model\BreadcrumbableModelInterface
并创建一个处理程序来处理它。
<?php declare(strict_types=1); namespace App\Entity; use Doctrine\ORM\Mapping as ORM; use Umanit\SeoBundle\Model\BreadcrumbableModelInterface; #[ORM\Entity] class Page implements BreadcrumbableModelInterface { // ... }
<?php declare(strict_types=1); namespace App\Seo\Breadcrumbable; use App\Entity\Page; use Umanit\SeoBundle\Handler\Breadcrumbable\BreadcrumbableHandlerInterface; use Umanit\SeoBundle\Model\Breadcrumb; use Umanit\SeoBundle\Model\BreadcrumbableModelInterface; use Umanit\SeoBundle\Model\BreadcrumbItem; class PageHandler implements BreadcrumbableHandlerInterface { public function supports(BreadcrumbableModelInterface $entity): bool { return $entity instanceof Page; } /** * @param Page $entity */ public function process(BreadcrumbableModelInterface $entity): Breadcrumb { $breadcrumb = new Breadcrumb(); $breadcrumb->setItems([ new BreadcrumbItem('Homepage', '/'), new BreadcrumbItem( $entity->getCategory()->getName(), $this->router->generate('app_page_category_show', ['slug' => $entity->getCategory()->getSlug()]) ), new BreadcrumbItem($entity->getName()), ]); return $breadcrumb; } }
注意:如果处理的实体实现了 RoutableModelInterface
,您可以省略 url
属性,让服务 umanit_seo.routable
为您生成它。
现在,您可以像以下示例一样使用 twig 函数 seo_breadcrumb()
{{ seo_breadcrumb() }} {# Will generate the breadcrumb from the current entity using microdata format #} {{ seo_breadcrumb(entity=my_entity, format='json-ld') }} {# Will generate the breadcrumb from my_entity using json-ld format #} {{ seo_breadcrumb(format='rdfa') }} {# Will generate the breadcrumb from the current entity using rdfa format #}
启用 301 重定向
为了在实体上启用 URL 历史记录和 301 重定向,请确保配置 umanit_seo.url_historization.enabled
是激活的(默认为 yes),然后实现接口 Umanit\SeoBundle\Model\HistorizableUrlModelInterface
并使用特质 Umanit\SeoBundle\Doctrine\Model\HistorizableUrlTrait
。
<?php declare(strict_types=1); namespace App\Entity; use Doctrine\ORM\Mapping as ORM; use Umanit\SeoBundle\Doctrine\Model\HistorizableUrlTrait; use Umanit\SeoBundle\Model\HistorizableUrlModelInterface; #[ORM\Entity] class Page implements HistorizableUrlModelInterface { use HistorizableUrlTrait; // ... }
Twig 函数参考
{{ path(entity, parameters = []) }} # Path to an Seo entity {{ url(entity, parameters = []) }} # Url to an Seo entity {{ seo_canonical(entity = null, parameters = []) }} # Canonical link of an Seo entity {{ seo_title(entity = null) }} # Title (without markup) of an Seo entity {{ seo_metadata(entity = null) }} # Metadata of an entity (title and description, with markup) {{ seo_schema_org(entity = null) }} # Json schema of an entity (with markup) {{ seo_breadcrumb(entity = null, format = null) }} # Breadcrumb from an entity (default format to 'microdata')
技巧
HistorizableUrlModelInterface
扩展了RoutableModelInterface
,因此您不需要实现两个接口,- 您可以通过覆盖
umanit_seo.url_historization.redirect_code
来使用自定义 HTTP 状态码进行重定向, - 您可以通过覆盖
umanit_seo.url_historization.cache_service
来使用自定义缓存服务为Umanit\SeoBundle\Doctrine\EventSubscriber\UrlHistoryWriter
, - 如果您的服务需要
@router
,您可以实现Umanit\SeoBundle\Service\RouterAwareInterface
并使用特质Umanit\SeoBundle\Service\RouterAwareTrait
(对面包屑处理程序很有用!)。