Skip to content
Grav 2.0 is officially stable. Read the announcement →

Community guidelines

Please keep discussions civil and on-topic. Repeated violations may lead to a temporary ban.

Content & Markdown

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

admin first-time

Started by Cedric W 8 years ago · 16 replies · 2137 views
8 years ago

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:

YAML
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.

8 years ago

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?

8 years ago

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

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

@hugoaf:
{{ 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")

8 years ago

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:

TWIG
{% 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()

8 years ago

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

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.

8 years ago

@paul:
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....

YAML
 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.

8 years ago

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

TWIG
{% 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.

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

@paul

Cool. Here's the results from some testing....

TWIG
 {% 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

8 years ago

Here is the correct version:

TWIG
{% 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

last edited 03/16/18 by Paul Massendari
8 years ago

@paul

yeah these lines results in nothing as well

TWIG
            {% 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.....

8 years ago

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

Made the mistake in my example. will edit

8 years ago

@paul unfortunately none of these worked

TWIG
     {% 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

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

this results to 5 nulls

...seems impossible because when doing this

TWIG
    {{ 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.

last edited 03/16/18 by Cedric W
8 years ago

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

TWIG
{% 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.

last edited 03/16/18 by Cedric W
8 years ago

Does this work ?:

TWIG
{% 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 %}
8 years ago

@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

TWIG
  {{ 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.

Suggested topics

Topic Participants Replies Views Activity
Content & Markdown · by Jochen, 8 months ago
6 93 8 months ago
Content & Markdown · by Ton Haarmans, 1 year ago
10 183 1 year ago
Content & Markdown · by Jan L'Am, 1 year ago
4 145 1 year ago
Content & Markdown · by Leonardo, 1 year ago
3 58 1 year ago
Content & Markdown · by belthasar, 1 year ago
4 253 1 year ago