How to dynamically access images from upload field from an images folder inside of theme?

So I’ve ran into an issue where I’m not able to pull the image from an custom upload field. Note: The destination is in a custom folder and the images are uploading fine on the backend.

Blueprint:

header.homepage_img:
     type: file
     destination: 'theme@:/images/featured'
     style: vertical
     size: medium
     accept:
        - 'image/*'

Twig Template

{{ page.media[‘header.overview.page_media’].html }}

Shouldn’t the above code work, because currently nothing outputs to the page? Even after clearing cache.

So I know this works – explicitly calling the image file.

{{ media[‘theme://images/featured/featured-event-efw.jpg’].html() }}

however I need a more dynamic approach, because I want to loop through the images in that same featured folder

I tried

{{ media[‘theme://images/featured/header.homepage_img’].html() }}

but this doesn’t output anything. So am I missing something?

If you have already the image name stored in the page header as a string in homepage_img, might the twig concatenate help?

{{ media['theme://images/featured/' ~ page.header.homepage_img].html() ] }}

Hey Hugoaf, thanks for the response, however, your example results in an error. One because there is an extra “]” added to this line but even removing the extra “]” I get this

an exception has been thrown during the rendering of a template (“Array to string conversion”)

if there are multiple images in your page this results in the output you got, loop them out by adding a for loop, like so:

{% for image in page.header.homepage_img %}
   {{ media[‘theme://images/featured/’ ~ image ~].html() }}
{% endfor %}

Haven’t tested this yet, but I hope it works for you. I’m just not sure about the second ~, whether it should be placed there or after the .html()

Hey Rob,

This example code didn’t work either. Still produced an error.

Unexpected token “punctuation” of value “]”."

It has to be the syntax is wrong or its not possible to use media objects in this way. I can add the media object with the name of the jpg statically but I’m trying to do it in a dynamic way because this code will live in an include…so this isn’t an authorable region on the page.

I know if there are images upload via the default upload field you can pull the file with

page.media

and thats if the image is being uploaded to the pages>images folder. But the destination on my field is different. I’m surprised there isnt an example / recipe of how to do this on the Grav Doc.

Take a look at this cookbook entry: https://learn.getgrav.org/cookbook/twig-recipes#displaying-an-image-uploaded-in-a-file-field
Example:

{{ page.media[header.yourfilefield|first.name] }}

@paul Yeah man I’ve been looking at this recipe and I don’t think it addresses what I am asking. Currently I can pull everything from the header except the fields with upload functions. And it may be because of how my for loop is and/or the destination of the images.

If I was to simply do:

{% for feature in page.find(‘/events’).children() %}
{{ feature.title }}
{% endfor %}

it outputs all the titles from each child page of the events folder, as expected. No issues.

But, it doesn’t seem to pull the image file, path, name or anything from the field that I use to upload images…

 header.overview.homepage_img:
     type: file
     destination: 'theme@:/images/featured'
     style: vertical
     size: medium
     accept:
        - 'image/*'

{% for feature in page.find(‘/events’).children() %}
{{ feature.header.overview.homepage_img.name }}
{% endfor %}

The above twig code doesn’t error out but it results to blank. And it should at least print out all the names of the image files right?

If I were to target just the field since its within the page header like so:

{% for feature in header.overview.homepage_img %}
{{ feature.name }}
{% endfor %}

This will pull the image name from the header…but that’s not what I need. I’m trying to go through all the child pages of the events folder and pull the images from the field above. The field above is simplified for this question, but I’m only allowing one image to be uploaded to this field. I’m sure there is something simple I’m missing or overlooking.

hi @horussky

The answer is in the cookbook, but let me explain.
When using file fields, don’t forget that the file field allows for multiple images to be uploaded, it therefore create an array of image, even if you only allowed for a single image.

In this example

{% for feature in page.find(’/events’).children() %}
{{ feature.header.overview.homepage_img.name }}
{% endfor %}

you did not add the first filter, so Grav won’t know which image name it should output

{% for feature in page.find(’/events’).children() %}
      {{ feature.header.overview.homepage_img|first.name }}
{% endfor %}

Notice the first filter added.

This will output the image name of the uploaded file.

Now if you haev the image name, you just have to add page.media to retrieve it.
On the page:

{{ page.media[header.overview.homepage_img|first.name].url }}

Now your complete loop with the image.

{% for feature in page.find(’/events’).children() %}
{{ feature.media[feature.header.overview.homepage_img|first.name].url }}
{% endfor %}

@paul

Cool. Here’s the results from some testing…

 {% for feature in page.find('/events').children() %}
 {% set image = feature.header.overview.homepage_img %}
     {{ image|first.size }} << output correctly
     {{ image|first.name }}  << output correctly
     {{ page.media['image|first'].url }} << nothing output
     {{ feature.media['feature.header.overview.homepage_img|first.name'].url }} << nothing output
     {{ page.media['feature.header.overview.homepage_img|first'].url }} << nothing output
 {% endfor %} 

for whatever reason the page.media doesn’t output an image within this loop…so weird

Here is the correct version:

{% for feature in page.find('/events').children() %}
 {% set image = feature.header.overview.homepage_img %}
     {{ image|first.size }} &lt;&lt; output correctly
     {{ image|first.name }}  &lt;&lt; output correctly
     {{ feature.media['image|first.name'].url }} &lt;&lt; nothing output
     {{ feature.media[feature.header.overview.homepage_img|first.name].url }} &lt;&lt; nothing output
     {{ feature.media[feature.header.overview.homepage_img|first.name].url }} &lt;&lt; nothing output
 {% endfor %}

Basically, you had unnecessary quotes, and you forgot the .name

@paul

yeah these lines results in nothing as well

            {% for feature in page.find('/events').children() %}
            {% set image = feature.header.overview.homepage_img %}
              {{ page.media[image|first.name].html }}
              {{ page.media[image|first.name].url }}
            {% endfor %}  

page.media seem to not like my field…

yes, it’s not page.media but should be feature.media.

Made the mistake in my example. will edit

@paul unfortunately none of these worked

     {% for feature in page.find('/events').children() %}
     {% set image = feature.header.overview.homepage_img %}
          {{ feature.media[image|first.name] }}
          {{ feature.media[image|first.name].html }}
          {{ feature.media[image|first.name].url }}
          {{ feature.media[feature.header.overview.homepage_img|first.name].url }}
     {% endfor %}

So using the Debugger and dump command within the forloop

    {{ dump(feature.media[image|first.name].url) }}

this results to 5 nulls

…seems impossible because when doing this

    {{ dump(image) }} 

The result for all 5 arrays are there…path, size, name, file. It just seems like when doing either page.media or .media I’m not pulling any results.

So taking a different approach I was able to output the images like so:

<img src="{{ '/' ~ feature.header.overview.homepage_img|first.path }}" />

So in my Loop, it looks like this

{% set this_year = "now"|date('Y-m-d') %}  
{% for feature in page.find('/events').children.order('feature.header.overview.datestart', 'desc') if feature.header.overview.datestart > this_year %}
       {% if loop.index < 4 %}
                    <div class="event">
                        <div class="event-img">
                            <a href="#" title="{{ feature.title }}">
                              <img src="{{ '/' ~ feature.header.overview.homepage_img|first.path }}" />      
                            </a>
                        </div>
                        <div class="event-content">
                            <h5>{{ feature.title }}</h5>
                            <p>{{ feature.header.overview.datestart }}</p>
                            <p><a href="#" title="See more about {{ feature.title }}">View Details</a></p>
                        </div>
                    </div>
       {% endif %}
{% endfor %} 

Would have preferred a prettier way of looping that image but if it works it works. @paul if you have any more suggestions I’ll appreciate your input alot. Thanks for your previous replies.

Does this work ?:

{% set this_year = "now"|date('Y-m-d') %}  
{% for feature in page.find('/events').children.order('feature.header.overview.datestart', 'desc') if feature.header.overview.datestart > this_year %}
       {% if loop.index < 4 %}
                    <div class="event">
                        <div class="event-img">
                            <a href="#" title="{{ feature.title }}">
                            {{ feature.media[header.overview.homepage_img|first.name] }}
                            </a>
                        </div>
                        <div class="event-content">
                            <h5>{{ feature.title }}</h5>
                            <p>{{ feature.header.overview.datestart }}</p>
                            <p><a href="#" title="See more about {{ feature.title }}">View Details</a></p>
                        </div>
                    </div>
       {% endif %}
{% endfor %}

@paul

unfortunately no… for whatever reason, page.media or media does not render an image within that forloop. When adding the following to the dump

  {{ feature.media[header.overview.homepage_img|first.name] }}

The debugger shows 3 null entries. Even the order is still acting wonky from the previous post you helped me on. It seems to only order the folders and not the data itself. I wonder if it has to do with the loop itself for both issues.