16

How can you programmatically save an entry that has a Matrix field in Craft 3?

(Something like this gist for Craft 2)

Brandon Kelly
  • 34,307
  • 2
  • 71
  • 137

2 Answers2

24

Saving Matrix fields programmatically got a lot easier in Craft 3 thanks to all the content refactoring.

use craft\elements\Entry;
use craft\elements\MatrixBlock;

// Figure out the section & entry type
$section = Craft::$app->sections->getSectionByHandle('news');
$entryTypes = $section->getEntryTypes();
$entryType = reset($entryTypes);

// Create an entry
$entry = new Entry([
    'sectionId' => $section->id,
    'typeId' => $entryType->id,
    'fieldLayoutId' => $entryType->fieldLayoutId,
    'authorId' => 1,
    'title' => 'My Entry',
    'slug' => 'my-entry',
    'postDate' => new DateTime(),
]);

// Set the custom field values (including Matrix)
$entry->setFieldValues([
    'summary' => 'Some "summary" custom field value...',
    'matrixField' => [
        'new1' => [
            'type' => 'blockTypeHandle',
            'fields' => [
                // the block's custom field values...
            ],
        ],
        'new2' => [
            'type' => 'blockTypeHandle',
            'fields' => [
                // the block's custom field values...
            ],
        ],
    ],
]);

// Save the entry
Craft::$app->elements->saveElement($entry);
Brandon Kelly
  • 34,307
  • 2
  • 71
  • 137
  • 2
    That still works in Craft CMS 4 (as of writing I am using 4.4.x). Just in case someone is asking if that's only a Craft 3 thing. :) – Arvid May 10 '23 at 13:00
13

Just an additional note:

If you want to append certain elements to your matrix field instead of overwriting them all you have to do

Update Craft 4.0

there is a new sortOrder key that makes my previous answer obsolete.

// grab all existing ids
$existingIds = $element->getFieldValue('matrixField')->ids();
// add a new block to the ids
$existingIds[] = 'new1';

$element->setFieldValue('matrixField', [ 'sortOrder' => $existingIds, 'blocks' => [ 'new1' => [ 'type' => 'blockTypeHandle', 'fields' => [ // the blocks custom field values... ] ] ] ]); // Save the entry Craft::$app->elements->saveElement($element);

Old answer for Craft 3 (first versions < 3.6)

Just an additional note:

If you want to append certain elements to your matrix field instead of overwriting them all you have to do

/** @var \craft\fields\Matrix $field */
$field = Craft::$app->getFields()->getFieldByHandle('matrixField');

// get the existing matrixField Value, keep in mind, this is a Query and not an array $existingMatrixQuery = $element->getFieldValue('matrixField');

// serialize the data in order to get an array like Brandon Kelly // created in his answer $serializedMatrix = $field->serializeValue($existingMatrixQuery, $element);

// append the new blocks to the existing array $serializedMatrix['new1'] = [ 'type' => 'blockTypeHandle', 'fields' => [ // the block's custom field values... ] ];

$element->setFieldValue('matrixField', $serializedMatrix);

// Save the entry Craft::$app->elements->saveElement($element);

Robin Schambach
  • 19,713
  • 1
  • 19
  • 44