Answers.Body: <p>I've also run into this problem. I've checked the API documentation both for <a href="https://docs.craftcms.com/api/v3/craft-elements-entry.html" rel="nofollow noreferrer">craft\elements\Entry</a> and <a href="https://docs.craftcms.com/api/v3/craft-base-element.html" rel="nofollow noreferrer">craft\base\Element</a> and neither seem to have a simple, straightforward method to check if a field exists. Here are a couple of options I have found:</p>
  <h2>Getting the list of fields</h2>
  <p>You can get the list of fields by going through the field layout:</p>
  <pre class="lang-php prettyprint-override"><code>// this works with any element
  $elementFields = $element-&gt;getFieldLayout()-&gt;getFields();
  
  // this works only with entries
  $entryFields = $entry-&gt;getType()-&gt;getFieldLayout()-&gt;getFields();
  
  // transform the array of Field objects into an array of field handles for convenience
  $entryFieldHandles = array_column($entryFields, 'handle');
  
  // check if the entry has my_custom_field
  $entryHasMyCustomField = in_array('my_custom_field', $entryFieldHandles);
  </code></pre>
  <p>This also works well in Twig:</p>
  <pre><code>{% set entry_field_handles = entry.getFieldLayout().getFields()|column('handle') %}
  {% set entry_has_field = 'my_custom_field' in entry_field_handles %}
  </code></pre>
  <p>Downside: May be slow, is a bit verbose, not sure how it interacts with different entry types in a section.</p>
  <h2>Going through the CustomFieldBehavior</h2>
  <p>Craft 3 compiles all your fields to the class <code>CustomFieldBehavior</code>, which is then attached to the <code>Element</code> object as a <a href="https://craftcms.com/docs/3.x/extend/extending-system-components.html#behaviors" rel="nofollow noreferrer">behavior</a>. This class has properties for each custom field and a method <code>canGetProperty</code> which you can use to check if a particular property exists:</p>
  <pre class="lang-php prettyprint-override"><code>$entryHasMyCustomField = $entry-&gt;getBehavior('customFields')
                                 -&gt;canGetProperty('my_custom_field');
  </code></pre>
  <p>Downsides: Uses undocumented methods / behavior which might change. There <em>might</em> also be some edge-cases if the CustomFieldBehavior class has different properties that aren't fields but match any of your field names, though that's pretty unlikely.</p>
  <h2>Catching the error</h2>
  <p>Simple but effective:</p>
  <pre class="lang-php prettyprint-override"><code>try {
      $fieldValue = $entry-&gt;getFieldValue('my_custom_field');
  } catch (\craft\errors\InvalidFieldException $error) {
      // field doesn't exist
  }
  </code></pre>
  <p>Downside: Really ugly and verbose.</p>
  
