表单构建器插件
该插件允许你直接在 Admin Panel 中构建和管理自定义表单。无需每次需要新表单时都将其硬编码到网站或应用中,管理员可以即时定义每个所需表单的结构,而你的前端可以遍历这个结构,渲染自己的 UI 组件,并匹配你的品牌设计系统。
所有表单提交都会直接存储在你的数据库中,并可直接通过 Admin Panel 进行管理。当表单提交时,你可以向用户显示自定义的屏幕确认信息,或者将他们重定向到专门的确认页面。你甚至可以根据表单数据发送动态的个性化邮件。例如,你可能想向提交表单的用户发送确认邮件,同时也给你的团队发送通知邮件。
表单可以根据需要简单或复杂,从基本的联系表单,到多步骤的潜在客户生成引擎,甚至是处理付款的捐赠表单。你可能不需要为此使用 HubSpot 或 Mailchimp 等第三方服务,而是直接使用内置于你自己应用中的第一方工具。
核心功能
- 直接从管理面板构建完全动态的表单,适用于多种使用场景
- 使用自定义 UI 组件在前端渲染表单,匹配品牌设计系统
- 表单提交时发送动态个性化邮件给多个收件人,邮件内容基于表单数据生成
- 显示自定义确认消息或在表单提交后自动重定向
- 基于表单输入构建动态价格,用于支付处理(可选)
安装
使用任意 JavaScript 包管理器(如 pnpm、npm 或 Yarn)安装插件:
pnpm add @payloadcms/plugin-form-builder
基础用法
在 Payload 配置 的 plugins
数组中,调用插件并传入 选项:
import { buildConfig } from 'payload'
import { formBuilderPlugin } from '@payloadcms/plugin-form-builder'
const config = buildConfig({
collections: [
{
slug: 'pages',
fields: [],
},
],
plugins: [
formBuilderPlugin({
// 可用选项见下文
}),
],
})
export default config
选项
fields
(可选)
fields
属性是一个字段类型对象,允许管理员编辑者构建表单。要覆盖默认设置,可以传入布尔值或部分 Payload Block(以块的 slug 为键)。详情请参阅 字段。
// payload.config.ts
formBuilderPlugin({
// ...
fields: {
text: true,
textarea: true,
select: true,
email: true,
state: true,
country: true,
checkbox: true,
number: true,
message: true,
date: false,
payment: false,
},
})
redirectRelationships
redirectRelationships
属性是一个 collection slug 数组,启用后会在表单的 redirect
字段中作为选项填充。该字段用于在表单提交后将用户重定向到指定的确认页面(可选)。
// payload.config.ts
formBuilderPlugin({
// ...
redirectRelationships: ['pages'],
})
beforeEmail
beforeEmail
属性是一个 beforeChange 钩子,在邮件准备就绪后、发送前调用。这是注入自定义 HTML 模板以添加样式的理想位置。
// payload.config.ts
formBuilderPlugin({
// ...
beforeEmail: (emailsToSend, beforeChangeParams) => {
// 在邮件发送前以任何方式修改邮件
return emails.map((email) => ({
...email,
html: email.html, // 以任何你想要的方式转换 HTML(比如将其包装在 HTML 模板中?)
}))
},
})
要获取完整的 beforeChangeParams
类型,你可以从插件中导入类型:
import type { BeforeEmail } from '@payloadcms/plugin-form-builder'
// 你生成的 FormSubmission 类型
import type { FormSubmission } from '@payload-types'
// 传入后,'data' 或 'originalDoc' 将被类型化
const beforeEmail: BeforeEmail<FormSubmission> = (
emailsToSend,
beforeChangeParams,
) => {
// 在邮件发送前以任何方式修改邮件
return emails.map((email) => ({
...email,
html: email.html, // 以任何你想要的方式转换 HTML(比如将其包装在 HTML 模板中?)
}))
}
defaultToEmail
提供一个备用的电子邮件地址,用于接收表单提交。如果表单配置中没有设置收件人邮箱,将使用此邮箱地址。如果此处也未提供,则会回退到 email 配置 中的 defaultFromAddress
。
// payload.config.ts
formBuilderPlugin({
// ...
defaultToEmail: 'test@example.com',
})
formOverrides
通过向 formOverrides
属性传递一个 Payload Collection 配置,可以覆盖 forms
collection 的任何设置。
注意:fields
属性是一个接收默认字段并返回字段数组的函数。这是因为 fields
属性是一个特殊情况,它会与默认字段合并而不是替换它们。这允许你遍历默认字段并根据需要进行修改。
重要提示:默认情况下,表单 collection 是公开可读的。 电子邮件字段仅对已认证用户锁定。如果你有前端用户, 应该覆盖 collection 和电子邮件字段的访问权限, 以确保不会泄露任何私人电子邮件。
// payload.config.ts
formBuilderPlugin({
// ...
formOverrides: {
slug: 'contact-forms',
access: {
read: ({ req: { user } }) => !!user, // 仅限已认证用户
update: () => false,
},
fields: ({ defaultFields }) => {
return [
...defaultFields,
{
name: 'custom',
type: 'text',
},
]
},
},
})
formSubmissionOverrides
通过向 formSubmissionOverrides
属性传递一个 Payload Collection Config,可以覆盖 form-submissions
collection 的任何配置。
默认情况下,该插件依赖 Payload 访问控制来限制对 form-submissions
collection 的 update
和 read
操作。这是因为 任何人 都应该能够创建表单提交(即使是来自面向公众的网站),但 任何人 都不应该能够在提交创建后更新它,或者在没有权限的情况下读取提交。你可以根据需要覆盖此行为或任何其他属性。
// payload.config.ts
formBuilderPlugin({
// ...
formSubmissionOverrides: {
slug: 'leads',
fields: ({ defaultFields }) => {
return [
...defaultFields,
{
name: 'custom',
type: 'text',
},
]
},
},
})
handlePayment
handlePayment
属性是一个 beforeChange 钩子,在表单提交时被调用。你可以在这里集成任何第三方支付处理 API,根据表单输入接收付款。可以使用 getPaymentTotal
函数在所有条件应用后计算总费用。这仅在表单启用了 payment
字段时适用。
首先导入实用函数。这将执行你在表单 payment
字段中设置的所有价格条件,并返回总价格。
// payload.config.ts
import { getPaymentTotal } from '@payloadcms/plugin-form-builder'
然后在你的插件配置中:
// payload.config.ts
formBuilderPlugin({
// ...
handlePayment: async ({ form, submissionData }) => {
// 首先计算价格
const paymentField = form.fields?.find(
(field) => field.blockType === 'payment',
)
const price = getPaymentTotal({
basePrice: paymentField.basePrice,
priceConditions: paymentField.priceConditions,
fieldValues: submissionData,
})
// 然后在这里异步处理支付
},
})
字段
每个字段代表一个表单输入。要覆盖默认设置,可以传递布尔值或部分 Payload Block(以块的 slug 为键)。有关如何执行此操作的更多详细信息,请参阅字段覆盖。
注意: 这里的"Fields"指的是_用于构建表单的字段_,
不要与_集合的字段_混淆,后者是通过
formOverrides.fields
设置的。
文本字段
对应前端中的 text
输入框。用于收集简单的字符串。
Property | Type | Description |
---|---|---|
name | string | 字段名称 |
label | string | 字段标签 |
defaultValue | string | 字段默认值 |
width | string | 字段在前端的宽度 |
required | checkbox | 提交时是否为必填字段 |
文本区域
对应前端中的 textarea
输入框。用于收集多行文本。
Property | Type | Description |
---|---|---|
name | string | 字段名称 |
label | string | 字段标签 |
defaultValue | string | 字段默认值 |
width | string | 字段在前端的宽度 |
required | checkbox | 提交时是否为必填字段 |
Select(选择框)
在前端映射为 select
输入框。用于显示选项列表。
Property | Type | Description |
---|---|---|
name | string | 字段名称 |
label | string | 字段标签 |
defaultValue | string | 字段默认值 |
width | string | 在前端显示的字段宽度 |
required | checkbox | 提交时该字段是否为必填项 |
options | array | 包含 label 和 value 属性的对象数组 |
Email(邮箱字段)
在前端映射为类型为 email
的 text
输入框。用于收集电子邮件地址。
Property | Type | Description |
---|---|---|
name | string | 字段名称 |
label | string | 字段标签 |
defaultValue | string | 字段默认值 |
width | string | 在前端显示的字段宽度 |
required | checkbox | 提交时该字段是否为必填项 |
State
对应前端的一个 select
输入框。用于收集美国州名。
Property | Type | Description |
---|---|---|
name | string | 字段名称。 |
label | string | 字段标签。 |
defaultValue | string | 字段默认值。 |
width | string | 字段在前端的宽度。 |
required | checkbox | 提交时该字段是否为必填项。 |
Country
对应前端的一个 select
输入框。用于收集国家名称。
Property | Type | Description |
---|---|---|
name | string | 字段名称。 |
label | string | 字段标签。 |
defaultValue | string | 字段默认值。 |
width | string | 字段在前端的宽度。 |
required | checkbox | 提交时该字段是否为必填项。 |
复选框 (Checkbox)
对应前端 checkbox
输入类型。用于收集布尔值。
Property | Type | Description |
---|---|---|
name | string | 字段名称 |
label | string | 字段标签 |
defaultValue | checkbox | 字段默认值 |
width | string | 字段在前端的显示宽度 |
required | checkbox | 提交时是否为必填字段 |
日期 (Date)
对应前端 date
输入类型。用于收集日期值。
Property | Type | Description |
---|---|---|
name | string | 字段名称 |
label | string | 字段标签 |
defaultValue | date | 字段默认值 |
width | string | 字段在前端的显示宽度 |
required | checkbox | 提交时是否为必填字段 |
Number(数字)
在前端映射为 number
输入框。用于收集数字类型的数据。
属性 | 类型 | 描述 |
---|---|---|
name | string | 字段名称 |
label | string | 字段标签 |
defaultValue | number | 字段的默认值 |
width | string | 字段在前端的显示宽度 |
required | checkbox | 提交时该字段是否为必填项 |
Message(消息)
在前端映射为 RichText
组件。用于在表单任意位置向用户显示自定义消息。
属性 | 类型 | 描述 |
---|---|---|
message | richText | 要在表单上显示的消息内容 |
支付
如果表单需要收集支付信息,可以添加此字段。提交时,系统会执行 handlePayment
回调函数,传入表单和提交数据。你可以利用这个回调来集成任何第三方支付处理 API。
属性 | 类型 | 描述 |
---|---|---|
name | string | 字段名称 |
label | string | 字段标签 |
defaultValue | number | 字段默认值 |
width | string | 字段在前端的显示宽度 |
required | checkbox | 提交时该字段是否为必填项 |
priceConditions | array | 定义价格条件的对象数组。详见下文获取更多细节。 |
价格条件
每个 priceConditions
都会由该插件提供的 getPaymentTotal
工具函数执行。你可以在 handlePayment
回调中调用此函数,根据用户输入动态计算表单提交时的总价。例如,你可以创建一个价格条件:"如果用户对此复选框选择'是',则在总价上增加 10 美元"。
property | type | description |
---|---|---|
fieldToUse | relationship | 用于确定价格的字段。 |
condition | string | 用于确定价格的条件。 |
valueForOperator | string | 用于运算符的值。 |
operator | string | 用于确定价格的运算符。 |
valueType | string | 用于确定价格的值类型。 |
value | string | 用于确定价格的值。 |
字段覆盖
你可以通过传入一个新的 Payload Block 对象到 fields
中,来提供自定义字段。你可以通过首先从插件导入 fields
来覆盖或扩展任何现有字段:
import { fields } from '@payloadcms/plugin-form-builder'
然后将其合并到你自己的自定义字段中:
// payload.config.ts
formBuilderPlugin({
// ...
fields: {
text: {
...fields.text,
labels: {
singular: '自定义文本字段',
plural: '自定义文本字段',
},
},
},
})
自定义日期字段默认值
你可以通过以下方式自定义日期字段的默认值以及日期块的其他方面。请注意,最终提交来源将负责处理日期的时区。Payload 仅以 UTC 格式存储日期。
import { fields as formFields } from '@payloadcms/plugin-form-builder'
// payload.config.ts
formBuilderPlugin({
fields: {
// date: true, // 不进行任何自定义,直接启用
date: {
...formFields.date,
fields: [
...(formFields.date && 'fields' in formFields.date
? formFields.date.fields.map((field) => {
if ('name' in field && field.name === 'defaultValue') {
return {
...field,
timezone: true, // 可选启用时区
admin: {
...field.admin,
description: '这是一个日期字段',
},
}
}
return field
})
: []),
],
},
},
})
电子邮件
该插件依赖于你在 Payload 配置中定义的 email 配置。它会读取你的配置并尝试使用提供的凭据发送电子邮件。
电子邮件格式
邮件内容支持富文本,这些内容会在服务器端被序列化为 HTML 后再发送。默认情况下,它会读取你富文本编辑器的全局配置。
邮件主题和正文支持使用 {{字段名}}
语法插入来自表单提交数据的动态字段。例如,如果你的表单中有一个名为 name
的字段,你可以像这样将其包含在邮件正文中:
感谢你的提交,{{name}}!
你还可以使用 {{*}}
作为通配符以键值格式输出所有数据,或使用 {{*:table}}
以表格格式输出所有数据。
TypeScript
所有类型都可以直接导入:
import type {
PluginConfig,
Form,
FormSubmission,
FieldsConfig,
BeforeEmail,
HandlePayment,
...
} from "@payloadcms/plugin-form-builder/types";
示例
示例目录中包含一个官方的表单构建插件示例,该示例展示了如何在 Payload 中配置此插件并在前端实现它。我们还在表单构建插件博客文章中详细介绍了如何从头开始构建表单。
故障排除
以下是一些常见的故障排除提示。为了帮助其他开发者,请在解决自己的应用问题时贡献到本节。
SendGrid 403 禁止访问错误
- 如果你使用 SendGrid 链接品牌来移除电子邮件中的"via sendgrid.net"部分,则还必须设置域名认证。这意味着你只能从该域名下的地址发送电子邮件——因此表单提交邮件中的
from
地址不能是除something@your_domain.com
之外的任何内容。这意味着{{email}}
将不起作用,但website@your_domain.com
可以。你仍然可以在邮件正文中发送表单的电子邮件地址。