<p>FYI, this is how it's done in Craft 3:</p>

<pre><code>use craft\fields\Matrix;
use craft\fields\PlainText;

//Create the matrix field 
$field = Craft::$app-&gt;getFields()-&gt;createField([
    'type' =&gt; Matrix::class,
    'groupId' =&gt; 1,
    'name' =&gt; 'My Matrix Field',
    'handle' =&gt; 'myMatrixField',
    'settings' =&gt; array (
        'minBlocks' =&gt; '1',
        'maxBlocks' =&gt; '',
        'localizeBlocks' =&gt; false,
    )
]);

try {
    Craft::$app-&gt;getFields()-&gt;saveField($field);
}
catch (\Throwable $e){
    echo $e-&gt;getMessage();
}

//Set new block type(s) and add sub-fields to it
$field-&gt;setBlockTypes(array(
    'new1' =&gt; array(
        'name' =&gt; "A Block",
        'handle' =&gt; "aBlock",
        'fields' =&gt; array(
            'new1' =&gt; array(
                'type' =&gt; PlainText::class,
                'name' =&gt; 'First Subfield',
                'handle' =&gt; 'firstSubfield',
                'instructions' =&gt; '',
                'required' =&gt; false,
                'typesettings' =&gt; array (
                    'multiline' =&gt; ''
                )
            ) 
        )
    )
);

//Save field with new block type and sub-fields settings
try{
    Craft::$app-&gt;matrix-&gt;saveSettings($field);
}
catch(\Throwable $e){
    echo $this-&gt;failed;
}
</code></pre>

CC BY-SA 4.0
2018-07-17T18:32:30.577Z
2018-07-19T16:35:18.147Z
2018-07-19T16:35:18.147Z
danbrellis
<p>I got the code working by using the following, without using the saveSettings method:</p>

<pre class="lang-php prettyprint-override"><code>$field = new FieldModel();
$field-&gt;groupId      = 1;
$field-&gt;name         = Craft::t('Field Name');
$field-&gt;handle       = 'handleName';
$field-&gt;translatable = false;
$field-&gt;type         = 'Matrix';

craft()-&gt;fields-&gt;saveField($field);

$settings = new MatrixSettingsModel($field);

$blockType = new MatrixBlockTypeModel();
$blockType-&gt;fieldId = $field-&gt;id;
$blockType-&gt;name = Craft::t('blockTypeName');
$blockType-&gt;handle = 'blockTypeHandle';

$mySubField1 = new FieldModel();
$mySubField1-&gt;name         = 'My Sub-Field 1';
$mySubField1-&gt;handle       = 'mySubField1a';
$mySubField1-&gt;required     = true;
$mySubField1-&gt;translatable = false;
$mySubField1-&gt;type         = 'PlainText';
$mySubField1-&gt;settings     = array('multiline' =&gt; false);

$mySubField2 = new FieldModel();
$mySubField2-&gt;name         = 'My Sub-Field 2';
$mySubField2-&gt;handle       = 'mySubField2a';
$mySubField2-&gt;required     = true;
$mySubField2-&gt;translatable = false;
$mySubField2-&gt;type         = 'PlainText';
$mySubField2-&gt;settings     = array('multiline' =&gt; true);

$blockType-&gt;setFields(array($mySubField1, $mySubField2));

craft()-&gt;matrix-&gt;saveBlockType($blockType);
$settings-&gt;setBlockTypes(array($blockType));
$success = craft()-&gt;matrix-&gt;saveSettings($settings);
</code></pre>

CC BY-SA 3.0
2014-08-07T10:14:56.307Z
Yeah that would work as well. The MySQL error you were getting was because I forgot `saveField()` is already going to end up calling MatrixService::saveSettings() for you, which will create the content table, albeit without any actual columns yet.
Brandon Kelly
CC BY-SA 3.0
2014-08-07T04:47:08.623Z
2014-08-07T10:15:51.170Z
2014-08-07T10:15:51.170Z
Anthony
<p>Creating the field/block types manually is only part of the equation - you would also need to create the new content table for your Matrix field.</p>

<p>All you need to do is assign all of your block types and their sub-fields’ settings to <code>$field-&gt;settings</code> before calling <code>saveField()</code>:</p>

<pre class="lang-php prettyprint-override"><code>$field = new FieldModel();
$field-&gt;groupId      = 1;
$field-&gt;name         = Craft::t('Field Name');
$field-&gt;handle       = 'handleName';
$field-&gt;translatable = false;
$field-&gt;type         = 'Matrix';

$field-&gt;settings = array(
    'blockTypes' =&gt; array(
        'new1' =&gt; array(
            'name' =&gt; 'My Block Type 1',
            'handle' =&gt; 'myBlockType1',
            'fields' =&gt; array(
                'new1' =&gt; array(
                    'name' =&gt; 'My Sub-Field 1',
                    'handle' =&gt; 'mySubField1',
                    'required' =&gt; true,
                    'translatable' =&gt; false,
                    'type' =&gt; 'PlainText',
                    'typesettings' =&gt; array(
                        'multiline' =&gt; false,
                    )
                ),
                'new2' =&gt; array(
                    'name' =&gt; 'My Sub-Field 2',
                    'handle' =&gt; 'mySubField2',
                    'required' =&gt; false,
                    'translatable' =&gt; false,
                    'type' =&gt; 'PlainText',
                    'typesettings' =&gt; array(
                        'multiline' =&gt; true,
                    )
                ),
            )
        )
    )
);

craft()-&gt;fields-&gt;saveField($field);
</code></pre>

CC BY-SA 3.0
2014-08-07T00:35:55.670Z
Thanks Brandon! When I install the plugin, I get an CDbException on the SQL statement: Base table or view already exists: 1050 Table 'craft_matrixcontent_handlename' already exists.
Anthony
CC BY-SA 3.0
2014-08-07T01:01:14.840Z
Well, try removing that DB table first ;)
Brandon Kelly
CC BY-SA 3.0
2014-08-07T01:05:40.193Z
Yes I've tried that. Even with brand new unique handles, it throws the same error. It looks like the saveSettings method is trying to save the matrix field which was originally created with: craft()->fields->saveField($field);
Anthony
CC BY-SA 3.0
2014-08-07T01:19:41.783Z
Any chance your code is getting run twice?
Brandon Kelly
CC BY-SA 3.0
2014-08-07T01:27:28.957Z
I don't think so, my test is just a straight copy & paste of the 3 code blocks provided in the onAfterInstall method.
Anthony
CC BY-SA 3.0
2014-08-07T10:08:52.567Z
@Anthony Sorry, figured out the issue with that previous code, and also realized that the easiest way to go about this is to just pass everything into `$field->settings` before calling `saveField()`. Just updated my answer with simple, working code.
Brandon Kelly
CC BY-SA 3.0
2014-09-02T17:51:13.703Z
@BrandonKelly This looks like just what I need but I'm having a problem with it: although I can add multiple fields to a single blockType, as soon as I try to add a second blockType (ie. add a new item to the 'blockTypes' array) I get the error message `No field exists with the ID “1”` - any idea what I might be doing wrong at all? Thanks!
Nick F
CC BY-SA 3.0
2014-09-02T17:55:23.630Z
@NickF Could be a Craft bug. Can you send your plugin to support@buildwithcraft.com ?
Brandon Kelly
CC BY-SA 3.0
2014-09-03T10:03:01.077Z
@BrandonKelly Ok, sent! Thanks. The problem, it turns out, is slightly different from what I thought it was, but I've explained in the email how to replicate it.
Nick F
CC BY-SA 3.0
2014-08-06T12:40:10.303Z
2014-09-03T14:29:09.437Z
2014-09-03T14:29:09.437Z
Brandon Kelly
<p>I'm developing a plugin which requires certain sections and fields to exist so I'm currently creating them in the <code>onAfterInstall()</code> method of the plugin.</p>

