Poison theme: Problems displaying images both in the home page preview and in each post

I’m using poison theme. My directory looks like

- content
 - posts/
   - post1.md
   - post1/
     - image.png

After running hugo and uploading all of the content of public/ I have an issue with my images. Let’s say that the content of post1.md was

<figure>
 <img src='image.png' alt='image' />
 <figcaption>
   my image
 </figcaption>
</figure>

Then in the post itself <url>/posts/post1/ I can see the image since it links to <url>/posts/post1/image.png . However, if I am at the homepage ( <url> ) and I see the preview of my post, I cannot see the image, since it links to <url>/image.png .

What is the proper solution? (other than uploading 2 copies of the image)

ps: unrelated. I am a new user so I can’t replace <url> with example.com (thereby making it clear that it is a link). It might be nice to let new users posts more than 2 links if the link is example . com

First, your content structure should be:

content/
└── posts/
    └── post-1/
        ├── image.png
        └── index.md

Second, you need to call the embedded figure shortcode:

{{< figure src=image.png >}}

Or you can create your own shortcode, but make sure it uses the same resource logic as the embedded template (source code here).

Third, I strongly recommend that you enable the embedded link and image render hooks.

[markup.goldmark.renderHooks.image]
enableDefault = true

[markup.goldmark.renderHooks.link]
enableDefault = true

Finally, to add example links when posting to this forum, use this Markdown syntax:

This is an `https://example.org` link.

That renders like this:

This is an https://example.org link.

Thank you for your response. I modified a page to be with the structure of

content/
└── posts/
    └── post1/
        ├── image.png
        └── index.md

Inside index.md I tried

{{< figure
	src="image.png"
	alt="image"
	caption="an image"
>}}

and I tried
![image](image.png "an image")

However, like before, both formats result in the homepage preview linking to the nonexistent https://example.org/image.png and the post1 page linking to the working https://example.org/posts/post1/image.png

I did not modify image render hooks, because from my understanding, that can help modify things like its display size. However, at this point I want to work on it rendering in the first place.

What I ended up doing was adding themes/poison/layouts/_default/_markup_render-image.html with the content

{{ $img := .Page.Resources.GetMatch (printf "**%s" .Destination) }}
{{ if $img }}
    <img src="{{ $img.RelPermalink }}" alt="{{ .Text }}" title="{{ .Title }}" loading="lazy" />
    {{ if .Text }}<figcaption>{{ .Text }}</figcaption>{{ end }}
{{ else }}
    <img src="{{ .Destination }}" alt="{{ .Text }}" title="{{ .Title }}" />
    {{ if .Text }}<figcaption>{{ .Text }}</figcaption>{{ end }}
{{ end }}

The {{ if .Text }}<figcaption>{{ .Text }}</figcaption>{{ end }} was needed so that I could do ![an image](image.png) and make an image the caption rather than the hover over.

This seems to work, although I don’t know if this is the “proper” way (my assumption is that changes directly to theme should be avoided). If so, I will suggest that change to the poison theme.

The instructions that I provided work great. Try it:

git clone --recurse-submodules --single-branch -b hugo-forum-topic-54391 https://github.com/jmooring/hugo-testing hugo-forum-topic-54391
cd hugo-forum-topic-54391
hugo server

Indeed it does. Sorry for dismissing your solution earlier. I suspect that I did not properly save my code when I tried what you suggested. I will make sure to do so in the future.

I prefer using markdown images ![an image](image.png) over embedded figure shortcode {{< figure src=image.png caption="an image" >}} since that way my markdown IDE can render the images as well. So for now I think I’ll stick with my _markup_render-image.html file. But thank you so much for the reference.

Your approach generates invalid HTML:

image

A figcaption element must be a child of a figure element.

That’s odd. I cloned your repo, added themes/poison/layouts/_default/_markup/render-image.html with the content

{{ $img := .Page.Resources.GetMatch (printf "**%s" .Destination) }}
{{ if $img }}
    <img src="{{ $img.RelPermalink }}" alt="{{ .Text }}" title="{{ .Title }}" loading="lazy" />
    {{ if .Text }}<figcaption style="text-align: center;">{{ .Text }}</figcaption>{{ end }}
{{ else }}
    <img src="{{ .Destination }}" alt="{{ .Text }}" title="{{ .Title }}" />
    {{ if .Text }}<figcaption style="text-align: center;">{{ .Text }}</figcaption>{{ end }}
{{ end }}

and modified your image on line 9 to

 ![an image](image.png) 

and ran hugo server. I could see the image with no issue (on both the homepage and post’s page).

This isn’t about what any given browser does. It’s about invalid HTML. Run the HTML through a validator yourself.

Relying on browsers to consistently render invalid HTML the way you want it to be rendered is a very bad idea.

