You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何使用含table、dropdown字段的matrix搭建CraftCMS前端表单

问题排查与实现方案

报错原因

你遇到的Impossible to access an attribute ("settings") on a null variable.错误来自三个核心问题:

  • courseTitle是属于Matrix Block Type(名称为course)下的子字段,不是站点全局的顶级字段,直接用craft.fields.getFieldbyHandle('courseTitle')获取不到对应字段对象,返回为空,调用settings就会触发报错
  • 你在for循环内部重定义了entry变量,会覆盖外层的entry对象,导致后续调用异常
  • Matrix子字段的提交参数格式错误,你把courseTitle写成了顶级字段,实际上它属于Matrix block的内部字段,参数层级不对

修正后的实现代码

以下代码同时兼容已有Matrix块的编辑、新Matrix块的提交,以及table字段内dropdown列的渲染:

{# 预先定义目标entry,避免循环内变量覆盖 #}
{% set targetEntry = entry ?? create('craft\\elements\\Entry') %}

{# 遍历已有Matrix块 #}
{% for block in targetEntry.course.all() %}
    {% if block.type.handle == 'course' %}
    <form method="post" accept-charset="UTF-8">
        {{ csrfInput() }}
        <input type="hidden" name="action" value="entries/save-entry">
        <input type="hidden" name="sectionId" value="1">
        <input type="hidden" name="enabled" value="1">
        <input type="hidden" name="entryId" value="{{ targetEntry.id ?? '' }}">
        
        {# Matrix字段排序、类型参数定义 #}
        <input type="hidden" name="fields[course][sort][]" value="{{ block.id ?? 'new1' }}">
        <input type="hidden" name="fields[course][{{ block.id ?? 'new1' }}][type]" value="course">
        <input type="hidden" name="fields[course][{{ block.id ?? 'new1' }}][enabled]" value="1">
        
        {# 正确获取Matrix Block下的courseTitle字段 #}
        {% set matrixBlockType = craft.app.matrix.getBlockTypeByHandle('course') %}
        {% set dropdownField = matrixBlockType.getFieldByHandle('courseTitle') %}
        
        <select class="form-control" id="courseTitle" name="fields[course][{{ block.id ?? 'new1' }}][fields][courseTitle]">
            {% for option in dropdownField.settings.options %}
            <option {{ block.courseTitle.value == option.value ? 'selected' : '' }} value="{{ option.value }}">{{ option.label }}</option>
            {% endfor %}
        </select>

        {# 渲染table类型字段stage1CourseBookingForm #}
        {% set tableField = matrixBlockType.getFieldByHandle('stage1CourseBookingForm') %}
        {% set tableData = block.stage1CourseBookingForm ?? [] %}
        <table class="form-table">
            <thead>
                <tr>
                    {% for col in tableField.settings.columns %}
                    <th>{{ col.heading }}</th>
                    {% endfor %}
                </tr>
            </thead>
            <tbody>
                {% for row in tableData %}
                <tr>
                    {% for col in tableField.settings.columns %}
                    <td>
                        {% if col.handle == 'courseType' %}
                        {# 渲染table内的dropdown列 #}
                        <select name="fields[course][{{ block.id ?? 'new1' }}][fields][stage1CourseBookingForm][{{ loop.parent.loop.index0 }}][{{ col.handle }}]">
                            {% for option in col.options %}
                            <option {{ row[col.handle] == option.value ? 'selected' : '' }} value="{{ option.value }}">{{ option.label }}</option>
                            {% endfor %}
                        </select>
                        {% else %}
                        <input type="text" name="fields[course][{{ block.id ?? 'new1' }}][fields][stage1CourseBookingForm][{{ loop.parent.loop.index0 }}][{{ col.handle }}]" value="{{ row[col.handle] ?? '' }}">
                        {% endif %}
                    </td>
                    {% endfor %}
                </tr>
                {% endfor %}
            </tbody>
        </table>
        
        <button type="submit">Publish</button>
    </form>
    {% endif %}
{% endfor %}

{# 新增entry无Matrix块的场景,渲染空表单 #}
{% if targetEntry.course.count() == 0 %}
<form method="post" accept-charset="UTF-8">
    {{ csrfInput() }}
    <input type="hidden" name="action" value="entries/save-entry">
    <input type="hidden" name="sectionId" value="1">
    <input type="hidden" name="enabled" value="1">
    <input type="hidden" name="entryId" value="{{ targetEntry.id ?? '' }}">
    
    <input type="hidden" name="fields[course][sort][]" value="new1">
    <input type="hidden" name="fields[course][new1][type]" value="course">
    <input type="hidden" name="fields[course][new1][enabled]" value="1">
    
    {% set matrixBlockType = craft.app.matrix.getBlockTypeByHandle('course') %}
    {% set dropdownField = matrixBlockType.getFieldByHandle('courseTitle') %}
    <select class="form-control" id="courseTitle" name="fields[course][new1][fields][courseTitle]">
        {% for option in dropdownField.settings.options %}
        <option value="{{ option.value }}">{{ option.label }}</option>
        {% endfor %}
    </select>

    {% set tableField = matrixBlockType.getFieldByHandle('stage1CourseBookingForm') %}
    <table class="form-table">
        <thead>
            <tr>
                {% for col in tableField.settings.columns %}
                <th>{{ col.heading }}</th>
                {% endfor %}
            </tr>
        </thead>
        <tbody>
            <tr>
                {% for col in tableField.settings.columns %}
                <td>
                    {% if col.handle == 'courseType' %}
                    <select name="fields[course][new1][fields][stage1CourseBookingForm][0][{{ col.handle }}]">
                        {% for option in col.options %}
                        <option value="{{ option.value }}">{{ option.label }}</option>
                        {% endfor %}
                    </select>
                    {% else %}
                    <input type="text" name="fields[course][new1][fields][stage1CourseBookingForm][0][{{ col.handle }}]" value="">
                    {% endif %}
                </td>
                {% endfor %}
            </tr>
        </tbody>
    </table>
    
    <button type="submit">Publish</button>
</form>
{% endif %}

注意事项

  • 遍历Matrix字段时必须调用.all()方法,否则返回的是查询对象不是block列表
  • 所有Matrix内的子字段提交参数必须嵌套在fields[course][blockID][fields][字段名]层级下,不能直接写为顶级fields参数
  • 若允许访客提交表单,需要配置对应section的访客提交权限,否则会触发权限错误
  • Table字段的提交参数是二维数组格式,第一层是行索引,第二层是列handle

内容的提问来源于stack exchange,提问作者SynecdocheNORTH

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.28 15:36:06