We add transforms to our images so they're the minimum needed size, and then improve performance by eager loading the images and transforms.
When we load in images during an element query and for-loop, like we are with the adventure images, we can run into an n+1 issue. That means that every loop produces at least one additional query to find the image for that element. This isn’t efficient and can cause performance issues.
Because of that, we want to eager load our images and their transforms, so we grab everything we need upfront rather than delaying it until we’re in the loop for each element.
Also, in Craft 4, there are some changes to how eagerly loaded elements work. All eager-loaded elements are returned as collections instead of standard data arrays. Because of this change, we don’t need to change our code for how we access the data that is returned from an eagerly loaded element.
To do this, we use the with
method to tell Craft to eager load any element handles we pass in. In this case, our field handle is images
, so we’ll pass it in in square brackets and in single quotes.
{% set adventures = craft.entries
.section('adventures')
.limit(10)
.with(['images'])
.all()
%}
We can dump and die the results of the adventures query to see that we have an eagerly loaded element in the returned data.
Because of the changes in Craft 4 with how it returns eagerly loaded elements, it now supports accessing the array elements via the one
method as an alias to the first()
method in Laravel Collections. That means we don’t have to change our code where we output the image. Everything just works as it is.
<img
src="{{ adventure.images.one.url('adventureListing') }}"
alt=""
class="w-full h-full object-center object-cover group-hover:opacity-75"
/>
One thing you’ll notice is that we are also retrieving an image transform as part of the code. That is something that we can eager load, too, alongside our image. This will also prevent another n+1 issue that we might encounter.
This uses a second parameter in the with
method called withTranforms
. We surround it with curly braces, and the property name is withTransforms
and then we pass in an array of transform handles we want to eager load. In our case, we’re going to eager load the one transform we need.
{% set adventures =
craft.entries
.section('adventures')
.with([
['images', {
withTransforms: ['adventuresListing']
}]
])
.limit(10)
.location(category ?? '')
.all() %}
While this has a minimal impact right now because our site is small, using this best practice is going to pay dividends going forward as you add more data output to your templates.
Real World Craft CMS is made up of the following videos: