I am wracking my brain here trying to understand the new documentation in Craft CMS 3 and the new way it handles assets from an entry. I have a page that creates a list of portfolio entries using thumbnails. The image is placed as a background-image using inline CSS and the div with the content appears on hover. The thumbnails are from a field in my entry called projectThumbnails. This field only allows a single image so pulling an array doesn't make sense, does it?

I got this working using a deprecated method (see code below) but I'd prefer to not have any deprecation warnings on my final site. The warning says "Looping through element queries directly has been deprecated. Use the all() function to fetch the query results before looping over them." but adding .all() to the asset query doesn't seem to fix the issue. Is there a way to avoid creating the asset query and just use the entry query since the field already exists in the entry?

{% block main %}

{# Create entry queries #}
{% set portfolioGrid = craft.entries().section('projects').all() %}
{% set portfolioThumnbnails = craft.assets.volume('projectThumbnails') %}

{# Display the entries #}
<section class="portfolioGrid">
    {% for portfolioTile in portfolioGrid %}
    <a href="{{ portfolioTile.url }}" class="portfolioTile{% if portfolioTile.featuredProject %} featuredProject{% endif %}"{% if portfolioTile.projectThumbnail | length %}{% for projectThumbnail in portfolioTile.projectThumbnail %} style="background-image: url('{{ projectThumbnail.getUrl }}'); background-size: cover;"{% endfor %}{% endif %}>
        <div class="portfolioTileContent">
            <h1>{{ portfolioTile.projectName }}</h1>
            <h2>{{ portfolioTile.client.one.title }}</h2>
    {% endfor %}

{% endblock %}

The documentation on this is a bit scattered about, it took me a while to get the whole picture as well. You need multiple pieces of information:

  1. The documentation on querying assets only mentions craft.assets() as a way to query entries, which you would use to query assets independently of an entry.
  2. Meanwhile, you can find the documentation on how to query assets from an entry field in the Asset Fields documentation. The thing to realize here is that entry.myFieldHandle gives you a craft\elements\db\AssetQuery object, same as craft.assets(), but populated with where-clauses to get only assets selected for that field on that entry.
  3. Finally, you need to look at the documentation for Element Queries, which will give you the different options for executing element queries, including AssetQuery::all(). AssetQuery::one() is the one you're looking for, this will execute the query and return a single result element (or null if no results are found).

Putting it all together, here's how you would access a single thumbnail in your code:

{% set portfolioGrid = craft.entries().section('projects').all() %}
{% for portfolioTile in portfolioGrid %}
    {% set thumbnail = portfolioTile.projectThumbnail.one() %}

    {# AssetQuery::one may return null if the field is empty. #}
    {% if thumbnail %}
        {# Output the thumbnail. #}
    {% endif %}
{% endfor %}
  • I thought this as well but when I tried this approach I got a twig error, "Variable "projectThumbnail" does not exist." I added "{% set portfolioThumbnail = portfolioTile.projectThumbnail.one() %}" inside the grid for loop and changed the anchor tag to "<a href="{{ portfolioTile.url }}" class="portfolioTile{% if portfolioTile.featuredProject %} featuredProject{% endif %}"{% if projectThumbnail | length %} style="background-image: url('{{ projectThumbnail.getUrl }}'); background-size: cover;"{% endif %}>" to try to grab the thumbnail. – Stuart McCoy Jun 8 at 12:58
  • @StuartMcCoy You're setting portfolioThumbnail but trying to access the variable as projectThumbnail :-) If you use the correct variable name it will work! ANother thing: Instead of {% if projectThumbnail | length %}, use just {% if projectThumbnail %}, since AssetQuery::one() returns either a single Asset object or null, not an array. – MoritzLost Jun 8 at 13:04
  • 1
    Thanks. It's always something stupid or little that gets overlooked. – Stuart McCoy Jun 8 at 14:00

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.