5

Can someone explain why and when we need to use .first()?

An example to use would be this code.

{% set featuredProductsHome = craft.entries.id(2).first() %}
{% for product in featuredProductsHome.featuredProducts %}
    {% import '_macros/_product' as m_product %}
    {{ m_product.teaser(product, 500, "product-teaser--featured") }}
{% endfor %}

The above works, but when I had {% set featuredProductsHome = craft.entries.id(2) %} without calling .first() it returned nothing.

1
  • Just for kicks, since you are limiting your query to a single entry result with id(2) you could also use last() and should see the same working results as when you use first(). Aug 20 '16 at 18:41
7

By default, when you query elements you get back an array of Elements. Craft assumes you are using find() to query your elements if you don't explicitly say otherwise. You can loop through those elements and display attributes of those elements like you are doing:

{% for entry in craft.entries.find() %}
    {{ entry.title }}
{% endfor %}

More generally, here an abstract example of what you are getting back from your query:

{# A query for several Entry elements #}
craft.entries.find()

{# Results are an array of Entry Models #}
array(
  EntryModel,
  EntryModel,
  EntryModel
)

And in the case, you are only querying a single entry, you still get it back in the format of an array when using the default find() behavior.

{# A query for a single Entry element using find() #}
craft.entries.id(11).find()

{# Results are an array of a single Entry Model #}
array(
  EntryModel
)

However, if you update your query to use first(), you get back the Model directly:

{# A query for a single Entry element using first() #}
craft.entries.id(11).first()

{# Results are the Entry Model itself (not within an array) #}
EntryModel

There is one more scenario to consider when using first(). If you happen to be Eager Loading Elements, the results that you get back for your Element fields are not ElementCriteriaModels, but just normal arrays. So, in the case of accessing the data returned from Eager Loaded Elements you will not be able to use first() as the first() method is only available when you interact with ElementCriteriaModels.

In these cases, or in cases where you are sharing a partial template between two pages, one which uses eager loading and one that doesn't, you will need to access your first entry in an array using array syntax.

{% set entry = entry.entryRelationsFieldHandle[0] ?? null %}

In the above example, since we are accessing the first element in the array directly [0], if it doesn't exist, we will get an error (The first first() method is a bit smarter and will not throw an error). So, in the above example we have to explicitly plan for the situation of having no results using the null-coalescing operator ?? and falling back to null.

A longer form discussion of this scenario can be found in the article Examples of Eager Loading Elements in Twig and PHP.

3

It's because craft.entries.id(2) could be an object/array containing many entries. .first() gets the first object within it, which in your case is the 1 entry.

Edit*: I'm wrong, see the comment beneath.

2
  • 3
    Very close, but not entirely accurate. Without the first, you're actually dealing with an ElementCriteriaModel. See this question/answer for more details.
    – Lindsey D
    Aug 19 '16 at 17:06
  • I have a followup question: given that .first() will only work in some cases (ElementCriteriaModel when eager loading is not being used), is there a compelling reason to not just always use [0] in place of .first() given that it seems to work in all of the same situations, and also works with normal arrays?
    – cmal
    Sep 18 '16 at 13:50

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.