Trouble converting images to WebP

Hi all,
I’m fairly new to Hugo.

I’m having trouble automatically converting images to optimised WebP images. My render-image.html is based off the code here by Eric Murphy.

{{ $src := resources.GetMatch (printf "%s" (.Destination | safeURL)) }}

{{ if $src }}
	{{ $data := newScratch }}

	{{ if gt $src.Width 1100 }}
		{{ $data.Set "wepb" ($src.Resize "960x webp q90") }}
	{{ else }}
		{{ $data.Set "wepb" ($src.Resize (printf "%dx%d webp q90" $src.Width $src.Height)) }}
	{{ end }}

	{{ $webp := $data.Get "webp" }}
	<figure>
		<a href="{{ $src }}">
			<img src="{{ $webp.RelPermalink }}" alt="{{ .Text }}" loading="lazy" decoding="async" width="{{ $src.Width }}" height="{{ $src.Height }}">
		</a>
		{{ with .Title }}
			<figcaption>{{ . | markdownify }}</figcaption>
		{{ end }}
	</figure>
{{ end }}

I put images in the root of assets/.

For example, here is content/test.md

---
title: Test
date: '2025-08-07'
---
This is a test post.

![here is some alt text](photo.jpg "here is a caption")

This results in the following HTML

<figure>
	<a href="/photo.jpg">
		<img src="" alt="here is some alt text" loading="lazy" decoding="async" width="3000" height="1800">
	</a>
	<figcaption>here is a caption</figcaption>
</figure>

As you can see, most of it renders correctly, except the images themselves. There should be both a link to the original image and an optimised WebP image. The former is not generated (going to /photo.jpg just gives the 404 page). The WebP is apparently not generated, since the src attribute is empty.

What am I doing wrong?

I have this in my hugo.yaml, though I think it’s irrelevant here.

markup:
  goldmark:
    parser:
      wrapStandAloneImageWithinParagraph: false

EDIT: forgot to mention I’m not using a premade theme.

I would suggest you test Hugo’s embedded image render hook and if it works, modify it to process images to webp

Also, learn to put assets into folders rather than at root. For example, assets/images/, assets/css, assets/js etc.

Also read Where to place image files when using the Markdown content format.

1 Like

the docs on image-render hooks. contain a figure example handling the block stuff.

The code you base on is about 2 years old. You don’t need newScratch for storing simple values,

{{ $webp := "" }}
   {{ if gt $src.Width 500 }}
      {{ $webp = $src.Resize "300x webp q90" }}
   {{ else }}
      {{ $webp = ($src.Resize (printf "%dx%d webp q90" $src.Width $src.Height)) }}
{{ end }}

but the most important thing is to correct the spelling of weXX :wink:

{{ $data.Set “wepb” ($src.Resize “960x webp q90”) }}
{{ $data.Set “wepb” ($src.Resize (printf “%dx%d webp q90” $src.Width $src.Height)) }}
{{ $webp := $data.Get “webp” }}

might also be a good idea to code defensive using {{ if $webp }} ...

looks like you got hit by Murphy’s law :slight_smile:

2 Likes

Oops, that’s kinda embarrassing…

I did already fix one misspelling that caused Hugo to throw an error. Guess I should have thought to look for more. I like to manually type out code to make myself actually read it and not just copy-paste it.

I fixed the typos and now it works.

Thanks for the info on newScratch, I’m working on changing it now.

EDIT: typo (!)

I tried making @irkode ‘s suggested modifications, and ran into errors. I reverted the file, stopped Hugo server, deleted public/ and resources/ and restarted the server, but now the linked image doesn’t exist. I’m getting 404 again. Not sure what’s going on, still testing.

Update: I’ve changed the code according with @irkode ‘s suggestion:

{{ $src := resources.GetMatch (printf "%s" (.Destination | safeURL)) }}
{{ if $src }}
	{{ $webp := "" }}
	{{ if gt $src.Width 1100 }}
		{{ $webp = $src.Resize "800x webp q90" }}
	{{ else }}
		{{ $webp = ($src.Resize (printf "%dx%d webp q90" $src.Width $src.Height)) }}
	{{ end }}
	<figure>
		<a href="{{ $src }}">
			<img src="{{ $webp.RelPermalink }}" alt="{{ .Text }}" loading="lazy" decoding="async" width="{{ $src.Width }}" height="{{ $src.Height }}">
		</a>
		{{ with .Title }}
			<figcaption>{{ . | markdownify }}</figcaption>
		{{ end }}
	</figure>
{{ end }}

It does partially work, but I still don’t have the source image linked. I don’t know why it just stopped working…

(I will worry about defensive code when I have a working solution)

check the value of $src and read the documentation about Resource methods.

$src is a resource object and here you evaluate that as string <a href="{{ $src }}">. The default conversion for a resource is to print the path which is /photo.jpg.

But you did not publish the resource before, so there’s no such file in your public folder.
… (my first test with the standard method published it there and and did not clean public in between)

to publish the resource you call the <a href="{{ $src.RelPermalink }}">. Check your public folder and the image is there.

Sorry for the inconvenience. :blush:

and this leads to @tyco comment about using a subfolder in assets. Or you will get all these images in your sites root folder.

general advice:

  • error checking/defensive coding is always a good idea. Being lazy at that part shifts problems to a later stage.
  • and it will help you to detect errors while testing out small snippets.
  • adding that later to a hundred lines of code with your mind on soime other topics, believe me is costly at the end.
1 Like

Thank you so much!

I think with myself, I tend to focus on the one thing (why won’t it work when it did before?!) and forget to step back and think. This is the second time I’ve failed to do so on this issue today.
{{ $url.RelPermalink }} does indeed work. I’ll have a proper read through the docs linked to by yourself and @tyco before moving on.
I will certainly put images and other resources in dedicated subdirs. I only put it in the root to minimise the mistakes the beginner that is myself could make on the first try.
Thanks for the advice, it’s very valuable to a novice like me.

Here’s what I have now. If you don’t mind I’d like to ask you if there’s anything else (either of) you would change before I mark the thread as solved.

{{ $src := resources.GetMatch (printf "%s" (.Destination | safeURL)) }}
{{ if $src }}
	{{ $webp := "" }}
	{{ if gt $src.Width 1100 }}
		{{ $webp = $src.Resize "800x webp q90" }}
	{{ else }}
		{{ $webp = ($src.Resize (printf "%dx%d webp q90" $src.Width $src.Height)) }}
	{{ end }}
	{{ if $webp }}
		<figure>
			<a href="{{ $src.RelPermalink }}">
				<img src="{{ $webp.RelPermalink }}" alt="{{ .Text }}" loading="lazy" decoding="async" width="{{ $src.Width }}" height="{{ $src.Height }}">
			</a>
			{{ with .Title }}
				<figcaption>{{ . | markdownify }}</figcaption>
			{{ end }}
		</figure>
	{{ end }}
{{ end }}

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