Answers.Body: <p>The main issue here ended up being a Craft bug (<a href="https://github.com/craftcms/cms/issues/6651" rel="nofollow noreferrer">craftcms/cms#6651</a>), which has been fixed for the next release (3.5.5).</p>
  <p>There are a couple ways your code could be improved as well, though:</p>
  <ul>
  <li><p><code>$fieldGroup</code> is a <a href="https://docs.craftcms.com/api/v3/craft-models-fieldgroup.html" rel="nofollow noreferrer">craft\models\FieldGroup</a> object, not an array, so you should access its ID via <code>$fieldGroup-&gt;id</code>, not <code>$fieldGroup['id']</code>. (Or just use the <code>$groupId</code> property.)</p>
  </li>
  <li><p>Avoid using <code>===</code> for numeric properties like <code>id</code>, unless you know for certain what the type is going to be. IDs <em>should</em> be casted as integers, not strings, and places where they are strings should be considered a minor bug. (It’s due to how MySQL returns the data, but not an issue in PostgreSQL, and we are working toward always ensuring that they are typed as ints correctly even for MySQL.) Safest thing for you to do is replace <code>===</code> with <code>==</code> on this line:</p>
  <pre class="lang-php prettyprint-override"><code>if ($entryType-&gt;id === '2') {
  </code></pre>
  </li>
  <li><p>Your two <code>continue</code> statements should be <code>break</code>. <code>continue</code> just tells the loop to move onto the next cycle of the loop; <code>break</code> tells it to completely break out of the loop.</p>
  </li>
  <li><p><code>$tabsForSaving</code> is never defined. I’m surprised that’s not causing a PHP error for you.</p>
  </li>
  </ul>
  
Answers.ContentLicense: CC BY-SA 4.0
Answers.CreationDate: 2020-08-18T17:19:25.377Z
Answers.Text: Cheers for the code review. Ah yes I stripped `$tabsForSaving` out, discovered that I did not need to call `setTabs` again on the layout for my new fields to be saved to the layout.
Answers.UserDisplayName: joep
Answers.ContentLicense: CC BY-SA 4.0
Answers.CreationDate: 2020-08-17T15:31:34.913Z
Answers.LastActivityDate: 2020-08-17T15:31:34.913Z
Answers.UserDisplayName: Brandon Kelly
Body: <p>as part of a migration script I'm trying to:</p>
  <ol>
  <li>create 2 new fields,</li>
  <li>add them to a field group</li>
  <li>add the new fields to a specific tab on an entry type</li>
  <li>Update the values of the new fields</li>
  </ol>
  <p>What I have so far works up until point 4, in the database the fields exist on the entry, I can see them there when I browse to an entry in the CMS, I can save new values to them, but, I cannot set a value with <code>setFieldValues</code> straight after. Can anyone suggest what I've done wrong here?</p>
  <p>Here is my code so far:</p>
  <pre class="lang-php prettyprint-override"><code>public function safeUp()
  {
      // Get contact field group
      $groupId = 31; // contact field group
      $fields = Craft::$app-&gt;getFields(); // Get fields
      $fieldGroup = $fields-&gt;getGroupById($groupId); // Get contact field group
  
      // Create heading field
      $headingFieldHandle = 'contactThanksHeading';
      $headingField = new PlainText([
          'groupId' =&gt; $fieldGroup['id'],
          'name' =&gt; 'Contact Thanks Heading',
          'handle' =&gt; $headingFieldHandle,
          &quot;instructions&quot; =&gt; &quot;Larger heading text for the contact form's thanks message&quot;,
          &quot;required&quot; =&gt; false,
          &quot;placeholder&quot; =&gt; &quot;Thank you&quot;,
          &quot;charLimit&quot; =&gt; 300,
          &quot;multiline&quot; =&gt; false,
          &quot;initialRows&quot; =&gt; &quot;4&quot;,
      ]);
      // Save heading field
      Craft::$app-&gt;getFields()-&gt;saveField($headingField);
  
      // Create copy field
      $copyFieldHandle = 'contactThanksCopy';
      $copyField = new PlainText([
          'groupId' =&gt; $fieldGroup['id'],
          'name' =&gt; 'Contact Thanks Copy',
          'handle' =&gt; $copyFieldHandle,
          &quot;instructions&quot; =&gt; &quot;Smaller copy text for the contact form's thanks message&quot;,
          &quot;required&quot; =&gt; false,
          &quot;placeholder&quot; =&gt; &quot;One of our team will get back shortly...&quot;,
          &quot;charLimit&quot; =&gt; 300,
          &quot;multiline&quot; =&gt; true,
          &quot;initialRows&quot; =&gt; &quot;4&quot;,
      ]);
      // Save copy field
      Craft::$app-&gt;getFields()-&gt;saveField($copyField);
  
      // Get contact single section
      $contactSection = Craft::$app-&gt;getSections()-&gt;getSectionById(2);
      // Get the section's entry types
      $contactEntryTypes = $contactSection-&gt;getEntryTypes();
  
      // Find entry type 2
      foreach ($contactEntryTypes as $entryType) {
          if ($entryType-&gt;id === '2') {
              $contactEntryType = $entryType;
              continue;
          }
      }
  
      // Get the field layout for entry type 2
      $contactFieldLayout = $contactEntryType-&gt;getFieldLayout(2);
      // Loop on tabs to find common
      foreach($contactFieldLayout-&gt;tabs as $tab) {
          if ($tab-&gt;name === 'Common') {
              $contactCommonTab = $tab;
              continue;
          }
      }
  
      // get the common tab's existing fields
      $tabFields = $contactCommonTab-&gt;getFields();
  
      // Set the sort order of the new fields to append them to the tab
      $headingField-&gt;sortOrder = count($tabFields);
      $copyField-&gt;sortOrder = count($tabFields)+1;
  
      // Add new fields to Common tab array
      $newFields = array_merge($tabFields,[$headingField, $copyField]);
      // Save fields to tab
      $contactCommonTab-&gt;setFields($newFields);
  
      // Set the tabs on the field layout
      $contactFieldLayout-&gt;setTabs($tabsForSaving);
  
      // Save the contact field layout
      Craft::$app-&gt;fields-&gt;saveLayout($contactFieldLayout);
  
      // get the contact entry
      $contactEntry = Craft::$app-&gt;entries-&gt;getEntryById(8);
      // Set the contact entry values
      $contactEntry-&gt;setFieldValues([
          $headingFieldHandle =&gt; '1',
          $copyFieldHandle =&gt; '1',
      ]);
      // save the contact entry
      Craft::$app-&gt;elements-&gt;saveElement($contactEntry);
  }
  </code></pre>
  
Tags: <plugin-development>
Title: unsucessful setFieldValues after programatically creating field on a migration
ThreadText: # unsucessful setFieldValues after programatically creating field on a migration
  
  (Asked by: username_0 on 2020-08-14)
  
  as part of a migration script I'm trying to:
  
  1. create 2 new fields,
  2. add them to a field group
  3. add the new fields to a specific tab on an entry type
  4. Update the values of the new fields
  
  What I have so far works up until point 4, in the database the fields exist on the entry, I can see them there when I browse to an entry in the CMS, I can save new values to them, but, I cannot set a value with `setFieldValues` straight after. Can anyone suggest what I've done wrong here?
  
  Here is my code so far:
  
  ```php
  public function safeUp()
  {
      // Get contact field group
      $groupId = 31; // contact field group
      $fields = Craft::$app->getFields(); // Get fields
      $fieldGroup = $fields->getGroupById($groupId); // Get contact field group
  
      // Create heading field
      $headingFieldHandle = 'contactThanksHeading';
      $headingField = new PlainText([
          'groupId' => $fieldGroup['id'],
          'name' => 'Contact Thanks Heading',
          'handle' => $headingFieldHandle,
          "instructions" => "Larger heading text for the contact form's thanks message",
          "required" => false,
          "placeholder" => "Thank you",
          "charLimit" => 300,
          "multiline" => false,
          "initialRows" => "4",
      ]);
      // Save heading field
      Craft::$app->getFields()->saveField($headingField);
  
      // Create copy field
      $copyFieldHandle = 'contactThanksCopy';
      $copyField = new PlainText([
          'groupId' => $fieldGroup['id'],
          'name' => 'Contact Thanks Copy',
          'handle' => $copyFieldHandle,
          "instructions" => "Smaller copy text for the contact form's thanks message",
          "required" => false,
          "placeholder" => "One of our team will get back shortly...",
          "charLimit" => 300,
          "multiline" => true,
          "initialRows" => "4",
      ]);
      // Save copy field
      Craft::$app->getFields()->saveField($copyField);
  
      // Get contact single section
      $contactSection = Craft::$app->getSections()->getSectionById(2);
      // Get the section's entry types
      $contactEntryTypes = $contactSection->getEntryTypes();
  
      // Find entry type 2
      foreach ($contactEntryTypes as $entryType) {
          if ($entryType->id === '2') {
              $contactEntryType = $entryType;
              continue;
          }
      }
  
      // Get the field layout for entry type 2
      $contactFieldLayout = $contactEntryType->getFieldLayout(2);
      // Loop on tabs to find common
      foreach($contactFieldLayout->tabs as $tab) {
          if ($tab->name === 'Common') {
              $contactCommonTab = $tab;
              continue;
          }
      }
  
      // get the common tab's existing fields
      $tabFields = $contactCommonTab->getFields();
  
      // Set the sort order of the new fields to append them to the tab
      $headingField->sortOrder = count($tabFields);
      $copyField->sortOrder = count($tabFields)+1;
  
      // Add new fields to Common tab array
      $newFields = array_merge($tabFields,[$headingField, $copyField]);
      // Save fields to tab
      $contactCommonTab->setFields($newFields);
  
      // Set the tabs on the field layout
      $contactFieldLayout->setTabs($tabsForSaving);
  
      // Save the contact field layout
      Craft::$app->fields->saveLayout($contactFieldLayout);
  
      // get the contact entry
      $contactEntry = Craft::$app->entries->getEntryById(8);
      // Set the contact entry values
      $contactEntry->setFieldValues([
          $headingFieldHandle => '1',
          $copyFieldHandle => '1',
      ]);
      // save the contact entry
      Craft::$app->elements->saveElement($contactEntry);
  }
  
  ```
  
  **Tags:** plugin-development
  
  
  ---
  
  ## 1 answers
  
  ### Answer by username_1 on 2020-08-17. Score: 3 | Accepted answer
  
  The main issue here ended up being a Craft bug ([craftcms/cms#6651](https://github.com/craftcms/cms/issues/6651)), which has been fixed for the next release (3.5.5).
  
  There are a couple ways your code could be improved as well, though:
  
  * `$fieldGroup` is a [craft\models\FieldGroup](https://docs.craftcms.com/api/v3/craft-models-fieldgroup.html) object, not an array, so you should access its ID via `$fieldGroup->id`, not `$fieldGroup['id']`. (Or just use the `$groupId` property.)
  * Avoid using `===` for numeric properties like `id`, unless you know for certain what the type is going to be. IDs *should* be casted as integers, not strings, and places where they are strings should be considered a minor bug. (It’s due to how MySQL returns the data, but not an issue in PostgreSQL, and we are working toward always ensuring that they are typed as ints correctly even for MySQL.) Safest thing for you to do is replace `===` with `==` on this line:
  
    ```php
    if ($entryType->id === '2') {
  
    ```
  * Your two `continue` statements should be `break`. `continue` just tells the loop to move onto the next cycle of the loop; `break` tells it to completely break out of the loop.
  * `$tabsForSaving` is never defined. I’m surprised that’s not causing a PHP error for you.
  
  > **Comments:**
  > **username_0**: Cheers for the code review. Ah yes I stripped `$tabsForSaving` out, discovered that I did not need to call `setTabs` again on the layout for my new fields to be saved to the layout.  
  
  ---
  
  