<p>I can create individual fields, sections, entry types and even a Matrix field + block type fine. I'm having trouble with creating the Matrix sub-field and attaching that field to the Matrix block type.</p>

<p>I have created the matrix field:</p>

<pre><code>$field = new FieldModel();
$field-&gt;groupId      = $group-&gt;id;
$field-&gt;name         = Craft::t('Field Name');
$field-&gt;handle       = 'handleName';
$field-&gt;translatable = false;
$field-&gt;type         = 'Matrix';
craft()-&gt;fields-&gt;saveField($fieldContentRSS);
</code></pre>

<p>And this is the block type:</p>

<pre><code>$blockType = new MatrixBlockTypeModel();
$blockType-&gt;fieldId = $field-&gt;id;
$blockType-&gt;name = Craft::t('Block Name');
$blockType-&gt;handle = 'handleName';
craft()-&gt;matrix-&gt;saveBlockType($blockType);
</code></pre>

<p>I know that I will need to create a field/set of fields for this block type. Is this exactly the same as the new field above? How do I then attach these fields to the block type?</p>

<plugin-development><matrix>
Programatically create a Matrix field
# Programatically create a Matrix field

(Asked by: username_0 on 2014-08-05)

I'm developing a plugin which requires certain sections and fields to exist so I'm currently creating them in the onAfterInstall() method of the plugin.
I can create individual fields, sections, entry types and even a Matrix field + block type fine. I'm having trouble with creating the Matrix sub-field and attaching that field to the Matrix block type.
I have created the matrix field:
$field = new FieldModel();
$field->groupId      = $group->id;
$field->name         = Craft::t('Field Name');
$field->handle       = 'handleName';
$field->translatable = false;
$field->type         = 'Matrix';
craft()->fields->saveField($fieldContentRSS);

