SEO 插件

从 Payload 管理后台管理 SEO 元数据

https://www.npmjs.com/package/@payloadcms/plugin-seo

该插件允许你直接从 Admin Panel 中轻松管理应用的 SEO 元数据。当在 CollectionsGlobals 上启用后,默认会添加一个包含 titledescriptionimage 的新 meta 字段组。你的前端应用可以使用这些数据来渲染所需的 meta 标签。例如,你可以使用 meta.title 作为内容,将 title 标签注入页面的 <head> 中。

当用户在 Admin Panel 中编辑文档时,他们可以选择"自动生成"这些字段。点击后,该插件会执行你自定义的函数来重新生成标题、描述和图片。这样你就可以直接在应用中构建自己的 SEO 写作辅助功能。例如,你可以在页面标题后附加网站名称,或使用文档的摘要字段作为描述,甚至可以通过集成第三方 API 使用 AI 生成图片。

为了帮助你预览页面在搜索引擎中的显示效果,页面上的 meta 字段下方会实时渲染预览。随着你编辑元数据,这个预览也会实时更新。还有一些视觉提示可以帮助你编写有效的元数据,比如标题和描述字段的字符计数器。你还可以根据应用需求,向 meta 字段组中注入自定义字段,如 og:titlejson-ld。如果你使用过类似 Yoast SEO 的工具,这个插件会让你感到非常熟悉。

该插件完全开源,源代码可在此处查看。如需帮助,请查阅我们的社区帮助。如果发现 bug,请提交新 issue,并尽可能提供详细信息。

核心功能

  • 为每个启用 SEO 的 collection 或 global 添加 meta 字段组
  • 允许定义自定义函数来自动生成元数据
  • 显示提示和指标,帮助内容编辑编写有效的元数据
  • 渲染搜索引擎可能显示的预览片段
  • 可扩展,可以定义自定义字段如 og:titlejson-ld
  • 即将支持动态变量注入

安装

使用任意 JavaScript 包管理器(如 pnpmnpmYarn)安装插件:

  pnpm add @payloadcms/plugin-seo

基础用法

Payload Configplugins 数组中,调用插件并传入 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" 开头的函数都会接收以下参数:

ArgumentDescription
collectionConfig集合的配置。
collectionSlug集合的 slug。
doc当前文档的数据。
docPermissions文档的权限。
globalConfig全局的配置。
globalSlug全局的 slug。
hasPublishPermission用户是否有发布文档的权限。
hasSavePermission用户是否有保存文档的权限。
id文档的 ID。
initialData文档的初始数据。
initialState文档的初始状态。
locale文档的语言环境。
preferencesKey文档的首选项键。
publishedDoc已发布的文档。
reqPayload 请求对象,包含 userpayloadi18n 等。
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,你可以使用 titleOverridesdescriptionOverrides 来覆盖长度规则。

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 TemplateE-commerce Template,这些模板展示了如何在 Payload 中配置此插件以及如何在前端实现它。

截图

image