Default Featured Image

So I’m building a website, and I’m so very frustrated. I want to be able to have a default featured image if none is specified in the frontmatter of a post.

On the surface, this would seem fairly easy.

{{ .Scratch.Set "image" "/images/" }}
{{ if .Params.splash }}
{{ .Scratch.Add "image" .Params.splash }}
{{ else }}
{{ .Scratch.Add "image" "banner.jpg" }}
{{ end }}
{{ $image := (.Scratch.Get "image") }}

Easy!
First I set a new scratch containing by subdirectory assets\images.

Next, I check if the param exists. If it does, I add it to my scratch.
If it doesn’t, I add a default to my scratch instead.

now to use it, I just call resources.Get, right?

<img src="{{ ((resources.Get $image).Resize "500x jpg q75").RelPermalink }}">

Now here’s the frustrating part: Whenever I do this I get the following error:

Failed to render pages: render of "home" failed: execute of template failed: template: index.html:5:12: executing "index.html" at <partial "header.html" .>: error calling partial: "{Path-to-my-site}\layouts\partials\header.html:57:110": execute of template failed: template: partials/header.html:57:110: executing "partials/header.html" at <$image>: nil pointer evaluating resource.Resource.Resize

If I understand, this error is saying I didn’t provide a valid URL to the resource. But if I just print my image variable I get the correct response:

/images/bison.jpg

and if I specify that image path literally in my code (such as {{ ((resources.Get "/images/bison.jpg").Resize "500x jpg q75").RelPermalink }}) it works fine.

What am I doing wrong here?

I worked it out with the following code:

{{- .Scratch.Set "image" "/images/" -}}
{{- if (or (.IsHome) (not .Params.splash)) -}}
	{{- .Scratch.Add "image" "banner.jpg" -}}
{{- else  -}}
	{{- .Scratch.Add "image" .Params.splash -}}
{{- end -}}

{{- $img := .Scratch.Get "image" -}}

First I set my scratch.

Then I check to see if we’re on the home page OR if the splash param DOESN’T exist.

If we’re on the home page, or if the param is missing, I add a default to my scratch.

Otherwise, if we’re not on the home page AND the param exists, I add the param.

Then set my scratch to a variable and call:

{{ ( ( resources.Get $img ).Resize "500x q75 webp" ).RelPermalink }}

Works like a charm.

I don’t think my logic changed that much, just how I wrote it, so I might submit this as a bug?

Prior to v0.48.0 (August 29, 2018) you could not assign a new value to a variable once it had been initialized. This was due to a Golang limitation that took over three years to address.

The Hugo “Scratch” was created to work around this limitation. Unfortunately, this outdated construct still exists in examples, tutorials, and themes.

There are valid reasons to use a Scratch, but this isn’t one of them.

Do this instead:

{{ $a := "foo" }} {{/* Initialize */}}
{{ if true }}
  {{ $a = "bar" }} {{/* Assign */}}
{{ else }}
  {{ $a = "baz" }} {{/* Assign */}}
{{ end }}

So I tried writing it that way initially, and it doesn’t work for me at all.

I also tried writing it this way just now, and got the error:

{{ $img := "" }}
{{ if (or (.IsHome) (not .Params.splash)) }}
	{{ $img := "/images/banner.jpg" }}
{{ else }}
	{{ $img := printf "/images/%s" .Params.splash }}
{{ end }}

I get the following error:

Failed to render pages: render of "home" failed: execute of template failed: template: index.html:5:12: executing "index.html" at <partial "header.html" .>: error calling partial: "[path-to-site]\layouts\partials\header.html:52:105": execute of template failed: template: partials/header.html:52:105: executing "partials/header.html" at <resources.Get>: error calling Get: dirs not supported resource types: &{0xc0008c8ff0 0xc0001d6a00}

Only the scratch method works works for me, and only when I write it as a negative (as in the solution above). I tried checking to see what version of Go I have installed, and I was on 1.16.x Ran upgrade from CLi and got to 1.17.3, but I don’t think that’s the issue. I’ll update this thread once Go installs the upgrade and I rerun.

Update

I’ve updated Go to 1.17.3 and Hugo to 0.89.1 and this I can still only get this to work with .Scratch, and only when the logic is done in the aforementioned order (by negation).

I’m pretty sure this is a bug.

But, in case it makes a difference, I’m doing all of this from a partial.

You are initializing the variable three times. Do this:

{{ $img := "" }}
{{ if (or (.IsHome) (not .Params.splash)) }}
	{{ $img = "/images/banner.jpg" }}
{{ else }}
	{{ $img = printf "/images/%s" .Params.splash }}
{{ end }}
1 Like

holy crap I’m an idiot.

And you’re a wizard.

Thank you.

This topic was automatically closed 2 days after the last reply. New replies are no longer allowed.