And this is the block type:
$blockType = new MatrixBlockTypeModel();
$blockType->fieldId = $field->id;
$blockType->name = Craft::t('Block Name');
$blockType->handle = 'handleName';
craft()->matrix->saveBlockType($blockType);

I know that I will need to create a field/set of fields for this block type. Is this exactly the same as the new field above? How do I then attach these fields to the block type?

**Tags:** plugin-development, matrix

---

## 3 answers

### Answer by username_2 on 2014-08-06. Score: 10 | Accepted answer

Creating the field/block types manually is only part of the equation - you would also need to create the new content table for your Matrix field.
All you need to do is assign all of your block types and their sub-fields’ settings to $field->settings before calling saveField():
$field = new FieldModel();
$field->groupId      = 1;
$field->name         = Craft::t('Field Name');
$field->handle       = 'handleName';
$field->translatable = false;
$field->type         = 'Matrix';

$field->settings = array(
    'blockTypes' => array(
        'new1' => array(
            'name' => 'My Block Type 1',
            'handle' => 'myBlockType1',
            'fields' => array(
                'new1' => array(
                    'name' => 'My Sub-Field 1',
                    'handle' => 'mySubField1',
                    'required' => true,
                    'translatable' => false,
                    'type' => 'PlainText',
                    'typesettings' => array(
                        'multiline' => false,
                    )
                ),
                'new2' => array(
                    'name' => 'My Sub-Field 2',
                    'handle' => 'mySubField2',
                    'required' => false,
                    'translatable' => false,
                    'type' => 'PlainText',
                    'typesettings' => array(
                        'multiline' => true,
                    )
                ),
            )
        )
    )
);

craft()->fields->saveField($field);

