xpertbot / craft-wheelform
Craft CMS 5 表单管理员,数据库集成
Requires
- craftcms/cms: ^5.0
Requires (Dev)
- craftcms/phpstan: dev-main
- craftcms/rector: dev-main
- dev-master
- 4.0.2
- 4.0.1
- 4.0.0
- 3.2.1
- 3.2.0
- 3.1.8
- 3.1.7
- 3.1.6
- 3.1.5
- 3.1.4
- 3.1.3
- 3.1.2
- 3.1.1
- 3.1.0
- 3.0.2
- 3.0.1
- 3.0.0
- 2.7.3
- 2.7.2
- 2.7.1
- 2.7.0
- 2.6.4
- 2.6.3
- 2.6.2
- 2.6.1
- 2.6.0
- 2.5.8
- 2.5.7
- 2.5.6
- 2.5.5
- 2.5.4
- 2.5.3
- 2.5.2
- 2.5.1
- 2.5.0
- 2.4.3
- 2.4.2
- 2.4.1
- 2.4.0
- 2.3.9
- 2.3.8
- 2.3.7
- 2.3.6
- 2.3.5
- 2.3.4
- 2.3.3
- 2.3.2
- 2.3.1
- 2.3.0
- 2.2.4
- 2.2.3
- 2.2.2
- 2.2.1
- 2.2.0
- 2.1.1
- 2.1.0
- 2.0.2
- 2.0.1
- 2.0.0
- 1.25.3
- 1.25.2
- 1.25.1
- 1.25.0
- 1.24.1
- 1.24.0
- 1.23.0
- 1.22.0
- 1.21.1
- 1.21.0
- 1.20.4
- 1.20.3
- 1.20.2
- 1.20.1
- 1.20.0
- 1.19.0
- 1.18.0
- 1.17.1
- 1.17.0
- 1.16.4
- 1.16.3
- 1.16.2
- 1.16.1
- 1.16.0
- 1.15.1
- 1.15.0
- 1.14.3
- 1.14.2
- 1.14.1
- 1.14.0
- 1.13.1
- 1.13.0
- 1.12.0
- 1.11.0
- 1.10.2
- 1.10.1
- 1.10.0
- 1.9.0
- 1.8.0
- 1.7.5
- 1.7.4
- 1.7.3
- 1.7.2
- 1.7.1
- 1.6.9
- 1.6.8
- 1.6.7
- 1.6.6
- 1.6.5
- 1.6.4
- 1.6.3
- 1.6.2
- 1.6.1
- 1.6.0
- 1.5.0
- 1.4.4
- 1.3.0
- 1.2.0
- 1.1.0
- 1.0.1
- dev-dependabot/npm_and_yarn/webpack-5.94.0
- dev-dev
- dev-craft4
- dev-craft3
This package is auto-updated.
Last update: 2024-08-29 16:13:17 UTC
README
具有数据库集成的免费表单构建工具,是 Straight Up Craft 上免费联系表单插件的后继产品
Craft CMS 4.x
使用 composer require xpertbot/craft-wheelform "^3.2"
Craft CMS 3.x
使用 composer require xpertbot/craft-wheelform "^2.7"
要求
此插件需要 Craft CMS 5.0.0 或更高版本
安装
要安装此插件,请按照以下说明操作。
-
打开您的终端并转到您的 Craft 项目
cd /path/to/project -
然后告诉 Composer 加载插件
composer require xpertbot/craft-wheelform -
在控制面板中,转到设置 → 插件,并为 Wheel Form 点击“安装”按钮。
功能
- reCaptcha 验证
- 导出 CSV 文件
- 自定义电子邮件 HTML 模板
- 模板变量,便于开发
- 基于所选字段类型的电子邮件验证
- 表单字段类型用于部分
- 必填字段
- 复选框选项
- 文件扩展名限制
- 蜜罐字段
- Ajax 和重定向友好
- 将表单提交发送到多个电子邮件地址
- 每个表单的高级权限
- 字段重新排序
- 将上传的文件保存到资产管理器
- 多语言
- 在不同网站之间导出/导入字段
- 动态电子邮件通知
用法
安装成功后,转到插件设置并添加您希望表单发送的电子邮件 FROM。还可以设置其他有用的设置。
表单在表单面板的主设置中进行管理。设置此表单应提交到 TO 以及表单的名称。
字段设置可以设置为必填或非必填,用于验证目的。
当前支持的字段类型有
- 文本
- 多行文本
- 电子邮件
- 数字
- 复选框
- 单选按钮
- 下拉列表
- 隐藏
- 文件
- 列表
- HTML
模板变量
-
wheelform
- 设置
- 表单
- recaptcha
- open()
- close()
- 字段
- 类型
- 名称
- 标签
- 项
- 字段类
- 容器类
- 必填
- 排序
- 值
- 选项
- 显示标签
- 条目
- id
- 表单id
- 字段
- 名称
- 标签
- 值
- 类型
- 日期
- getErrors()
- 最后提交
- id
- 表单id
- 字段
- 名称
- 标签
- 值
- 类型
-
wheelformErrors (基于字段名、表单、reCaptcha、蜜罐的错误数组)
-
values (基于字段名的用户提交值数组)
表单配置选项
这些是可以传递给 wheelform.form 以配置您的表单的配置选项。
id: 必需 正在使用的表单的 ID。redirect: 表单提交成功后将重定向到的 URL。registerScripts: 布尔值,用于在wheelform.open调用之前加载脚本(这对于缓存表单和模板很有用)。默认为 False。refreshCsrf:布尔值,用于加载JavaScript以刷新当前页面的表单的CSRF令牌(这对于缓存表单和模板很有用)。为了使此功能正常工作,需要将form.open()放在{% cache %}块之外。submitForm:提交按钮的配置选项。示例
{# SubmitButton options: "type" can be button, or input "html" attribute takes precedence over the other properties, "attributes" is an easy way to add attributes to the button, all attributes are optional #} submitButton: { "type": "button", "label": "Send", // Text displayed for the button "attributes": { // Array of attributes for the Button. Same as Form "class": "btn btn-success", "id": "submit-btn", "data-submit": "Foo", }, "html": "<span><button>Custom Button</button></span>", // Custom HTML Overwrittes any other options and will render it as final. }
Form.open()参数选项
action:字符串,用于覆盖表单提交的位置。如果需要使用JavaScript覆盖它,这很有用。默认为空字符串。attributes:{键:值}数组,表示当前表单的属性。默认为空数组。注意:表单属性会覆盖默认值。示例
{# - Special Attribute: `csrf`: {boolean}, enables/disables csrf token field, disable if you would like to implement your own csrf token generation. Example: {{ form.open('', { 'csrf': false, }) }} {{ craft.blitz.csrfInput() }} ... Rest of form template ... #}
method:字符串,用于覆盖表单HTML的method属性。默认为"POST"。
{{ form.open("", {
'novalidate': 'novalidate',
'id':'custom-form',
'class': 'custom-form',
}, "POST") }}
字段服务选项
getFileExtensions:如果当前字段类型为"文件",可以检索在该字段上设置的当前"文件扩展名限制"。
动态电子邮件通知
- “电子邮件主题”、“提交消息”、“用户通知主题”和“用户通知消息”表单设置可以使用动态字段值,通过在方括号中引用字段“名称”。例如,“您收到来自
[email]的表单提交”其中email是您表单中字段的name。
模板结构
您的表单模板可能看起来像这样
{% macro errorList(errors) %}
{% if errors %}
<ul class="errors">
{% for error in errors %}
<li>{{ error }}</li>
{% endfor %}
</ul>
{% endif %}
{% endmacro %}
{% from _self import errorList %}
{% set form = wheelform.form({
id: 1,
redirect: 'contact/thanks'
}) %}
{{ form.open() }}
{{ wheelformErrors['form'] is defined ? errorList(wheelformErrors['form']) }}
{{ wheelformErrors['recaptcha'] is defined ? errorList(wheelformErrors['recaptcha']) }}
{{ wheelformErrors['honeypot'] is defined ? errorList(wheelformErrors['honeypot']) }}
{% for field in form.fields %}
{{ field.render() }}
{{ wheelformErrors[field.name] is defined ? errorList(wheelformErrors[field.name]) }}
{% endfor %}
{{ form.close() }}
高级模板
{% macro errorList(errors) %}
{% if errors %}
<ul class="errors">
{% for error in errors %}
<li>{{ error }}</li>
{% endfor %}
</ul>
{% endif %}
{% endmacro %}
{% from _self import errorList %}
{% set form = wheelform.form({
id: 1,
redirect: 'contact/thanks',
}) %}
{{ form.open() }}
{{ wheelformErrors['form'] is defined ? errorList(wheelformErrors['form']) }}
{{ wheelformErrors['recaptcha'] is defined ? errorList(wheelformErrors['recaptcha']) }}
{{ wheelformErrors['honeypot'] is defined ? errorList(wheelformErrors['honeypot']) }}
{% for field in form.fields %}
{% switch field.type %}
{% case "checkbox" %}
<div class="form-checkbox">
{% for item in field.items %}
<label><input class="checkbox" type="checkbox" value="{{ item }}" {{values[field.name] is defined and item in values[field.name] ? ' checked="checked"' : '' }} name="{{field.name}}[]" id=""/>{{item}}</label>
{% endfor %}
</div>
{% case "radio" %}
<div class="form-radio">
{% for item in field.items %}
<input class="radio" type="radio" value="{{ item }}" {{values[field.name] is defined and item == values[field.name] ? ' checked="checked"' : '' }} name="{{field.name}}" id=""/>
<label>{{item}}</label>
{% endfor %}
</div>
{% case "select" %}
<div class="form-select">
<select id="wf-select" name="{{field.name}}" class="wf-field {{field.fieldClass}}">
{% for item in field.items %}
<option value="{{ item }}" {{values[field.name] is defined and item == values[field.name] ? 'selected="selected"' : '' }}>{{item}}</option>
{% endfor %}
</select>
</div>
{% case "file" %}
<div class="form-group">
<label>{{field.label}}</label>
<input type="file" name="{{field.name}}" id=""/>
</div>
{% case "textarea" %}
<div class="form-group">
<label>{{field.label}}</label>
<textarea class="form-control" name="{{field.name}}" id="">{{ values[field.name] ?? '' }}</textarea>
</div>
{% case "list" %}
<div class="form-group">
<label>{{field.label}}</label>
<input type="text" name="{{field.name}}[]" id=""/>
<script>//Javascript to handle adding fields</script>
</div>
{% default %}
<div class="form-group">
<label>{{field.label}}</label>
<input class="form-control" type="{{field.type}}" value="{{ values[field.name] ?? '' }}" name="{{field.name}}" id=""/>
</div>
{% endswitch %}
{{ wheelformErrors[field.name] is defined ? errorList(wheelformErrors[field.name]) }}
{% endfor %}
{% if form.recaptcha %}
<div>
<script src="https://www.google.com/recaptcha/api.js"></script>
<!-- Production captcha -->
<div class="g-recaptcha" data-sitekey="{{wheelform.getSettings('recaptcha_public')}}"></div>
</div>
{% endif %}
<button class="btn btn-success" id="submit">Send</button>
</form>
如果您想坚持使用HTML而不使用变量
{% macro errorList(errors) %}
{% if errors %}
<ul class="errors">
{% for error in errors %}
<li>{{ error }}</li>
{% endfor %}
</ul>
{% endif %}
{% endmacro %}
{% from _self import errorList %}
{{ wheelformErrors['form'] is defined ? errorList(wheelformErrors['form']) }}
<form method="post" action="" accept-charset="UTF-8" novalidate="" enctype="multipart/form-data">
{{ csrfInput() }}
<input type="hidden" name="action" value="wheelform/message/send">
<input type="hidden" name="form_id" value="1">
<input type="hidden" name="redirect" value="{{ 'contact/thanks'|hash }}">
<h3><label for="from-name">Your Name</label></h3>
<input id="from-name" type="text" name="name" value="{{ values['name'] ?? '' }}">
{{ wheelformErrors['name'] is defined ? errorList(wheelformErrors['name']) }}
<h3><label for="from-email">Your Email</label></h3>
<input id="from-email" type="email" name="email" value="{{ values['email'] ?? '' }}">
{{ wheelformErrors['email'] is defined ? errorList(wheelformErrors['email']) }}
<h3><label for="phone">Phone</label></h3>
<input id="phone" type="text" name="phone" value="{{ values['phone'] ?? '' }}">
{{ wheelformErrors['phone'] is defined ? errorList(wheelformErrors['phone']) }}
<label><input type="checkbox" name="favorite_topping[]" value="Chocolate">Chocolate</label>
<label><input type="checkbox" name="favorite_topping[]" value="Vanilla">Vanilla</label>
<label><input type="checkbox" name="favorite_topping[]" value="Strawberry">Strawberry</label>
{{ wheelformErrors['favorite_topping'] is defined ? errorList(wheelformErrors['favorite_topping']) }}
<h3><label for="message">Message</label></h3>
<textarea rows="10" cols="40" id="message" name="message">{{ values['message'] ?? '' }}</textarea>
{{ wheelformErrors['message'] is defined ? errorList(wheelformErrors['message']) }}
<input type="file" name="user_file" id="user_filer">
{# if using recaptcha settings #}
<div class="recaptcha-container">
<script src="https://www.google.com/recaptcha/api.js"></script>
<div class="g-recaptcha" data-sitekey="{{ site_key }}">
</div>
</div>
<input type="submit" value="Send">
</form>
提交后重定向
如果您有一个隐藏的'重定向'输入,则在成功发送电子邮件后,用户将被重定向到该输入。
请注意,如果您没有包含redirect输入,当前页面将被重新加载。
显示闪存消息
当提交联系表单时,插件将在用户会话上设置一个success闪存消息。这样做是为了在表单提交后显示成功消息,并且可以在重定向页面上显示。可用的闪存变量是:wheelformSubmittedForm - 提交表单的ID wheelformSuccess - 要显示的消息。您可以在模板中这样显示它
{% if craft.app.session.hasFlash('wheelformSuccess') %}
<p class="message success">{{ craft.app.session.getFlash('wheelformSuccess') }}</p>
{% endif %}
表单字段类型
您可以将字段类型分配给用户可以从中选择要显示的表单的分区。此字段将返回一个wheelform.form模板服务(与其他示例相同),它属于在管理员面板上选择的表单。如果您需要自定义它,可以使用setConfig变量来修改默认行为。
{% set form = entry.formField.setConfig({
redirect: 'contact/thanks',
attributes: {
'novalidate':"novalidate",
'id':'field-form',
'class': 'field-form',
},
}) %}
显示最后/当前提交
类似于闪存消息(仅在提交后可用),当提交联系表单时,插件会将提交表单的值存储在会话中,并通过wheelform.lastSubmission变量提供一次。您可以在模板中使用它(通常在重定向页面上)如下所示
{% set submission = wheelform.lastSubmission %}
{% if submission %}
<dl>
{% for field in submission.fields %}
<dt>{{ field.label }}</dt>
<dd>{{ field.value }}</dd>
{% endfor %}
</dl>
{% endif %}
您还可以使用submission.id、submission.formId和submission.date(注意:submission.date是DateTime对象,通过date()过滤器运行)。
Recaptcha V3
{# You need to add the Recaptcha Init before the form.open() #} {# action is optional, action defaults to form URL #} {{ wheelform.recaptchaV3({'action': 'contact-form'})}}
显示现有表单提交
您可以通过form.entries属性访问表单上的现有提交表单条目。
{% set form = wheelform.form({ id: 1 }) %}
{# form.entries(start, limit) can be used for pagination purposes #}
{% set entries = form.entries %}
{# form.fields returns active form fields #}
{% set fields = form.fields %}
<table>
<thead>
{% for field in fields %}
<th>{{ field.label }}</th>
{% endfor %}
<th>Date</th>
</thead>
<tbody>
{% for entry in entries %}
<tr data-id="{{ entry.id }}">
{% for field in fields %}
{% set current = entry.fields[field.name] %}
<td data-id="{{ current.name }}">{{ current.value }}</td>
{% endfor %}
<td data-id="date">{{ entry.date|date("m/d/Y") }}</td>
</tr>
{% endfor %}
</tbody>
显示特定表单提交
您可以通过加载表单并按ID请求它来访问特定表单条目。
{% set form = wheelform.form({ id: 1 }) %}
{% set entry = form.entry(id) %}
{% for field in entry.fields %}
<p>{{ field.value }}</p>
{% endfor %}
文件附件
如果您希望您的表单接受文件附件,请按照以下步骤操作
- 确保您的打开HTML
<form>标签包含enctype="multipart/form-data"。 - 在您的表单中添加一个
<input type="file" name="{field_name}">。
将文件保存到资产文件夹
在插件设置中选择您希望保存文件的文件夹。确保已打开“允许公共URL”选项。
Ajax表单提交
您可以选择通过Ajax发布联系表单提交。只需向您的站点发送包含所有常规数据的POST请求即可
JQuery
$('#my-form').submit(function(ev) { // Prevent the form from actually submitting ev.preventDefault(); var data = $(this).serialize(); // Send it to the server $.post('/wheelform/message/send', data, function(response) { if (response.success) { //reponse.message is the message saved in the Form Settings $('#thanks').fadeIn(); } else { // response.values will contain user submitted values // response.errors will be an array containing any validation errors that occurred, indexed by field name // e.g. response.error['email'] => ['Email is required', 'Email is invalid'] alert('An error occurred. Please try again.'); } } ); });
使用 Axios 和 Babel 以及 Webpack 进行基本的 JavaScript 编程
import axios from 'axios'; const contactForm = document.getElementById('contact-form'); if (contactForm) { contactForm.addEventListener('submit', function(event) { /** * This prevents the default behaviour of the browser submitting * the form so that we can handle things instead. */ event.preventDefault(); /** * This gets the element which the event handler was attached to. * * @see https://mdn.org.cn/en-US/docs/Web/API/Event/currentTarget */ const form = event.currentTarget; /** * Hidden field named action */ const url = form.action.value; /** * This takes all the fields in the form and makes their values * available through a `FormData` instance. * * @see https://mdn.org.cn/en-US/docs/Web/API/FormData */ const formData = new FormData(form); axios({ method: 'post', url: url, responseType: 'json', headers: {'X-Requested-With': 'XMLHttpRequest'}, data: formData, }) .then(function (response) { console.log(response); }) .catch(function (error) { console.log(error); }); }); }
如果使用 getCrsfInput(),请确保您将其与表单的其余部分一起提交。
使用 Ajax 的 Recaptcha
如果您使用 Ajax 实现Recaptcha,请注意,在每次 Ajax 请求之后都需要刷新 recaptcha 令牌,以避免无效的 recaptcha 验证错误(请参阅问题 242)。
使用 Fetch API 的示例
const myRequest = new Request('endpoint.json', { method: 'POST', // any allowed Method param: value }); fetch(myRequest) .then((response) => response.json()) .then((data) => { // Use respose `data` here // Refresh Recaptcha token wheelformProcessRecaptchaCallback() });
CSRF 元标签
如果您提交 Ajax 请求且需要在 head 元素中包含元标签,可以使用 {{ wheelform.metaTags() }} 生成适当的 CSRF 值。
权限
有 4 种不同的权限类型({表单名称} 权限在每个表单上重复)
- 创建新表单 - 允许用户/组看到“新建表单”按钮并创建新表单。
- 编辑 {表单名称} - 允许用户/组在表单列表中看到表单。
- {表单名称} 条目 - 允许用户/组查看条目列表。
- {表单名称} 设置 - 允许用户/组编辑表单设置。
表单工具
- CSV 导出器可以根据条目日期进行,在 Admin > 工具 > 表单工具下。
- 可以将表单字段导出为 JSON 文件。
- 可以从有效的 JSON 文件导入表单字段。
删除消息的 Cron 任务
您可以在服务器上安排一个 Cron 任务,每天运行一次,检查并删除数据库中保存的任何旧消息值。Cron 任务命令是:php var/www/yourwebsite/craft wheelform/message/purge 其中 var\www\yourwebsite\craft 是 craft 可执行包的路径。
在 config\wheelform.php 中需要进行的唯一配置是
return [ 'purgeMessages' => true, //True / False value to allow Cron Job to go 'purgeMessagesDays' => 30, //Number of days messages should live in your database ];
注意:此操作不可撤销。
每个表单的“来自”地址自定义
根据每个表单更改“来自”地址,这将覆盖表单设置中设置的一般电子邮件。
- 在 Craft 的配置文件夹内创建
wheelform.php文件。 - 添加一个带有键
forms的array,该ID是您想要覆盖的表单的 ID 作为键,然后是一个带有键from的数组。以下是一个示例
return [ 'forms' => [ // ID of form 3 => [ // This is the email to use for this specific form 'from' => 'form3@example.com', ], 5 => [ // This can also be an array with a custom name 'from' => [ 'form5@example.com' => "Form 5 Custom Name", ] ] ] ];
自定义电子邮件模板
电子邮件模板是可选的。可以使用以下步骤使用自定义 Twig 模板
- 在 Craft 的配置文件夹内创建
wheelform.php文件。 wheelform.php预期返回一个配置设置数组。选项包括template:用于所有电子邮件的默认模板。notification:默认通知模板覆盖。forms:是一个数组,覆盖特定于表单的任何设置。数组的键是要修改的表单的 ID。(这些设置优先于其他任何内容)(注意:此forms键与上面自定义“来自”地址的相同)
return [ 'template' => '_emails/custom', 'notification' => [ 'template' => '_emails/notification', 'subject' => 'Default Notification Subject', ], 'forms' => [ 1 => [ 'template' => '_emails/form1_template', 'notification' => [ 'template' => '_emails/notification2', 'subject' => 'Form specific Subject', ], ], 3 => [ 'template' => '_emails/form3_template', ], ], ];
- 在您的模板中,您将能够访问一个
fields数组和notification_message,其中包含在表单管理面板上设置的消息。以下是一个示例
<html> <body> <h1>Custom Template</h1> <ul> {% for field in fields %} <li> <strong>{{ field.label }}:</strong> {% switch field.type %} {% case "file" %} {# This is an object with file attributes #} {{ field.value.name }} {% case "checkbox" %} {# Array of all choices selected #} {{ field.value | join(',')}} {% case "list" %} {% if field.value %} <ul> {% for item in field.value %} <li>{{ item }}</li> {% endfor %} </ul> {% endif %} {% default %} {# Text based items #} {{ field. value }} {% endswitch %} </li> {% endfor %} </ul> </body> </html>
跳过将文件附加到电子邮件中
在 wheelform.php 中,每个表单都可以有一个标志来跳过附加电子邮件
return [ 'forms' => [ 1 => [ 'skip_attachments' => true, // True/False value, leave empty if not needed. ], ], ];
蜜罐字段
Honeypot 字段是一个旨在由人类留空的字段。通常通过 CSS 隐藏。有关 Honeypot 字段的更多信息请参阅 此处。
如果您不使用 {{ form.close() }} 辅助标签,请确保您添加一个与创建表单时使用的名称相同名称的文本字段。然后,使用 CSS 或 JavaScript 隐藏它。
渲染 Honeypot(可选)
如果您需要完全控制蜜罐字段的行为。您可以通过调用 {{ form.honeypot($type, $attributes = [], $returnString = false) }} 来实现,其中
$type可以是三种类型之一:text、password、hidden。$attributes:(可选)字段的选项数组。例如:{'autocomplete': 'none', 'class': 'comments-field'}。$returnString:(可选)这将返回字段的 HTML 字符串以进行进一步操作,而不是模板准备实体。
事件
(注意:这主要面向了解基本 PHP 和 Composer 包的开发者)
beforeValidate 事件,允许开发者在基本插件验证之前验证值并添加自定义错误。跳过插件验证,这个事件发生在基本插件验证之前。
afterValidate 事件,允许开发者在基本插件验证之后验证消息并调整值和错误,这些更改将级联到其他事件和邮件发送者。
beforeSave 事件,允许开发者在将活动记录对象保存到数据库之前修改其值,这些更改将级联到其他事件和邮件发送者。
beforeSend 事件,允许开发者在电子邮件中修改要发送的字段,此事件不会修改在数据库中输入的值。仅修改发送给客户端的字段。
afterSend 事件,最终发送给用户电子邮件的值,非常适合第三方集成和库。
beforeResponse 事件,修改提交的响应,是添加自定义标题、动态成功消息或前端自定义数据的好地方。
您还可以触发其他自定义功能,例如收集自定义字段值以添加到第三方服务,例如邮件列表。
beforeSend 和 afterSend 对象如下所示: Event 类属性
form_id- 正在提交的当前表单的 ID。这允许开发者以某种方式检查正在发送的字段。subject- 当前表单的主题。这可以修改为使其可定制。message- 关联数组,包含提交的不同字段及其值。from- 发送消息的电子邮件地址。to- 发送消息的电子邮件地址(这可以是一个多个电子邮件的数组)。reply_to- 消息可以回复的电子邮件地址。email_html- 将在电子邮件中发送的完整 HTML 字符串。这将覆盖其他电子邮件模板。saveMessage- 允许消息在数据库中保存(默认:True)。sendMessage- 允许发送消息(默认:True)。
处理这些事件的示例插件。 wheelformhelper
翻译
可以使用翻译文件夹内的格式提交新的翻译。 (我将尽可能保持“es”翻译的最新状态,这可以成为您翻译的良好起点)
