craftcms/guest-entries

此插件允许您从网站前端保存访客条目。

安装次数: 84,733

依赖项: 3

建议者: 0

安全: 0

星星: 106

关注者: 12

分支: 26

开放性问题: 12

类型:craft-plugin

4.0.1 2024-05-23 05:03 UTC

README

允许访客从网站前端创建条目。

要求

Guest Entries 需要 Craft CMS 4.0.0+ 或 5.0.0+。

安装

您可以从 插件商店 或使用 Composer 安装 Guest Entries

从插件商店

转到项目控制面板中的 插件商店(在允许 管理员更改的环境中),搜索“Guest Entries”,然后点击 安装

使用 Composer

打开您的终端并运行以下命令

# Navigate to your project directory:
cd /path/to/my-project

# Require the plugin package with Composer:
composer require craftcms/guest-entries -w

# Install the plugin with Craft:
php craft plugin/install guest-entries

设置

从插件设置页面,您可以配置……

  • ……哪些部分允许访客提交条目;
  • ……默认条目作者和状态;
  • ……以及是否在接收之前验证提交。

用法

基本的访客条目模板应类似于以下内容

{# Macro to help output errors: #}
{% macro errorList(errors) %}
    {% if errors %}
        {{ ul(errors, { class: 'errors' }) }}
    {% endif %}
{% endmacro %}

{# Default value for the `entry` variable: #}
{% set entry = entry ?? null %}

<form method="post" action="" accept-charset="UTF-8">
    {# Hidden inputs required for the form to work: #}
    {{ csrfInput() }}
    {{ actionInput('guest-entries/save') }}

    {# Custom redirect URI: #}
    {{ redirectInput('success') }}

    {# Section for new entries: #}
    {{ hiddenInput('sectionHandle', 'mySectionHandle') }}

    {# Entry properties and custom fields: #}
    <label for="title">Title</label>
    {{ input('text', 'title', entry ? entry.title, { id: 'title' }) }}
    {{ entry ? _self.errorList(entry.getErrors('title')) }}

    <label for="body">Body</label>
    {{ tag('textarea', {
        text: entry ? entry.body,
        id: 'body',
        name: 'fields[body]',
    }) }}
    {{ entry ? _self.errorList(entry.getErrors('body')) }}

    {# ... #}

    <button type="submit">Publish</button>
</form>

注意
提交数据和处理成功和错误状态的过程在 控制器操作 文档中概述。

支持的参数

以下参数可以与提交一起发送

表单提示

指定部分 + 条目类型

插件通过查找 sectionHandlesectionUidsectionId 参数(按此顺序)来确定新条目所在的分区。另一方面,条目类型只能由 typeId 参数定义——但由于 ID 在不同环境中可能不稳定,您必须通过已知标识符来查找它们。

假设您已经有了分区(或者至少有一个分区 handle),通过分区模型来做这件事是最简单的方法

{% set targetSection = craft.app.sections.getSectionByHandle('resources') %}
{% set entryTypes = targetSection.getEntryTypes() %}

{# Select a single type, identified by its handle: #}
{% set targetEntryType = collect(entryTypes).firstWhere('handle', 'document') %}

{{ hiddenInput('sectionId', targetSection.id) }}
{{ hiddenInput('typeId', targetEntryType.id) }}

发送自定义字段

自定义字段数据应嵌套在 fields 键下,字段名用 [方括号] 包围

<input
    type="text"
    name="fields[myCustomFieldHandle]"
    value="{{ entry ? entry.myCustomFieldHandle }}">

如果指定分区的条目默认启用,则将在 所有 自定义字段上进行验证,这意味着标记为 必填 的条目类型的字段布局必须随提交一起发送。有关 Craft 接受的值类型的详细信息,请参阅 字段类型 文档。

警告
从您的表单中省略字段并不意味着它是安全的!聪明的用户可能会修改请求有效负载并提交额外的字段数据。如果这对您的网站造成问题,请考虑使用 事件 来清除值或拒绝提交。

验证错误

如果在输入时存在验证错误,页面将重新加载,并在一个名为 entry 的变量下提供一个填充的 craft\elements\Entry 对象。您可以像访问正常条目一样访问该对象中的已发布值,或者使用 getErrors()getFirstError()getFirstErrors() 显示错误。

注意
可以使用控制面板中的“条目变量名称” 设置 重命名 entry 变量。如果您想在已经注入同名变量的条目页上使用表单,这可能是有必要的。

重定向

发送一个 redirect 参数,在成功保存条目后将用户发送到特定位置。在上面的例子中,这是通过 redirectInput('...') 函数 来处理的。路径被评估为一个 对象模板,并且可以包含 {curlyBraces} 中的保存条目的属性。

通过 Ajax 提交

如果您通过带有 Accept: application/json 头的 Ajax 提交表单 通过 Ajax,将返回一个包含以下键的 JSON 响应

  • success (布尔值) – 条目是否成功保存
  • errors (对象) – 所有验证错误按字段名称索引(如果未保存)
  • id (字符串) – 条目的 ID(如果已保存)
  • title (字符串) – 条目的标题(如果已保存)
  • authorUsername (字符串) – 条目的作者的用户名(如果已保存)
  • dateCreated (字符串) – 条目的创建日期,格式为 ISO 8601(如果已保存)
  • dateUpdated (字符串) – 条目的更新日期,格式为 ISO 8601(如果已保存)
  • postDate (字符串,null) – 条目的发布日期,格式为 ISO 8601(如果已保存且已启用)
  • url (字符串,null) – 条目的公共 URL(如果已保存、已启用且在具有 URL 的部分中)

查看条目

使用 redirect 参数允许您显示用户刚刚提交的一些或全部内容——即使条目默认情况下是禁用的。

警告
在您的网站上显示不受信任的内容时请格外小心,尤其是在绕过审核流程时!

默认启用

具有 URL 的部分的条目可以立即查看,使用此 redirect 参数

{{ redirectInput('{url}') }}

默认禁用

为了显示一个 已禁用 的条目,您需要设置一个自定义 路由

<?php

return [
    // This route uses the special `{uid}` token, which will
    // match any UUIDv4 generated by Craft:
    'submissions/confirmation/<entryUid:{uid}>' => ['template' => '_submissions/confirmation'],
];

…并通过在条目表单中包含 {{ redirectInput('submissions/confirmation/{uid}') }} 将用户引导到它。您的模板(_submissions/confirmation.twig)将负责根据 Craft 提供的 entryUid 路由令牌查找禁用条目并显示它

{% set preview = craft.entries()
    .status('disabled')
    .section('documents')
    .uid(entryUid)
    .one() %}

{# Bail if it doesn’t exist: #}
{% if not preview %}
    {% exit 404 %}
{% endif %}

{# Supposing the user’s name was recorded in the `title` field: #}
<h1>Thanks, {{ preview.title }}!</h1>

<p>Your submission has been recorded, and is awaiting moderation.</p>

此查询仅选择 disabled 条目,以便条目上线后“预览”无效。此“确认”URI 不需要 与条目的实际 URI 匹配。

事件

访客条目 通过添加一些自己的事件来增强条目生命周期中发射的正常 事件,允许开发人员自定义提交过程。

以下片段应添加到您插件或模块的 init() 方法中,按照官方的 事件使用说明

beforeSaveEntry 事件

插件可以通过使用 beforeSaveEntry 事件在访客条目保存之前得到通知。这也是标记提交为垃圾邮件并阻止其保存的机会

use craft\helpers\StringHelper;
use craft\guestentries\controllers\SaveController;
use craft\guestentries\events\SaveEvent;
use yii\base\Event;

// ...

Event::on(
    SaveController::class,
    SaveController::EVENT_BEFORE_SAVE_ENTRY,
    function(SaveEvent $e) {
        // Get a reference to the entry object:
        $entry = $e->entry;

        // Perform spam detection logic of your own design:
        if (StringHelper::contains($entry->title, 'synergy', false)) {
            // Set the event property:
            $e->isSpam = true;
        }
    }
);

afterSaveEntry 事件

插件可以通过使用 afterSaveEntry 事件在访客条目保存之后得到通知

use craft\guestentries\controllers\SaveController;
use craft\guestentries\events\SaveEvent;
use yii\base\Event;

// ...

Event::on(
    SaveController::class,
    SaveController::EVENT_AFTER_SAVE_ENTRY,
    function(SaveEvent $e) {
        // Grab the entry
        $entry = $e->entry;

        // Was it flagged as spam?
        $isSpam = $e->isSpam;
    }
);

afterError 事件

插件可以在提交被判定为无效后立即使用 afterError 事件得到通知

use craft\guestentries\controllers\SaveController;
use craft\guestentries\events\SaveEvent;
use yii\base\Event;

// ...

Event::on(
    SaveController::class,
    SaveController::EVENT_AFTER_ERROR,
    function(SaveEvent $e) {
        // Grab the entry
        $entry = $e->entry;

        // Get any validation errors
        $errors = $entry->getErrors();
    }
);