> **Comments:**
> **username_0**: Thanks Brandon! When I install the plugin, I get an CDbException on the SQL statement: Base table or view already exists: 1050 Table 'craft_matrixcontent_handlename' already exists.  
> **username_2**: Well, try removing that DB table first ;)  
> **username_0**: Yes I've tried that. Even with brand new unique handles, it throws the same error. It looks like the saveSettings method is trying to save the matrix field which was originally created with: craft()->fields->saveField($field);  
> **username_2**: Any chance your code is getting run twice?  
> **username_0**: I don't think so, my test is just a straight copy & paste of the 3 code blocks provided in the onAfterInstall method.  
> **username_2**: @Anthony Sorry, figured out the issue with that previous code, and also realized that the easiest way to go about this is to just pass everything into `$field->settings` before calling `saveField()`. Just updated my answer with simple, working code.  
> **username_3**: @BrandonKelly This looks like just what I need but I'm having a problem with it: although I can add multiple fields to a single blockType, as soon as I try to add a second blockType (ie. add a new item to the 'blockTypes' array) I get the error message `No field exists with the ID “1”` - any idea what I might be doing wrong at all? Thanks!  
> **username_2**: @NickF Could be a Craft bug. Can you send your plugin to support@buildwithcraft.com ?  
> **username_3**: @BrandonKelly Ok, sent! Thanks. The problem, it turns out, is slightly different from what I thought it was, but I've explained in the email how to replicate it.  

---

### Answer by username_1 on 2018-07-17. Score: 6

FYI, this is how it's done in Craft 3:
use craft\fields\Matrix;
use craft\fields\PlainText;

//Create the matrix field 
$field = Craft::$app->getFields()->createField([
    'type' => Matrix::class,
    'groupId' => 1,
    'name' => 'My Matrix Field',
    'handle' => 'myMatrixField',
    'settings' => array (
        'minBlocks' => '1',
        'maxBlocks' => '',
        'localizeBlocks' => false,
    )
]);

try {
    Craft::$app->getFields()->saveField($field);
}
catch (\Throwable $e){
    echo $e->getMessage();
}

//Set new block type(s) and add sub-fields to it
$field->setBlockTypes(array(
    'new1' => array(
        'name' => "A Block",
        'handle' => "aBlock",
        'fields' => array(
            'new1' => array(
                'type' => PlainText::class,
                'name' => 'First Subfield',
                'handle' => 'firstSubfield',
                'instructions' => '',
                'required' => false,
                'typesettings' => array (
                    'multiline' => ''
                )
            ) 
        )
    )
);

//Save field with new block type and sub-fields settings
try{
    Craft::$app->matrix->saveSettings($field);
}
catch(\Throwable $e){
    echo $this->failed;
}


---

### Answer by username_0 on 2014-08-07. Score: 4

I got the code working by using the following, without using the saveSettings method:
$field = new FieldModel();
$field->groupId      = 1;
$field->name         = Craft::t('Field Name');
$field->handle       = 'handleName';
$field->translatable = false;
$field->type         = 'Matrix';

craft()->fields->saveField($field);

$settings = new MatrixSettingsModel($field);

$blockType = new MatrixBlockTypeModel();
$blockType->fieldId = $field->id;
$blockType->name = Craft::t('blockTypeName');
$blockType->handle = 'blockTypeHandle';

$mySubField1 = new FieldModel();
$mySubField1->name         = 'My Sub-Field 1';
$mySubField1->handle       = 'mySubField1a';
$mySubField1->required     = true;
$mySubField1->translatable = false;
$mySubField1->type         = 'PlainText';
$mySubField1->settings     = array('multiline' => false);

$mySubField2 = new FieldModel();
$mySubField2->name         = 'My Sub-Field 2';
$mySubField2->handle       = 'mySubField2a';
$mySubField2->required     = true;
$mySubField2->translatable = false;
$mySubField2->type         = 'PlainText';
$mySubField2->settings     = array('multiline' => true);

$blockType->setFields(array($mySubField1, $mySubField2));

craft()->matrix->saveBlockType($blockType);
$settings->setBlockTypes(array($blockType));
$success = craft()->matrix->saveSettings($settings);

> **Comments:**
> **username_2**: Yeah that would work as well. The MySQL error you were getting was because I forgot `saveField()` is already going to end up calling MatrixService::saveSettings() for you, which will create the content table, albeit without any actual columns yet.  

---

