1

Thanks to some help recieved on another question I have discovered Eager loading which makes a lot of sense. I am now trying to output an image from a matrix field.

I am part way there as my imageAlt outputs, but not the actuall photo? If I remove the .url I am presented with a number which I assume is the image ID.

My Matrix field is as follows:

Handle: teamPortrait
Block Types: Asset
Fields: image (Assets field type) and imageAlt (Plai text field type)

{% set teamEntries = craft.entries()
.section('team')
.with(['teamPortrait'])
.limit(3)
.all() %}

{% for teamEntry in teamEntries %}
<div class="col-4">
  {% set image = teamEntry.teamPortrait[0] ?? null %}
  {% if image %}
  <picture>
    <img src="{{ image.url }}" alt="{{ image.imageAlt }}" width="200" height="300">
  </picture>
  {% endif %}
  <h1>{{ teamEntry.title }}</h1>
  <h2>{{ teamEntry.jobTitle }}</h2>
</div>
{% endfor %}
2

You've eager-loaded the matrix block(s), but not the image(s) within them. Change to something like this to eager load both, assuming you have named the block type "asset" and the asset field "image":


{% set teamEntries = craft.entries()
    .section('team')
    .with(['teamPortrait.asset:image'])
    .limit(3)
    .all()
%}

(To remember the correct syntax, I mentally visualise a colon in the matrix config UI in-between those two columns that hold the matrix block type handles and the blocks' field handles).

Then your second problem is that you're referencing the first matrix block instead of the asset field within it just here: {% set image = teamEntry.teamPortrait[0] ?? null %}. Instead you'll need {% set image = teamEntry.teamPortrait[0].images[0] ?? null %}. To output the alt text, you'd then need to change it to {{ teamEntry.teamPortrait[0].imageAlt) }} as it's part of the matrix block, not part of the image field. Typically though, when adding alt text to images, I store it directly against the image as an asset field - in which case you'd keep the syntax as-is.

After you've got that working, look into eager loading transforms too, as you'll probably need that if applying a transform (as a general rule you should never output an image as-is from any CMS - even if the current editors are technically-savvy enough to optimise their images, their successors may not be).

The syntax for eager loading image transforms for images inside matrix blocks gets a little bit hairy, but once you've forced yourself to type it out 400 times you get used to it! That could look something like this:

{#---- in core layout wrapper for reusability: ----- #}
{% set transforms = {
    galleryImgHalf: { width: 900 },
    galleryImgThirds: { width: 585 },
    galleryImgQuarters: { width: 420 },
    galleryImgFull: { width: 1080 },
    cardImgCropped: { width: 585, height: 732, mode: 'crop'},
    ... etc
} %}


{#---- in child templates: ----- #}
{% set teamEntries = craft.entries().section('team').with([
    ['teamPortrait.asset:image', {withTransforms: [
        transforms.galleryImgFull,
        transforms.galleryImgThirds,
        transforms.galleryImgHalf
    ]}],
    ['more.things:here', {withTransforms: [transforms.someTransform]}],
    ['and.more:here', {withTransforms: [transforms.someTransform2]}],
]).limit(3).all() %}
2
  • This is great, thank you. If I keep the image alt with the asset then I don't actually need a matrix field, still great information though Oct 4 at 10:23
  • ha ha, ah yes definitely much much much simpler that way! If the only reason you were using a matrix was for visually grouping those two fields together that's generally something to avoid in future, even if it means using two separate fields. Oct 4 at 10:37

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.