I see what you mean. I’m not a well versed web programmer, but I see in my html that it generated

<p>
    <img src="/posts/post1/image.png" alt="an image" title="" loading="lazy" />
    <figcaption style="text-align: center;">an image</figcaption>
</p>

But as per the specification HTML Standard
figcaption: Contexts in which this element can be used: As the first or last child of a figure element.

So while it works for me now, there is no guarantee that future versions of my browser, or other browsers, will render it properly.

Your solution produces

<p>
    <figure>
        <img src="/posts/post1/image.png" alt="an image">
        <figcaption>
            <p>an image</p>
        </figcaption>
    </figure>
</p>

Which follows the standard.

Why is it that hugo (or poison) requires images to be written like so {{< figure src=image.png caption="an image" >}} rather than typical markdown ![an image](image.png)? It would seem to me to be better to use markdown, but I’m new to this, so it’s possible that I’m missing something.

IT DOESN’T.

hmm … I may be misunderstanding what you wrote then.

I raised my issue with images being displayed in posts, but not on the home page. You suggested {{< figure src=image.png caption="an image" >}} (not a native markdown function) to solve the issue. I would have preferred something like ![an image](image.png) (a native markdown function), however, in order to support that I modified _markup_render-image.html to create something not as per the standard. To avoid that I reluctantly used your suggestion.

I’m not sure what you meant by “IT DOESN’T”. Since it seems to me that in fact I do have to use embedded figure shortcode if I want to create proper html while displaying the image both on the home page and post.


I tried to modify the _markup_render-image.html file again, with

{{ $img := .Page.Resources.GetMatch (printf "**%s" .Destination) }}
<figure style="text-align: center;">
    {{ if $img }}
    <img src="{{ $img.RelPermalink }}" alt="{{ .Text }}" title="{{ .Title }}" loading="lazy" />
    {{ else }}
    <img src="{{ .Destination }}" alt="{{ .Text }}" title="{{ .Title }}" loading="lazy" />
    {{ end }}
    {{ if .Text }}
    <figcaption>{{ .Text }}</figcaption>
    {{ end }}
</figure>

Now it creates html of the form

<figure style="text-align: center;">
    <img src="/posts/post1/image.png" alt="an image" title="" loading="lazy" />
    <figcaption>an image</figcaption>
</figure>

So I hope that this is a proper solution.

I suggested that because your initial post showed that you were using raw HTML (a figure element) in your Markdown.

If you want to render a figure element, use a figure shortcode.

If you want to render an img element, use the Markdown image syntax.

Your latest attempt also generates invalid HTML because it renders like this:

<p>
  <figure style="text-align: center;">
    <img src="img.html" alt="foo" title="" loading="lazy" />
    <figcaption>foo</figcaption>
  </figure>
</p>

And you can’t place a block element (e.g., figure) within a p element.

I suggested that because your initial post showed that you were using raw HTML (a figure element) in your Markdown.

I’m sorry, I was unclear. My goal is to

  1. Display an image
  2. Both in the homepage and in the post
  3. Support a caption

Do you know how to do that with Markdown image syntax in such a way that will create a valid html output?


Unless I somehow rendered your github example improperly, it produces

<p>
    <figure>
        <img src="/posts/post1/image.png" alt="an image">
        <figcaption>
            <p>an image</p>
        </figcaption>
    </figure>
</p>

Does that not go against the concept of

And you can’t place a block element (e.g., figure) within a p element.

Pull changes or clone again.

git clone --recurse-submodules --single-branch -b hugo-forum-topic-54391 https://github.com/jmooring/hugo-testing hugo-forum-topic-54391
cd hugo-forum-topic-54391
hugo server

You must add this to your site config:

[markup.goldmark.parser]
wrapStandAloneImageWithinParagraph = false

[markup.goldmark.parser.attribute]
block = true
title = true

[markup.goldmark.renderHooks.image]
enableDefault = true

[markup.goldmark.renderHooks.link]
enableDefault = true

That is almost perfect. Thank you so much for all your patience. If I have an empty line before and after my image

blah

![an image](image.png "an image" )

blah

Then it works well. and creates

<p>blah</p>
<figure>
    <img src="/posts/post1/image.png" alt="an image"><figcaption>an image</figcaption></figure><p>blah</p>
<p>blah

But if not

blah
![an image](image.png "an image" )
blah

Then I cannot see my caption. It creates the following html

<p>blah
<img src="/posts/post1/image.png" alt="an image" title="an image">
blah</p>

It’s not too bad to need a new line before and after, it’s just something that I’ll have to remember.

I suggest you spend some time understanding how Markdown behaves, and you can use the reference implementation playground to do so:

https://spec.commonmark.org/dingus/?text=blah ![an%20image](image.png%20"an%20image"%20) blah

1 Like

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