1

I have an entry type with simple Matrix field which has just one block type [activity] and several other non-matrix fields.

My front-end entry form works perfectly on non-matrix fields, but for some reason I'm not able to insert new blocks into the matrix field.

Here's my form code that only deals with the matrix field:

{# get field settings #}
{% set fieldTimeStart = craft.app.fields.getFieldById(253) %}
{% set fieldTimeEnd = craft.app.fields.getFieldById(249) %}
{% set fieldDescription = craft.app.fields.getFieldById(251) %}
{% set fieldLocation = craft.app.fields.getFieldById(250) %}
{% set fieldParticipants = craft.app.fields.getFieldById(252) %}

<form method="post" accept-charset="UTF-8" enctype="multipart/form-data">
{{ csrfInput() }}
{{ actionInput('entries/save-entry') }}
{{ hiddenInput('sectionId', '5') }}
{{ hiddenInput('enabled', '1') }}
{{ hiddenInput('entryId', entry.id) }}
{{ redirectInput(url('planning/schedule', {'diagnostic':diagnosticId})) }}

{# All existing blocks #}
{% for blockId in clone(entry.planningSchedule).anyStatus().ids() %}
    {{ hiddenInput('fields[planningSchedule][sortOrder][]', blockId) }}
{% endfor %}

{# For the new activity block #}
{{ hiddenInput('fields[planningSchedule][sortOrder][]', 'new:1') }}
{#
 # Including these hidden fields for the new matrix block results is "entry not saved" error
 #
{{ hiddenInput('fields[planningSchedule][blocks][new:1][type]', 'activity') }}
{{ hiddenInput('fields[planningSchedule][blocks][new:1][enabled]', '1') }}
#}

{# Prefix the block's input names with `fields[planningSchedule][blocks][new:1][fields]` #}
{% set fieldNamePrefix = 'fields[planningSchedule][blocks][new:1][fields]' %}

<div class="form-row">
    <div class="form-group col-md-6">
        <label for="{{ fieldTimeStart.handle }}">Start Time</label>
        <select id="{{ fieldTimeStart.handle }}" name="{{ fieldNamePrefix }}[{{ fieldTimeStart.handle }}][time]" class="custom-select" required="required">
            <option disabled selected hidden value="">Select start time</option>
            {% for i in 7..16 %}
            <option value="{{ i }}:00">{{ i > 12 ? i - 12 : i }}:00 {{ i < 12 ? 'am' : 'pm' }}</option>
            <option value="{{ i }}:15">{{ i > 12 ? i - 12 : i }}:15 {{ i < 12 ? 'am' : 'pm' }}</option>
            <option value="{{ i }}:30">{{ i > 12 ? i - 12 : i }}:30 {{ i < 12 ? 'am' : 'pm' }}</option>
            <option value="{{ i }}:45">{{ i > 12 ? i - 12 : i }}:45 {{ i < 12 ? 'am' : 'pm' }}</option>
            {% endfor %}
        </select>
    </div>
    
    <div class="form-group col-md-6">
        <label for="{{ fieldTimeEnd.handle }}">End Time</label>
        <select id="{{ fieldTimeEnd.handle }}" name="{{ fieldNamePrefix }}[{{ fieldTimeStart.handle }}][time]" class="custom-select" required>
            <option disabled selected hidden value="">Select end time</option>
            {% for i in 7..16 %}
            <option value="{{ i }}:00">{{ i > 12 ? i - 12 : i }}:00 {{ i < 12 ? 'am' : 'pm' }}</option>
            <option value="{{ i }}:15">{{ i > 12 ? i - 12 : i }}:15 {{ i < 12 ? 'am' : 'pm' }}</option>
            <option value="{{ i }}:30">{{ i > 12 ? i - 12 : i }}:30 {{ i < 12 ? 'am' : 'pm' }}</option>
            <option value="{{ i }}:45">{{ i > 12 ? i - 12 : i }}:45 {{ i < 12 ? 'am' : 'pm' }}</option>
            {% endfor %}
        </select>
    </div>
</div>

<div class="form-group">
    <label for="{{ fieldDescription.handle }}">Activity</label>
    <textarea class="form-control" id="{{ fieldDescription.handle }}" name="{{ fieldNamePrefix }}[{{ fieldDescription.handle }}]" placeholder="Describe activity" required="required"></textarea>
</div>

<div class="form-row">
    <div class="form-group col-md-6">
        <label for="{{ fieldLocation.handle }}">Location</label>
        <input type="text" class="form-control" id="{{ fieldLocation.handle }}" name="{{ fieldNamePrefix }}[{{ fieldLocation.handle }}]" placeholder="" required>
    </div>
    
    <div class="form-group col-md-6">
        <label for="{{ fieldParticipants.handle }}">Participants</label>
        <input type="text" class="form-control" id="{{ fieldParticipants.handle }}" name="{{ fieldNamePrefix }}[{{ fieldParticipants.handle }}]" placeholder="" required>
    </div>
</div>

<div class="schedule-btn-container">
    <button type="submit" class="btn btn-primary">Save Activity</button>
</div>

</form>

And here's how the field inputs look on the rendered form:

{# All existing blocks #}
<input type="hidden" name="fields[planningSchedule][sortOrder][]" value="19132">

{# For the new activity block #}
<input type="hidden" name="fields[planningSchedule][sortOrder][]" value="new:1">


<select id="timeStart" name="fields[planningSchedule][blocks][new:1][fields][timeStart][time]" class="custom-select" required="required">
    <option disabled="" selected="" hidden="" value="">Select start time</option>
    <option value="7:00">7:00 am</option>
    ...
</select>

<select id="timeEnd" name="fields[planningSchedule][blocks][new:1][fields][timeStart][time]" class="custom-select" required="">
    <option disabled="" selected="" hidden="" value="">Select end time</option>
    <option value="7:00">7:00 am</option>
    ... 
</select>

<textarea class="form-control" id="description" name="fields[planningSchedule][blocks][new:1][fields][description]" placeholder="Describe activity" required="required"></textarea>

<input type="text" class="form-control" id="location" name="fields[planningSchedule][blocks][new:1][fields][location]" placeholder="" required="">

<input type="text" class="form-control" id="participants" name="fields[planningSchedule][blocks][new:1][fields][participants]" placeholder="" required="">

Comparing these field name attributes to what's used in the control panel, the only difference I can see is that the control panel uses [new1] instead of [new:1] for the temporary id of new blocks being inserted.

Neither [new1] nor [new:1] seem to make any difference.

{# CONTROL PANEL INPUTS WHEN INSERTING NEW MATRIX BLOCK #}
{# Trimmed out extra attributes to focus on name attribute #}
<input name="fields[planningSchedule][blocks][new1][fields][timeStart][time]">
<input name="fields[planningSchedule][blocks][new1][fields][timeEnd][time]">
<textarea name="fields[planningSchedule][blocks][new1][fields][description]"></textarea>
<input name="fields[planningSchedule][blocks][new1][fields][location]">
<input name="fields[planningSchedule][blocks][new1][fields][participants]">

After submitting the entry form with a new matrix block the flash message says "Entry saved" and any existing matrix blocks (created within the control panel) are retained, but the new matrix block is not saved to the entry.

I've also tried using the Guest Entries plugin to see if that makes any difference, but I get the same result either way... "Entry saved" but no new matrix block.

I've seen some posts here on stack exchange about this issue, but they seem to be very old and are probably for Craft 2 instead of Craft 3. Those posts seem to leave out [blocks] from the matrix field names, ex:

<input name="fields[planningSchedule][new:1][fields][location]">

instead of

<input name="fields[planningSchedule][blocks][new:1][fields][location]">

I've tried both field name patterns and neither works.

If anyone can spot what I'm doing wrong I'd love to hear!

1

You seem to be missing the block type:

<input type="hidden" name="fields[planningSchedule][blocks][new:1][type]" value="text" />

and change the value to your block type (handle).

1

Thanks Oli! I got this working after making two changes:

  1. Add hidden field for declaring Matrix block type
{# For the new activity block #}
{{ hiddenInput('fields[planningSchedule][sortOrder][]', 'new:1') }}
{{ hiddenInput('fields[planningSchedule][blocks][new:1][type]', 'activity') }}
  1. My Time field's select option values were not formatted correctly. Need to use date('H:i') format.
<select id="{{ fieldTimeStart.handle }}" name="{{ fieldNamePrefix }}[{{ fieldTimeStart.handle }}][time]" class="custom-select" required="required">
    <option disabled selected hidden value="">Select start time</option>
    {% for i in 7..16 %}
        {% for increment in [':00',':15',':30',':45'] %}
            {% set value = i ~ increment %}
            <option value="{{ value | date('H:i') }}">{{ i > 12 ? i - 12 : i }}{{ increment }} {{ i < 12 ? 'am' : 'pm' }}</option>
        {% endfor %}
    {% endfor %}
</select>

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.