Answers.Body: <p>I believe I have a workaround and can (roughly) explain what's going on here.</p>
  
  <p>First, the workaround:</p>
  
  <p><strong>Use array syntax to test the existence of your custom fields instead of object syntax.</strong></p>
  
  <pre><code>{# This works #}
  {% if entry['someField'] is defined %} ... {% endif %}
  </code></pre>
  
  <p>Using array syntax for your conditional will result as true if your field does exist and false if it does not. Using object syntax results in false positives where the conditional always returns true even if a field doesn't exist:</p>
  
  <pre><code>{# FALSE POSITIVES: These return true if a field doesn't exist #}
  
  {% if entry.someField is defined %} ... {% endif %}
  {% if attribute(entry, 'someField') is defined %} ... {% endif %}
  </code></pre>
  
  <p>I believe the false positive occurs using object syntax when the object has or is extending another object that uses a <code>__call()</code> method. Twig will test to see if it can find an <code>attribute</code> or a <code>method</code>.  In the case it can't find an attribute on an object, it will look for a method.  And if it can't find a method on the object, it will check for the existence of a <code>__call()</code> method and if the <code>_call()</code> method exists it returns true, creating the undesired result of also returning true for any variable that doesn't exist on an object that uses a <code>__call()</code> method.</p>
  
  <p>I haven't dug into the code, but it seems that using the array syntax doesn't trigger a search for a potential method associated with the <code>__call()</code> behavior.</p>
  
  <hr>
  
  <p>A couple related articles can be found on Straight Up Craft:</p>
  
  <ul>
  <li><a href="https://straightupcraft.com/articles/how-to-check-if-a-variable-or-value-exists-using-twig" rel="noreferrer">How to check if a variable or value exists using Twig</a></li>
  <li><a href="https://straightupcraft.com/articles/testing-if-something-exists-is-defined-length-is-not-null-is-not-empty" rel="noreferrer">Testing if something exists: is defined, length, is not null, is not empty</a></li>
  </ul>
  
Answers.ContentLicense: CC BY-SA 3.0
Answers.CreationDate: 2016-01-18T19:34:03.553Z
Answers.Text: This should go into the official documentation! ... I just dumped several hours into researching this odd behaviour :(
Answers.UserDisplayName: m9dfukc
Answers.ContentLicense: CC BY-SA 3.0
Answers.CreationDate: 2016-03-21T10:02:47.240Z
Answers.Text: Sweet, that resolves it. Thanks for sharing!
Answers.UserDisplayName: medoingthings
Answers.ContentLicense: CC BY-SA 4.0
Answers.CreationDate: 2021-01-06T02:38:36.533Z
Answers.Text: This had me flummoxed, thank you!
Answers.UserDisplayName: Judd Lyon
Answers.ContentLicense: CC BY-SA 4.0
Answers.CreationDate: 2019-10-31T23:16:56.060Z
Answers.Text: 2019 and this is still an issue - and this appears to still be a work-around. Thanks!
Answers.UserDisplayName: Mike
Answers.ContentLicense: CC BY-SA 3.0
Answers.CreationDate: 2015-10-24T16:38:32.337Z
Answers.LastActivityDate: 2017-03-15T02:12:23.760Z
Answers.LastEditDate: 2017-03-15T02:12:23.760Z
Answers.UserDisplayName: Ben Parizek
Answers.Body: <p>I was able to resolve this issue by creating a custom plugin that uses a service and template variables. The service will accept the content object and field name. You can reference how to write a conditional to check if the field is set (<a href="http://buildwithcraft.com/classreference/models/BaseElementModel#getFieldValue-detail" rel="nofollow">http://buildwithcraft.com/classreference/models/BaseElementModel#getFieldValue-detail</a>). The service is then used in the template variables and will return true or false based on if the field is set.</p>
  
  <p>Craft Template Twig Example</p>
  
  <pre><code>{{ (craft.pluginName.isFieldDefined(e, 'someField') ? e.someField : false) }}
  </code></pre>
  
  <p>Sorry, I can't post a full code example.</p>
  
Answers.ContentLicense: CC BY-SA 3.0
Answers.CreationDate: 2015-03-04T19:15:26.307Z
Answers.LastActivityDate: 2015-03-04T20:27:19.063Z
Answers.LastEditDate: 2015-03-04T20:27:19.063Z
Answers.UserDisplayName: Mike Zens
Answers.Body: <p>I came across this while trying to check if object has method. I found out that <code>is defined</code> always returns true and some other options would return always null (even if the method existed) so I ended up writing a twig extension (which was faster than trying to solve the problem):</p>
  <pre><code>/**
   * @param object $entity
   * @param string $method
   *
   * @return bool
   */
  public function twig_method_exists($entity, string $method): bool
  {
      if (!is_object($entity)) {
          throw new InvalidArgumentException('Given entity is not of type object, got: '.get_class($entity));
      }
  
      if (empty($method)) {
          throw new InvalidArgumentException('Method name empty');
      }
  
      return method_exists($entity, $method);
  }
  
  </code></pre>
  <p>And i use it like this in the twig</p>
  <pre><code>{% if method_exists(entity, 'getCreatedBy') %}
      ({{ entity.createdBy.name }})
  {% endif %}
  </code></pre>
  
Answers.ContentLicense: CC BY-SA 4.0
Answers.CreationDate: 2020-08-21T08:19:15.343Z
Answers.LastActivityDate: 2020-08-21T08:19:15.343Z
Answers.UserDisplayName: Tuomas Valtonen
Answers.Body: <p>I had a similar issue when using an if statement to define a block element. The correct way doing this will be following:</p>
  
  <pre><code>{% block metaOgImage %}
    {% if og.image is defined %}
     &lt;meta property="og:image" content="{{ og.image }}"&gt;
    {% endif %}
  {% endblock %}
  </code></pre>
  
  <p>Do not use the if statement outside the block statement.</p>
  
Answers.ContentLicense: CC BY-SA 3.0
Answers.CreationDate: 2016-08-31T11:34:48.867Z
Answers.LastActivityDate: 2016-08-31T11:34:48.867Z
Answers.UserDisplayName: Stephan
Answers.Body: <p>This is a known issue with Twig’s ‘defined’ test - it’s not very reliable when it comes to object properties. We plan on looking further into it at some point and coming up with a formal test case that reproduces the issue, plus a bug fix. Just haven’t gotten around to it yet.</p>
  
  <p>In the meantime, rather than testing if a field is defined, check the entry type:</p>
  
  
  
  <pre class="lang-twig prettyprint-override"><code>{% if e.type == 'news' %}
  </code></pre>
  
  <p>If you want to check multiple entry/block types at once, you can use the <code>in</code> operator:</p>
  
  <pre class="lang-twig prettyprint-override"><code>{% if e.type.handle in ['news', 'blog'] %}
  </code></pre>
  
Answers.ContentLicense: CC BY-SA 3.0
Answers.CreationDate: 2015-02-13T01:47:04.193Z
Answers.Text: Is this still true? I have an environment where a field is assigned to an entry type, and another environment where it isn't—so the entry type check won't solve this. (Nevermind that my situation is questionable.)
Answers.UserDisplayName: Matt Stein
Answers.ContentLicense: CC BY-SA 3.0
Answers.CreationDate: 2015-02-18T14:28:06.947Z
Answers.Text: @MattStein Yeah. I recently spent some time trying to look into it again but Twig basically just assumes something actually is defined if it can’t be determined. In your case you would just need to add an additional check in the conditional for the environment. (You can give each environment config a custom `'env'` key set and check with `craft.config.env`.)
Answers.UserDisplayName: Brandon Kelly
Answers.ContentLicense: CC BY-SA 3.0
Answers.CreationDate: 2015-02-18T15:38:49.687Z
Answers.Text: @BrandonKelly So to Twig, a falling tree makes a sound no matter what. Thanks for the update and environment-check approach!
Answers.UserDisplayName: Matt Stein
Answers.ContentLicense: CC BY-SA 3.0
Answers.CreationDate: 2014-08-22T18:02:03.353Z
Answers.LastActivityDate: 2014-08-22T18:02:03.353Z
Answers.UserDisplayName: Brandon Kelly
Body: <p>I am trying to code defensively and check whether a field exists before accessing it:</p>
  
  <pre><code>{% if e.someField is defined %} {{e.someField}} {% endif %}
  </code></pre>
  
  <p>And I get a CException</p>
  
  <blockquote>
    <p>Craft\EntryModel and its behaviors do not have a method or closure named "someField".</p>
  </blockquote>
  
  <p>Because <a href="http://twig.sensiolabs.org/doc/templates.html#test-operator">is</a> <a href="http://twig.sensiolabs.org/doc/tests/defined.html">defined</a> is always returning <code>true</code>.</p>
  
  <p>Any clue what's wrong?</p>
  
Tags: <templating>
Title: Twig "is defined" always returning true
ThreadText: # Twig "is defined" always returning true
  
  (Asked by: username_0 on 2014-08-22)
  
  I am trying to code defensively and check whether a field exists before accessing it:
  
  ```
  {% if e.someField is defined %} {{e.someField}} {% endif %}
  
  ```
  
  And I get a CException
  
  > Craft\EntryModel and its behaviors do not have a method or closure named "someField".
  
  Because [is](http://twig.sensiolabs.org/doc/templates.html#test-operator) [defined](http://twig.sensiolabs.org/doc/tests/defined.html) is always returning `true`.
  
  Any clue what's wrong?
  
  **Tags:** templating
  
  
  ---
  
  ## 5 answers
  
  ### Answer by username_9 on 2014-08-22. Score: 10 | Accepted answer
  
  This is a known issue with Twig’s ‘defined’ test - it’s not very reliable when it comes to object properties. We plan on looking further into it at some point and coming up with a formal test case that reproduces the issue, plus a bug fix. Just haven’t gotten around to it yet.
  
  In the meantime, rather than testing if a field is defined, check the entry type:
  
  ```twig
  {% if e.type == 'news' %}
  
  ```
  
  If you want to check multiple entry/block types at once, you can use the `in` operator:
  
  ```twig
  {% if e.type.handle in ['news', 'blog'] %}
  
  ```
  
  > **Comments:**
  > **username_10**: Is this still true? I have an environment where a field is assigned to an entry type, and another environment where it isn't—so the entry type check won't solve this. (Nevermind that my situation is questionable.)  
  > **username_9**: @username_10 Yeah. I recently spent some time trying to look into it again but Twig basically just assumes something actually is defined if it can’t be determined. In your case you would just need to add an additional check in the conditional for the environment. (You can give each environment config a custom `'env'` key set and check with `craft.config.env`.)  
  > **username_10**: @username_9 So to Twig, a falling tree makes a sound no matter what. Thanks for the update and environment-check approach!  
  
  ---
  
  ### Answer by username_1 on 2015-10-24. Score: 17
  
  I believe I have a workaround and can (roughly) explain what's going on here.
  
  First, the workaround:
  
  **Use array syntax to test the existence of your custom fields instead of object syntax.**
  
  ```
  {# This works #}
  {% if entry['someField'] is defined %} ... {% endif %}
  
  ```
  
  Using array syntax for your conditional will result as true if your field does exist and false if it does not. Using object syntax results in false positives where the conditional always returns true even if a field doesn't exist:
  
  ```
  {# FALSE POSITIVES: These return true if a field doesn't exist #}
  
  {% if entry.someField is defined %} ... {% endif %}
  {% if attribute(entry, 'someField') is defined %} ... {% endif %}
  
  ```
  
  I believe the false positive occurs using object syntax when the object has or is extending another object that uses a `__call()` method. Twig will test to see if it can find an `attribute` or a `method`. In the case it can't find an attribute on an object, it will look for a method. And if it can't find a method on the object, it will check for the existence of a `__call()` method and if the `_call()` method exists it returns true, creating the undesired result of also returning true for any variable that doesn't exist on an object that uses a `__call()` method.
  
  I haven't dug into the code, but it seems that using the array syntax doesn't trigger a search for a potential method associated with the `__call()` behavior.
  
  ---
  
  A couple related articles can be found on Straight Up Craft:
  
  * [How to check if a variable or value exists using Twig](https://straightupcraft.com/articles/how-to-check-if-a-variable-or-value-exists-using-twig)
  * [Testing if something exists: is defined, length, is not null, is not empty](https://straightupcraft.com/articles/testing-if-something-exists-is-defined-length-is-not-null-is-not-empty)
  
  > **Comments:**
  > **username_2**: This should go into the official documentation! ... I just dumped several hours into researching this odd behaviour :(  
  > **username_3**: Sweet, that resolves it. Thanks for sharing!  
  > **username_5**: 2019 and this is still an issue - and this appears to still be a work-around. Thanks!  
  > **username_4**: This had me flummoxed, thank you!  
  
  ---
  
  ### Answer by username_6 on 2015-03-04. Score: 1
  
  I was able to resolve this issue by creating a custom plugin that uses a service and template variables. The service will accept the content object and field name. You can reference how to write a conditional to check if the field is set (<http://buildwithcraft.com/classreference/models/BaseElementModel#getFieldValue-detail>). The service is then used in the template variables and will return true or false based on if the field is set.
  
  Craft Template Twig Example
  
  ```
  {{ (craft.pluginName.isFieldDefined(e, 'someField') ? e.someField : false) }}
  
  ```
  
  Sorry, I can't post a full code example.
  
  
  ---
  
  ### Answer by username_7 on 2020-08-21. Score: 1
  
  I came across this while trying to check if object has method. I found out that `is defined` always returns true and some other options would return always null (even if the method existed) so I ended up writing a twig extension (which was faster than trying to solve the problem):
  
  ```
  /**
   * @param object $entity
   * @param string $method
   *
   * @return bool
   */
  public function twig_method_exists($entity, string $method): bool
  {
      if (!is_object($entity)) {
          throw new InvalidArgumentException('Given entity is not of type object, got: '.get_class($entity));
      }
  
      if (empty($method)) {
          throw new InvalidArgumentException('Method name empty');
      }
  
      return method_exists($entity, $method);
  }
  
  ```
  
  And i use it like this in the twig
  
  ```
  {% if method_exists(entity, 'getCreatedBy') %}
      ({{ entity.createdBy.name }})
  {% endif %}
  
  ```
  
  
  ---
  
  ### Answer by username_8 on 2016-08-31. Score: 0
  
  I had a similar issue when using an if statement to define a block element. The correct way doing this will be following:
  
  ```
  {% block metaOgImage %}
    {% if og.image is defined %}
     <meta property="og:image" content="{{ og.image }}">
    {% endif %}
  {% endblock %}
  
  ```
  
  Do not use the if statement outside the block statement.
  
  
  ---
  
  