Answers.ContentLicense: CC BY-SA 4.0
Answers.CreationDate: 2021-05-18T09:46:22.617Z
Answers.Text: Haha, 1 minute behind but great minds :)
Answers.UserDisplayName: Wallace
Answers.ContentLicense: CC BY-SA 4.0
Answers.CreationDate: 2021-05-18T09:47:58.027Z
Answers.Text: @Andy You're too fast for me ^^
Answers.UserDisplayName: MoritzLost
Answers.ContentLicense: CC BY-SA 4.0
Answers.CreationDate: 2021-05-18T09:51:34.263Z
Answers.Text: The only correction I'd make to your first option is to get the field layout for the entry _type_, not just the entry.
Answers.UserDisplayName: Wallace
Answers.ContentLicense: CC BY-SA 4.0
Answers.CreationDate: 2021-05-18T10:06:11.160Z
Answers.Text: @Andy Thanks for the tip, I've updated my example code. One thing that's bugging me is that `EntryType::getFieldLayout()` [isn't documented at all](https://docs.craftcms.com/api/v3/craft-models-entrytype.html#public-methods). Probably because the field layout is attached as a behavior. Though it feels icky to use undocumented methods like that.
Answers.UserDisplayName: MoritzLost
Answers.ContentLicense: CC BY-SA 4.0
Answers.CreationDate: 2021-05-18T23:59:15.737Z
Answers.Text: Perfect, exactly what I was looking for!
Answers.UserDisplayName: Mark Lloyd
Answers.ContentLicense: CC BY-SA 4.0
Answers.CreationDate: 2021-05-18T09:44:24.477Z
Answers.LastActivityDate: 2021-08-09T10:10:50.873Z
Answers.LastEditDate: 2021-08-09T10:10:50.873Z
Answers.UserDisplayName: MoritzLost
Answers.Body: <p>Without modifying your code too much, you could simply add an exception handler with a try/catch block.</p>
  <p>Another method would be to retrieve the field handles for the entry type's field layout, and check for a match:</p>
  <p>Getting the $entryType as necessary,</p>
  <pre><code>$etFieldHandles = [];
  $fields = $entryType-&gt;getFieldLayout()-&gt;getFields();
  foreach ($fields as $field) {
      $etFieldHandles[] = $field-&gt;handle;
  }
  
  if (in_array('yourfieldhandle', $etFieldHandles) ) {
      // the field exists in this entry type's layout.
  }
  </code></pre>
  
Answers.ContentLicense: CC BY-SA 4.0
Answers.CreationDate: 2021-05-18T23:59:36.423Z
Answers.Text: This is exactly what I was after, thanks!
Answers.UserDisplayName: Mark Lloyd
Answers.ContentLicense: CC BY-SA 4.0
Answers.CreationDate: 2021-05-18T09:42:57.653Z
Answers.LastActivityDate: 2021-05-18T09:42:57.653Z
Answers.UserDisplayName: Wallace
Answers.Body: <h2>Update for Craft 4</h2>
  <pre><code>$entry-&gt;getFieldLayout()-&gt;getFieldByHandle('fieldHandle');
  </code></pre>
  <p><a href="https://docs.craftcms.com/api/v4/craft-models-fieldlayout.html#public-methods" rel="nofollow noreferrer">https://docs.craftcms.com/api/v4/craft-models-fieldlayout.html#public-methods</a></p>
  
Answers.ContentLicense: CC BY-SA 4.0
Answers.CreationDate: 2023-11-29T22:11:38.037Z
Answers.LastActivityDate: 2023-11-29T22:11:38.037Z
Answers.UserDisplayName: comtyler
Body: <p>I've been pulling my hair out trying to work this one out.</p>
  <p>I'm building a module to auto-populate a super-table on EVENT_BEFORE_SAVE, the module works exactly the way I want it to, everything seems to be working fine.</p>
  <p>Except Craft throws a &quot;Invalid field handle:&quot; exception if the custom field doesn't exist on that entry.</p>
  <p>I've tried to check if the field exists with a few different methods, but anything that directly references the fieldhandle seems to throw an exception.</p>
  <p>What's the proper way of checking if a field exists and running the code if it does?</p>
  
Tags: <modules>
Title: Check if a FieldHandle exists in Module without throwing 'Invalid field handle' exceptions
ThreadText: # Check if a FieldHandle exists in Module without throwing 'Invalid field handle' exceptions
  
  (Asked by: username_0 on 2021-05-18)
  
  I've been pulling my hair out trying to work this one out.
  
  I'm building a module to auto-populate a super-table on EVENT\_BEFORE\_SAVE, the module works exactly the way I want it to, everything seems to be working fine.
  
  Except Craft throws a "Invalid field handle:" exception if the custom field doesn't exist on that entry.
  
  I've tried to check if the field exists with a few different methods, but anything that directly references the fieldhandle seems to throw an exception.
  
  What's the proper way of checking if a field exists and running the code if it does?
  
  **Tags:** modules
  
  
  ---
  
  ## 3 answers
  
  ### Answer by username_1 on 2021-05-18. Score: 2 | Accepted answer
  
  I've also run into this problem. I've checked the API documentation both for [craft\elements\Entry](https://docs.craftcms.com/api/v3/craft-elements-entry.html) and [craft\base\Element](https://docs.craftcms.com/api/v3/craft-base-element.html) and neither seem to have a simple, straightforward method to check if a field exists. Here are a couple of options I have found:
  
  ## Getting the list of fields
  
  You can get the list of fields by going through the field layout:
  
  ```php
  // this works with any element
  $elementFields = $element->getFieldLayout()->getFields();
  
  // this works only with entries
  $entryFields = $entry->getType()->getFieldLayout()->getFields();
  
  // transform the array of Field objects into an array of field handles for convenience
  $entryFieldHandles = array_column($entryFields, 'handle');
  
  // check if the entry has my_custom_field
  $entryHasMyCustomField = in_array('my_custom_field', $entryFieldHandles);
  
  ```
  
  This also works well in Twig:
  
  ```
  {% set entry_field_handles = entry.getFieldLayout().getFields()|column('handle') %}
  {% set entry_has_field = 'my_custom_field' in entry_field_handles %}
  
  ```
  
  Downside: May be slow, is a bit verbose, not sure how it interacts with different entry types in a section.
  
  ## Going through the CustomFieldBehavior
  
  Craft 3 compiles all your fields to the class `CustomFieldBehavior`, which is then attached to the `Element` object as a [behavior](https://craftcms.com/docs/3.x/extend/extending-system-components.html#behaviors). This class has properties for each custom field and a method `canGetProperty` which you can use to check if a particular property exists:
  
  ```php
  $entryHasMyCustomField = $entry->getBehavior('customFields')
                                 ->canGetProperty('my_custom_field');
  
  ```
  
  Downsides: Uses undocumented methods / behavior which might change. There *might* also be some edge-cases if the CustomFieldBehavior class has different properties that aren't fields but match any of your field names, though that's pretty unlikely.
  
  ## Catching the error
  
  Simple but effective:
  
  ```php
  try {
      $fieldValue = $entry->getFieldValue('my_custom_field');
  } catch (\craft\errors\InvalidFieldException $error) {
      // field doesn't exist
  }
  
  ```
  
  Downside: Really ugly and verbose.
  
  > **Comments:**
  > **username_2**: Haha, 1 minute behind but great minds :)  
  > **username_1**: @Andy You're too fast for me ^^  
  > **username_2**: The only correction I'd make to your first option is to get the field layout for the entry _type_, not just the entry.  
  > **username_1**: @Andy Thanks for the tip, I've updated my example code. One thing that's bugging me is that `EntryType::getFieldLayout()` [isn't documented at all](https://docs.craftcms.com/api/v3/craft-models-entrytype.html#public-methods). Probably because the field layout is attached as a behavior. Though it feels icky to use undocumented methods like that.  
  > **username_0**: Perfect, exactly what I was looking for!  
  
  ---
  
  ### Answer by username_2 on 2021-05-18. Score: 2
  
  Without modifying your code too much, you could simply add an exception handler with a try/catch block.
  
  Another method would be to retrieve the field handles for the entry type's field layout, and check for a match:
  
  Getting the $entryType as necessary,
  
  ```
  $etFieldHandles = [];
  $fields = $entryType->getFieldLayout()->getFields();
  foreach ($fields as $field) {
      $etFieldHandles[] = $field->handle;
  }
  
  if (in_array('yourfieldhandle', $etFieldHandles) ) {
      // the field exists in this entry type's layout.
  }
  
  ```
  
  > **Comments:**
  > **username_0**: This is exactly what I was after, thanks!  
  
  ---
  
  ### Answer by username_3 on 2023-11-29. Score: 1
  
  ## Update for Craft 4
  
  ```
  $entry->getFieldLayout()->getFieldByHandle('fieldHandle');
  
  ```
  
  <https://docs.craftcms.com/api/v4/craft-models-fieldlayout.html#public-methods>
  
  
  ---
  
  