Access page resources from list templates

I got content and a theme. With my site, every page (normal and list pages) should have a image:

/content/images/A.jpg

/content/_index.md

---
title: "Hello"
date: 2019-11-03T00:00:00+00:00
image: images/A.jpg
resources:
- src: images/A.jpg
  title: "A picture"
---
# Hello

/themes/mytheme/layouts/index.html

{{ define "head" }}
	{{ if .Params.image -}}
	{{ $img := resources.Get (.Params.image) }}
	<style>
header.banner {
	background-image: url('{{ $img.RelPermalink }}');
	background-position: 50% {{.Params.image_pos_vert | default "50%"}};
}
	</style>
	{{- end -}}
{{ end }}

When I build, I get this error:

ERROR [...] Failed to render pages:
render of "home" failed:
"[...]themes/mytheme/layouts/index.html:6:31":
execute of template failed: template:
index.html:6:31:
executing "head" at <$img.RelPermalink>:
nil pointer evaluating resource.Resource.RelPermalink

Instead of resources.Get (.Params.image) I can write

.Page.Resources.Get (.Params.image)
$.Page.Resources.Get (.Params.image)
.Resources.Get (.Params.image)
$.Resources.Get (.Params.image)

$img stays pointing to nil. Getting .Params.image works as expected.

This pattern works for Pages and fails for ListPages and the HomePage.

After reading the docs, I would expect it to work for list pages, also: “This new model allows you to include list-specific front matter via .Params and also means that list templates have access to all page variables.”

Am I doing something wrong?

1 Like

Hi,

Resources for list pages need to be in the same level as the _index.md: See table here Page bundles | Hugo

Hi pointyfar,

thank you for your explaination. This clears up some things. Yet it makes me question many more (for my own answer, see after the EDIT tag):
Why is there any constraint on where my resources reside?
Is it any different when I explicitly list my resources (like in the example below)? Or do resources need to get listed in the front matter at all times (even if I do not have metadata for them; so there are no implicit resources)?

Conceptually I do not understand why this should not work:

---
title: "Hello"
resources:
- src: ../../A.jpg
  name: A.jpg
  title: "A picture"
---
<img src="{{ .Resources.Get('A.jpg').RelPermalink }}" />

I can’t find the relevant code. All I see is a generic globbing and loading of the specified files…

EDIT:
I think I just understood: When I say

Any page bundle (leaf or branch bundle) is only allowed to use its exclusive directories. It can not use resources located at a position that can be referenced by another page bundle. All page bundle resources are independet of their surrounding bundles and can be moved to arbitrary positions without breaking their resource references.
So a branch bundle can only use resources on its exact level in the directory hierachy. A leaf bundle can use resources on its own level or in any directory below.
The only exception from that rule are headless bundles, which can be the source of resources in other page bundles via a special mechanism to dereference them.

am I right?

You don’t need to list your resources in your frontmatter. You do if you need to add metadata.

Essentially, yes.


Note that this example:

will not work because:

  1. You cannot use templating logic directly in your content/markdown. You need to encapsulate it into a shortcode: Shortcodes | Hugo

  2. Page .Resources have the following methods: (see .Resources.GetMatch) Page resources | Hugo
    NOT to be confused with Hugo Pipes: (see resources.Get) Hugo Pipes | Hugo

The title is kind of misleading or I understood it differently.

I was looking to add feature or cover image on list page for each blog post. But the image is stored into page resources of each individual post. I didn’t want to add all images in static folder.

I found a hack solution that may be useful to some people.
Following code is inside range for pages slice.

{{ $link := .Permalink }}
{{ with .Param.image }}
  {{ $image := . }}
  <img
    src="{{$link}}{{$image}}"
  >
  </img>
{{ end }}

My post is https://example.com/blog/my-first-post/ and in front matter it shows.

---
image: images/cover.jpg
--- 

After joining both the img src becomes.
https://example.com/blog/my-first-post/images/cover.jpg

Hope this helps.

1 Like

This worked for me, thank you!
Is there a more elegant solution to this? The whole point of list pages is to showcase a summary from the main post and from what I see on the web a cover image is used pretty much all the time.

Another solution I found is to actually use this in a list/collection page (which doesn’t make much sense to have a workaround just to grab an image):

{{ range .Pages }}    
<img src="{{ Rel.Permalink }}{{ .Params.image }}" alt=".Params.alt" >
{{ end }}

{{ .Rel.Permalink }} brings the url for your post, e.g. www.hugo.com/blog/my-post.
{{ .Params.image }} brings the url of the image inside the page bundle.

In frontmatter .image would be image = “/image/beautiful.jpg”.

So concatened it means www.hugo.com/blog/my-post/image/beautiful.jpg and can render on the list page.

1 Like

Thank you so much for the hack it worked perfectly! Except I had to replace Rel.Permalink with .Permalink I have no idea why, but the following snippet worked for me:

{{ range .Pages }}    
<img src="{{ .Permalink }}{{ .Params.image }}" alt=".Params.alt" >
{{ end }}