lensmedia / symfony-seo
一些可复用的SEO内容的“私有”包。
dev-main
2024-06-03 15:31 UTC
Requires
- php: >=8.2
- spatie/schema-org: ^3.23
- symfony/framework-bundle: ^7.0
- symfony/translation: ^7.0
- symfony/twig-bundle: ^7.0
Requires (Dev)
- symfony/profiler-pack: ^1.0
This package is auto-updated.
Last update: 2024-09-03 15:59:31 UTC
README
为Symfony项目提供的简单可复用SEO工具。
元数据
属性
use Lens\Bundle\SeoBundle\Attribute\Meta; class Index extends AbstractController { #[Route([ 'nl' => null, 'en' => '/en', ], name: 'homepage')] #[Meta('nl', 'Hoi wereld!', keywords: ['lens', 'zmo', 'bundel'])] #[Meta('en', 'Hello world!', keywords: ['lens', 'seo', 'bundle'])] public function __invoke(): Response { return $this->render('homepage.html.twig'); } }
在twig中使用
Twig/MetaExtension
向twig上下文添加了一个全局变量lens_seo_meta
(可以更改,见配置),然后可以使用它
<title>{{ title ?? lens_seo_meta.title ?? 'meta.title'|trans }}</title> {% set title = lens_seo_meta.title ?? title ?? 'meta.title'|trans %} {% set description = lens_seo_meta.description ?? description ?? 'meta.description'|trans %} {% if lens_seo_meta is defined and lens_seo_meta is not empty %} <meta name="title" content="{{ title }}"> <meta name="description" content="{{ description }}"> {% if (keywords ?? lens_seo_meta.keywords)|length %} <meta name="keywords" content="{{ (keywords ?? lens_seo_meta.keywords)|join(', ') }}"> {% endif %} {% endif %}
元数据解析器
元数据解析器允许完全控制元标签,主要用于动态路由。
#[Route(name: 'faq')] #[Meta(resolver: FaqResolver::class)] public function __invoke(): Response { ...
namespace App\Seo\Meta; use Lens\Bundle\SeoBundle\Attribute\Meta; use Lens\Bundle\SeoBundle\MetaResolverInterface; use Symfony\Component\HttpFoundation\Request; class FaqResolver implements MetaResolverInterface { public function resolveMeta(Request $request, Meta $meta): void { // This works well if you have an entity value resolver, otherwise you // can use the value and use dependency injection to get the entity. $faq = $request->attributes->get('faq'); $meta->title = $faq->metaTitle ?? $faq->question; $meta->description = $faq->metaDescription; }
面包屑
添加面包屑的属性
use Lens\Bundle\SeoBundle\Attribute\Breadcrumb; class Index extends AbstractController { #[Route(name: 'homepage_route_name')] #[Breadcrumb([ 'nl' => 'homepagina', 'en' => 'homepage', ])] public function __invoke(): Response { return $this->render('homepage.html.twig'); } }
class Faq extends AbstractController { #[Route(name: 'faq_route_name')] #[Breadcrumb([ 'nl' => 'veel gestelde vragen', 'en' => 'frequently asked questions', ], parent: 'homepage_route_name')] public function __invoke(): Response { return $this->render('faq.html.twig'); } }
在twig中使用
Twig/BreadcrumbExtension
向twig上下文添加了一个全局变量lens_seo_breadcrumbs
(可以更改,见配置),然后可以使用它
{% if lens_seo_breadcrumbs is defined and lens_seo_breadcrumbs is not empty %} <ol class="breadcrumbs"> {% for breadcrumb in lens_seo_breadcrumbs %} {% if loop.last %} <li class="breadcrumb-item active">{{ breadcrumb.title }}</li> {% else %} <li class="breadcrumb-item"> <a href="{{ path(breadcrumb.routeName, breadcrumb.routeParameters) }}">{{ breadcrumb.title }}</a> </li> {% endif %} {% endfor %} </ol> {% endif %}
面包屑解析器
面包屑解析器允许在面包屑具有动态值时进行完全控制。
#[Route(name: 'faq')] #[Meta(resolver: FaqResolver::class)] public function __invoke(): Response { ...
namespace App\Seo\Meta; use Lens\Bundle\SeoBundle\Attribute\Breadcrumb; use Lens\Bundle\SeoBundle\BreadcrumbResolverInterface; use Symfony\Component\HttpFoundation\Request; class FaqResolver implements BreadcrumbResolverInterface { public function resolveMeta(Request $request, Breadcrumb $breadcrumb): void { $faq = $request->attributes->get('faq'); $breadcrumb->title = $faq->question ?? $request->attributes->get('uri'); $breadcrumb->routeParameters['uri'] = $request->attributes->get('uri'); $breadcrumb->routeParameters['_locale'] = $request->getLocale(); }
结构化数据
提供类,帮助使用spatie/schema-org设置结构化数据。
<?php use Spatie\SchemaOrg\Schema; use Lens\Bundle\SeoBundle\StructuredData\StructuredDataBuilder; class Index extends AbstractController { #[Route(name: 'homepage')] public function __invoke(StructuredDataBuilder $structuredData): Response { $url = rtrim($this->generateUrl('homepage_route_name', [], UrlGeneratorInterface::ABSOLUTE_URL), '/'); $address = Schema::postalAddress() ->streetAddress('Energiestraat 5') ->addressLocality('Hattem') ->postalCode('8051TE') ->addressCountry('NL'); return Schema::organization() ->name('LENS Verkeersleermiddelen') ->address($address) ->url($url) ->sameAs($url); // Usually you would do the organization in a listener, so it works on all requests. $structuredData->addSchema($organization); return $this->render('homepage.html.twig'); } }
您也可以创建一个工厂服务以实现可复用性,如下所示
class Organization implements StructuredDataInterface { public function __construct( private UrlGeneratorInterface $urlGenerator, ) { } public function __invoke(array $context = []): \Spatie\SchemaOrg\Organization { $url = rtrim($this->urlGenerator->generate('web_common_index', [], UrlGeneratorInterface::ABSOLUTE_URL), '/'); $address = Schema::postalAddress() ->streetAddress('Energiestraat 5') ->addressLocality('Hattem') ->postalCode('8051TE') ->addressCountry('NL'); return Schema::organization() ->name('LENS Verkeersleermiddelen') ->address($address) ->url($url) ->sameAs($url); } }
这反过来又改变了控制器为
class Index extends AbstractController { #[Route(name: 'homepage')] public function __invoke(StructuredDataBuilder $structuredData, Organization $organization): Response { $structuredData->addSchema($organization); return $this->render('homepage.html.twig'); } }
可调用的方法将自动被调用(但如果你这样做也没关系)。
将结构化数据添加到响应中
Event/AppendStructuredDataToResponse
监听器将在存在时自动将结构化数据添加到响应中,就在关闭body标签之前。如果出于某种原因你需要不同的用例,你可以使用StructuredDataBuilder
服务的toArray
/toScript
函数来做你的事情。
手动添加额外的结构化数据
您可以使用StructuredDataBuilder
服务从几乎任何地方添加额外的结构化数据到响应中。例如,将服务暴露给twig,您可以直接这样做
{% do lens_seo_structured_data.addFromArray({ foo: 'bar' }) %}
$structeredData->addFromString('{"foo":"bar"}');
配置
以下是默认可用的配置选项。
lens_seo: structured_data: json_encode_options: 320 # int bitmask, see https://php.ac.cn/manual/en/function.json-encode.php unescaped slashes (64) & unescaped unicode (256) twig: globals: prefix: 'lens_seo_' # prefix for the global variable names listed below, null to disable meta: enabled: true # enables the global variable name: 'meta' # name of the global variable breadcrumbs: enabled: true name: 'breadcrumbs' structured_data: enabled: true name: 'structured_data'
我们当前的常用示例配置
lens_seo: twig: globals: # removes all prefixes allows direct access to: meta, breadcrumbs and structuredData. prefix: ~ structured_data: # looks prettier when using e.g.: structuredData.addFromArray. We do not use snake # case anymore, and the other functions are already one word. name: 'structuredData' when@dev: lens_seo: structured_data: json_encode_options: 448 # Adds pretty print (128) in dev