In website operation, collecting user feedback and inquiries is an important link to improve service quality and understand user needs.AnQiCMS provides a flexible and powerful message management function, allowing you to easily display the message form in the frontend template and support custom fields to meet the information collection needs of different business scenarios.

To implement dynamic display of user submitted comment forms and custom fields in AnQiCMS templates, we mainly use a core tag: guestbook. This tag can fetch all the comment field information you configure in the background, and then render it to the front-end page through a loop to build a completely dynamic comment form.

UnderstandguestbookTag

guestbookThe label is designed specifically for the留言表单in Anqi CMS, its basic usage is very intuitive:

{% guestbook fields %}
    {# 在这里循环渲染表单字段 #}
{% endguestbook %}

When you use{% guestbook fields %}It will return a namedfieldsto the template. ThisfieldsThe variable is an array that contains all the form field information you have configured under "Function Management" in the Anqi CMS backend, including default system fields and custom fields you have created.

Moreover, if you are managing multiple sites and want to call form field of other sites' comment forms in the current site's template, you can do so bysiteIdparameter to specify the site ID, for example{% guestbook fields with siteId="2" %}.

Dynamically render the message form field

fieldsEach element in the variable represents a message form field. In the loop traversalfieldsAn array, we can get detailed properties of each field and dynamically generate corresponding HTML form elements.

Each field object (usually named in loops) will contain the following key properties:item) will include the following key attributes:

  • item.Name: The display name of the field, such as 'Your Name', 'Phone Number', etc.
  • item.FieldName: The internal identifier of the field, used as the HTML form element'snameproperties, such asuser_name/contactThe camel case naming form of the field you customize.
  • item.TypeThe field type determines which type of HTML form element should be rendered. Common types include:
    • textSingle-line text input box (<input type="text">)
    • numberNumber input box (<input type="number">)
    • textarea: Text box (multi-line)<textarea>)
    • radio: Radio button group (<input type="radio">)
    • checkbox: Checkbox group (<input type="checkbox">)
    • select: Dropdown selection box (<select>)
  • item.Required: Boolean value indicating whether this field is required. If it istrueWe can add in the HTML elementrequiredProperty.
  • item.Content: Default value or placeholder text for the field.
  • item.Items: When the field type isradio/checkboxorselectAt this time, this property will be an array containing all the option values available. We need to loop through thisitem.Itemsarray to generate options.

common template code for building a message form

With this field information, we can build a generic template code that can automatically adapt to changes in the backend configuration without manually modifying the frontend HTML.

The following is a detailed example showing how to dynamically render a message form in a template, and it includes common text, numbers, multi-line text, radio buttons, checkboxes, dropdown selections, and captcha functions:

`twig

{# 隐藏字段,用于指定后端返回格式,例如设置为'html'会返回HTML页面,'json'则返回JSON数据 #}
<input type="hidden" name="return" value="html">

{% guestbook fields %}
    {% for item in fields %}
        <div class="form-group">
            <label for="{{ item.FieldName }}">{{ item.Name }}{% if item.Required %}<span class="required-star">*</span>{% endif %}</label>
            <div>
                {% if item.Type == "text" or item.Type == "number" %}
                    <input type="{{ item.Type }}"
                           id="{{ item.FieldName }}"
                           name="{{ item.FieldName }}"
                           {% if item.Required %}required{% endif %}
                           placeholder="{{ item.Content }}"
                           class="form-control"
                           autocomplete="off">
                {% elif item.Type == "textarea" %}
                    <textarea id="{{ item.FieldName }}"
                              name="{{ item.FieldName }}"
                              {% if item.Required %}required{% endif %}
                              placeholder="{{ item.Content }}"
                              rows="5"
                              class="form-control"></textarea>
                {% elif item.Type == "radio" %}
                    <div class="form-check-group">
                        {% for val in item.Items %}
                            <input type="radio"
                                   id="{{ item.FieldName }}_{{ loop.index }}"
                                   name="{{ item.FieldName }}"
                                   value="{{ val }}"
                                   {% if item.Required %}required{% endif %}
                                   class="form-check-input">
                            <label for="{{ item.FieldName }}_{{ loop.index }}" class="form-check-label">{{ val }}</label>
                        {% endfor %}
                    </div>
                {% elif item.Type == "checkbox" %}
                    <div class="form-check-group">
                        {% for val in item.Items %}
                            <input type="checkbox"
                                   id="{{ item.FieldName }}_{{ loop.index }}"
                                   name="{{ item.FieldName }}[]" {# 多选时name属性需要加[] #}
                                   value="{{ val }}"
                                   class="form-check-input">
                            <label for="{{ item.FieldName }}_{{ loop.index }}" class="form-check-label">{{ val }}</label>
                        {% endfor %}
                        {# 如果需要必填,可以考虑通过JS进行校验,或将Required放在一个隐藏字段中辅助判断 #}
                    </div>
                {% elif item.Type == "select" %}
                    <select id="{{ item.FieldName }}"
                            name="{{ item.FieldName }}"
                            {% if item.Required %}required{% endif %}
                            class="form-control">
                        {% if not item.Required %}<option value="">请选择</option>{% endif %} {# 非必填时提供空选项 #}
                        {% for val in item.Items %}
                            <option value="{{ val }}">{{ val }}</option>
                        {% endfor %}
                    </select>
                {% endif %}
            </div>
        </div>
    {% endfor %}
{% endguestbook %}

{# 验证码部分:如果后台开启了留言验证码功能,这部分代码是必需的 #}
<div class="form-group captcha-group">
    <label for="captcha">验证码<span class="required-star">*</span></label>
    <div class="captcha-input-wrapper">
        <input type="hidden" name="captcha_id" id="captcha_id">
        <input type="text" name="captcha" id="captcha" required placeholder="请填写验证码" class="form-control captcha-input" autocomplete="off">
        <img src="" id="get-captcha" class="captcha-image" alt="验证码" title="点击刷新验证码" style="cursor: pointer;">
    </div>
</div>
<script>
    // JavaScript 用于刷新验证码
    document.getElementById('get-captcha').addEventListener("click", function (e) {
        fetch('/api/captcha')
            .then(response => response.json())
            .then(res => {
                document.getElementById('captcha_id').setAttribute("value", res.data.captcha_id);
                document.getElementById('get-captcha').setAttribute("src", res.data.captcha);
            }).catch(err => console.error("获取验证码失败:", err));
    });
    document.getElementById('get-captcha').click(); // 页面加载时自动获取一次验证码
</script>

<div class="form-group form-actions">
    <button type="submit" class="btn btn-primary">提交留言</button>
    <button type="reset" class="btn btn-secondary">重置</button>
</div>

/