Answers.Body: <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>
  
Answers.ContentLicense: CC BY-SA 4.0
Answers.CreationDate: 2018-07-17T18:32:30.577Z
Answers.LastActivityDate: 2018-07-19T16:35:18.147Z
Answers.LastEditDate: 2018-07-19T16:35:18.147Z
Answers.UserDisplayName: danbrellis
Answers.Body: <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>
  
Answers.ContentLicense: CC BY-SA 3.0
Answers.CreationDate: 2014-08-07T10:14:56.307Z
Answers.Text: 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.
Answers.UserDisplayName: Brandon Kelly
Answers.ContentLicense: CC BY-SA 3.0
Answers.CreationDate: 2014-08-07T04:47:08.623Z
Answers.LastActivityDate: 2014-08-07T10:15:51.170Z
Answers.LastEditDate: 2014-08-07T10:15:51.170Z
Answers.UserDisplayName: Anthony
Answers.Body: <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>
  
Answers.ContentLicense: CC BY-SA 3.0
Answers.CreationDate: 2014-08-07T00:35:55.670Z
Answers.Text: 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.
Answers.UserDisplayName: Anthony
Answers.ContentLicense: CC BY-SA 3.0
Answers.CreationDate: 2014-08-07T01:01:14.840Z
Answers.Text: Well, try removing that DB table first ;)
Answers.UserDisplayName: Brandon Kelly
Answers.ContentLicense: CC BY-SA 3.0
Answers.CreationDate: 2014-08-07T01:05:40.193Z
Answers.Text: 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);
Answers.UserDisplayName: Anthony
Answers.ContentLicense: CC BY-SA 3.0
Answers.CreationDate: 2014-08-07T01:19:41.783Z
Answers.Text: Any chance your code is getting run twice?
Answers.UserDisplayName: Brandon Kelly
Answers.ContentLicense: CC BY-SA 3.0
Answers.CreationDate: 2014-08-07T01:27:28.957Z
Answers.Text: I don't think so, my test is just a straight copy & paste of the 3 code blocks provided in the onAfterInstall method.
Answers.UserDisplayName: Anthony
Answers.ContentLicense: CC BY-SA 3.0
Answers.CreationDate: 2014-08-07T10:08:52.567Z
Answers.Text: @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.
Answers.UserDisplayName: Brandon Kelly
Answers.ContentLicense: CC BY-SA 3.0
Answers.CreationDate: 2014-09-02T17:51:13.703Z
Answers.Text: @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!
Answers.UserDisplayName: Nick F
Answers.ContentLicense: CC BY-SA 3.0
Answers.CreationDate: 2014-09-02T17:55:23.630Z
Answers.Text: @NickF Could be a Craft bug. Can you send your plugin to support@buildwithcraft.com ?
Answers.UserDisplayName: Brandon Kelly
Answers.ContentLicense: CC BY-SA 3.0
Answers.CreationDate: 2014-09-03T10:03:01.077Z
Answers.Text: @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.
Answers.UserDisplayName: Nick F
Answers.ContentLicense: CC BY-SA 3.0
Answers.CreationDate: 2014-08-06T12:40:10.303Z
Answers.LastActivityDate: 2014-09-03T14:29:09.437Z
Answers.LastEditDate: 2014-09-03T14:29:09.437Z
Answers.UserDisplayName: Brandon Kelly
Body: <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>
  
Tags: <plugin-development><matrix>
Title: Programatically create a Matrix field
ThreadText: # 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()`:
  
  ```php
  $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 username_2! 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**: @username_0 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**: @username_2 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**: @username_3 Could be a Craft bug. Can you send your plugin to support@buildwithcraft.com ?  
  > **username_3**: @username_2 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:
  
  ```php
  $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.  
  
  ---
  
  