SEO 插件
从 Payload 管理后台管理 SEO 元数据
该插件允许你直接从 Admin Panel 中轻松管理应用的 SEO 元数据。当在 Collections 和 Globals 上启用后,默认会添加一个包含 title
、description
和 image
的新 meta
字段组。你的前端应用可以使用这些数据来渲染所需的 meta 标签。例如,你可以使用 meta.title
作为内容,将 title
标签注入页面的 <head>
中。
当用户在 Admin Panel 中编辑文档时,他们可以选择"自动生成"这些字段。点击后,该插件会执行你自定义的函数来重新生成标题、描述和图片。这样你就可以直接在应用中构建自己的 SEO 写作辅助功能。例如,你可以在页面标题后附加网站名称,或使用文档的摘要字段作为描述,甚至可以通过集成第三方 API 使用 AI 生成图片。
为了帮助你预览页面在搜索引擎中的显示效果,页面上的 meta 字段下方会实时渲染预览。随着你编辑元数据,这个预览也会实时更新。还有一些视觉提示可以帮助你编写有效的元数据,比如标题和描述字段的字符计数器。你还可以根据应用需求,向 meta
字段组中注入自定义字段,如 og:title
或 json-ld
。如果你使用过类似 Yoast SEO 的工具,这个插件会让你感到非常熟悉。
核心功能
- 为每个启用 SEO 的 collection 或 global 添加
meta
字段组 - 允许定义自定义函数来自动生成元数据
- 显示提示和指标,帮助内容编辑编写有效的元数据
- 渲染搜索引擎可能显示的预览片段
- 可扩展,可以定义自定义字段如
og:title
或json-ld
- 即将支持动态变量注入
安装
使用任意 JavaScript 包管理器(如 pnpm、npm 或 Yarn)安装插件:
pnpm add @payloadcms/plugin-seo
基础用法
在 Payload Config 的 plugins
数组中,调用插件并传入 options:
import { buildConfig } from 'payload';
import { seoPlugin } from '@payloadcms/plugin-seo';
const config = buildConfig({
collections: [
{
slug: 'pages',
fields: []
},
{
slug: 'media',
upload: {
staticDir: // 静态目录路径,
},
fields: []
}
],
plugins: [
seoPlugin({
collections: [
'pages',
],
uploadsCollection: 'media',
generateTitle: ({ doc }) => `Website.com — ${doc.title}`,
generateDescription: ({ doc }) => doc.excerpt
})
]
});
export default config;
选项
collections
一个数组,包含要启用 SEO 的 collection slug。启用的 collection 会获得一个 meta
字段,该字段是一个包含 title、description 和 image 子字段的对象。
globals
一个数组,包含要启用 SEO 的 global slug。启用的 global 会获得一个 meta
字段,该字段是一个包含 title、description 和 image 子字段的对象。
fields
一个接收默认字段对象并返回字段数组的函数。你可以使用这个函数来修改现有字段或添加新字段。
// payload.config.ts
{
// ...
seoPlugin({
fields: ({ defaultFields }) => [
...defaultFields,
{
name: 'customField',
type: 'text',
},
],
})
}
uploadsCollection
将 uploadsCollection
设置为你的应用中启用了上传功能的 collection slug。这用于在 meta
字段组中提供一个 image
字段。
tabbedUI
当 tabbedUI
属性为 true
时,它会使用 Payload 的 Tabs Field 在你的配置中添加一个 SEO
标签页。如果你的 collection 尚未启用标签页(即配置中的第一个字段不是 tabs
类型),则会自动创建一个名为 Content
的标签页。默认值为 false
。
请注意,插件或字段在配置中的顺序可能会影响插件是否能智能地将标签页与现有字段合并。如果你的结构比较复杂,我们建议你直接使用字段而不是依赖此配置选项。
如果你想在使用 tabbedUI
的同时继续使用顶层或侧边栏字段,
必须避免让默认的 Content
标签页自动创建(参见上面的说明)。
相反,你应该将配置的第一个字段定义为 tabs
类型,
并将所有其他字段放置在这个字段旁边。
generateTitle
一个允许你返回任意元标题的函数,包括从文档内容中生成的标题。
// payload.config.ts
{
// ...
seoPlugin({
generateTitle: ({ doc }) => `Website.com — ${doc?.title}`,
})
}
所有 "generate" 开头的函数都会接收以下参数:
Argument | Description |
---|---|
collectionConfig | 集合的配置。 |
collectionSlug | 集合的 slug。 |
doc | 当前文档的数据。 |
docPermissions | 文档的权限。 |
globalConfig | 全局的配置。 |
globalSlug | 全局的 slug。 |
hasPublishPermission | 用户是否有发布文档的权限。 |
hasSavePermission | 用户是否有保存文档的权限。 |
id | 文档的 ID。 |
initialData | 文档的初始数据。 |
initialState | 文档的初始状态。 |
locale | 文档的语言环境。 |
preferencesKey | 文档的首选项键。 |
publishedDoc | 已发布的文档。 |
req | Payload 请求对象,包含 user 、payload 、i18n 等。 |
title | 文档的标题。 |
versionsCount | 文档的版本数量。 |
generateDescription
一个允许你返回任意元描述的函数,可以从文档内容中提取。
// payload.config.ts
{
// ...
seoPlugin({
generateDescription: ({ doc }) => doc?.excerpt,
})
}
完整参数列表请参见 generateTitle
函数。
generateImage
一个允许你返回任意元图片的函数,可以从文档内容中提取。
// payload.config.ts
{
// ...
seoPlugin({
generateImage: ({ doc }) => doc?.featuredImage,
})
}
完整参数列表请参见 generateTitle
函数。
generateURL
搜索预览组件调用的函数,用于显示页面的实际 URL。
// payload.config.ts
{
// ...
seoPlugin({
generateURL: ({ doc, collectionSlug }) =>
`https://yoursite.com/${collectionSlug}/${doc?.slug}`,
})
}
完整参数列表请参见 generateTitle
函数。
interfaceName
重命名为 TypeScript 和 GraphQL 生成的元组接口名称。
// payload.config.ts
{
// ...
seoPlugin({
interfaceName: 'customInterfaceNameSEO',
})
}
直接使用字段
你可以选择直接从插件中导入任何字段,以便根据需要将它们包含在任何地方。
你仍然需要在 Payload Config 中配置插件以设置生成函数。由于这些字段是直接导入和使用的,它们无法访问插件配置,因此可能需要额外的参数才能以相同方式工作。
import {
MetaDescriptionField,
MetaImageField,
MetaTitleField,
OverviewField,
PreviewField,
} from '@payloadcms/plugin-seo/fields'
// 作为字段使用
MetaImageField({
// 上传集合的 slug
relationTo: 'media',
// 如果配置了 `generateImage` 函数
hasGenerateFn: true,
})
MetaDescriptionField({
// 如果配置了 `generateDescription` 函数
hasGenerateFn: true,
})
MetaTitleField({
// 如果配置了 `generateTitle` 函数
hasGenerateFn: true,
})
PreviewField({
// 如果配置了 `generateUrl` 函数
hasGenerateFn: true,
// 字段路径以匹配目标数据字段
titlePath: 'meta.title',
descriptionPath: 'meta.description',
})
OverviewField({
// 字段路径以匹配目标数据字段
titlePath: 'meta.title',
descriptionPath: 'meta.description',
imagePath: 'meta.image',
})
提示:你可以通过更改字段上的 minLength 和 maxLength 属性来覆盖长度规则。对于 OverviewField,你可以使用 titleOverrides
和 descriptionOverrides
来覆盖长度规则。
TypeScript
所有类型都可以直接导入:
import type {
PluginConfig,
GenerateTitle,
GenerateDescription
GenerateURL
} from '@payloadcms/plugin-seo/types';
然后你可以将生成的 Payload 类型中的 collections 传递给生成类型,例如:
import type { Page } from './payload-types.ts'
import type { GenerateTitle } from '@payloadcms/plugin-seo/types'
const generateTitle: GenerateTitle<Page> = async ({ doc, locale }) => {
return `Website.com — ${doc?.title}`
}
示例
Templates Directory 包含官方的 Website Template 和 E-commerce Template,这些模板展示了如何在 Payload 中配置此插件以及如何在前端实现它。