<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>

CC BY-SA 4.0
2021-05-18T09:46:22.617Z
Haha, 1 minute behind but great minds :)
Wallace
CC BY-SA 4.0
2021-05-18T09:47:58.027Z
@Andy You're too fast for me ^^
MoritzLost
CC BY-SA 4.0
2021-05-18T09:51:34.263Z
The only correction I'd make to your first option is to get the field layout for the entry _type_, not just the entry.
Wallace
CC BY-SA 4.0
2021-05-18T10:06:11.160Z
@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.
MoritzLost
CC BY-SA 4.0
2021-05-18T23:59:15.737Z
Perfect, exactly what I was looking for!
Mark Lloyd
CC BY-SA 4.0
2021-05-18T09:44:24.477Z
2021-08-09T10:10:50.873Z
2021-08-09T10:10:50.873Z
MoritzLost
<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>

CC BY-SA 4.0
2021-05-18T23:59:36.423Z
This is exactly what I was after, thanks!
Mark Lloyd
CC BY-SA 4.0
2021-05-18T09:42:57.653Z
2021-05-18T09:42:57.653Z
Wallace
<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>

CC BY-SA 4.0
2023-11-29T22:11:38.037Z
2023-11-29T22:11:38.037Z
comtyler
<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>

<modules>
Check if a FieldHandle exists in Module without throwing 'Invalid field handle' exceptions
# 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 and craft\base\Element 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:
// 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. This class has properties for each custom field and a method canGetProperty which you can use to check if a particular property exists:
$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:
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


---

