Shortcode for iframe breaking at update Hugo 122.x→123.8

Hello,

I have a custom shortcode for embedding iframes:

{{- $src := .Get "src" }}
{{- if not (in $src "://") }}
	{{- $src = .Page.Resources.GetMatch (printf "*%s*" $src) }}
	{{- $src = $src.RelPermalink }}
{{- end -}}
<iframe src="{{ $src }}"{{ if (.Get "h") }}style="height: {{ .Get "h" }}"{{ end }}>The <a href="{{ $src }}">embedded content</a> cannot be displayed.</iframe>

Usage is like this, e.g. to embed an HTML email saved to content/posts/example-post/mail/mail1.htm:

{{< iframe src="mail/mail1.htm" >}}

After an update from Hugo 122.x (I don’t know the exact version anymore) to 123.8, the shortcode does not find a match anymore (resulting HTML is <iframe src="">). Has the pattern matching behaviour changed?

Thank you in advance for all suggestions!

Is this is multilingual site? If yes is it single-host or multihost?

Can you provide some details, such as the value of src and the tree structure for the page bundle?

Single-language site, very simple setup. Page bundle structure is

.
├── archetypes
│   └── default.md
├── config.toml
├── content
│   └── posts
│       ├── example-post
│       │   ├── index.md
│       │   └── mail
│       │       ├── mail1.htm
│       │       └── mail2.htm
│       ├── other-post
│       │   ├── index.md
│       │   └── img
│       │       └── sample-image.jpg
...

I.e. I create subfolders for article assets such as images or, in the case relevant here, HTML files to be displayed as an iframe.

There’s a bug here, I think, and I will log it.

Background

With v0.123.0 and later we do not blindly copy content page resources (.html, .htm, .adoc, .pdc, .org, .rst, .md) to the public directory when building a site. This is by design.

The bug

The bug is that the Permalink, RelPermalink, and Publish methods are not publishing the resource. There is a workaround, but if I were you I would wait until the issue is either resolved or rejected.

I will add a link to the issue later today.

https://github.com/gohugoio/hugo/issues/12274

I don’t know enough about this to understand if my following hint is already part of your explanation. But please notice that the problem is not getting a “file not found” error in the browser because the HTML file has not been copied over; instead even the iframe’s src attribute is empty, as if the pattern matching has not found any file anymore.

In my example, I have only changed the post title. The “mail1.htm” filename is genuine. By now I have also noticed this happening in another custom shortcode using the same pattern *%s* to find GPX files.

Besides, I’d be happy to be informed that I don’t need this odd pattern; I cannot recollect exactly why it looks like this. Apparently, %s only, without *, did not work before (neither does it now).

This has nothing to do with the pattern. If the resource isn’t published there isn’t a permalink.

The easiest thing to do: use an extension that doesn’t map to a content file (e.g., txt). Can you do that instead? This would allow you to use your existing code.

Otherwise, you’ll need to use either of these examples:
https://github.com/gohugoio/hugo/issues/12274#issuecomment-2007144611

The second example is better in that you don’t have to specify the path twice.

After bep’s review of Issue #12274, we’ve classified this as an enhancement instead of bug, and it probably won’t be addressed in the near term. In the interim, either:

  1. Change the extension of your page resources to something other than .html, .htm, .adoc, .pdc, .org, .rst, or .md.

  2. Use this construct:

    {{ with .Resources.Get "a.html" }}
      {{ (.Content | resources.FromString .Path).RelPermalink }}
    {{ end }}
    

With option 2 above, your shortcode (with lots of error checking) should look something like this:

{{ with .Get "src" }}
  {{ $u := urls.Parse . }}
  {{ if $u.IsAbs }}
    {{ errorf "The src argument passed to the %q shortcode may not be an absolute URL. See %s" $.Name $.Position }}
  {{ else }}
    {{ with $.Page.Resources.Get $u.Path }}
      {{ $src := (.Content | resources.FromString .Path).RelPermalink }}
      <iframe src="{{ $src }}"{{ with $.Get "h" }}style="height: {{ . }}"{{ end }}>The <a href="{{ $src }}">embedded content</a> cannot be displayed.</iframe>
    {{ else }}
      {{ errorf "The %q shortcode was unable to find %s. See %s" $.Name $u.Path $.Position }}
    {{ end }}
  {{ end }}
{{ else }}
  {{ errorf "The %q shortcode requires a src argument. See %s" .Name .Position }}
{{ end }}

Test site to prove it works:

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

I shall try the second suggestion later today. Thank you for posting this! For the first one, I am not overly fond of changing file extensions. This is creating confusion on my side when I look at the files later and webservers might serve files with the wrong mimetype.

That being said, I do not fully understand how my previous solution is going against the concepts of a static site generator, which I understand to mainly consist of copying files together in the right order and doing some processing on the raw resources (Markdown rendering, image resizing and the like).

I am sure there are good reasons for this (from my point of view) unexpected behaviour that I’m just unable to grasp. This message is not intended to provoke, but to further my education. I am glad for your kind support and your splendid work in developing and maintaining this software.

There’s a long story behind this, but with v0.123.0 everything in a bundle is a page resource, and if it’s a content resource (with any of the extensions above) it’s a headless Page and is no longer “blindly” copied. This change was technically and structurally necessary to enable recent improvements and future capabilities, and it elimated some confusing inconsistencies.

One of the recent improvements, enabled by default in v0.123.0 and later, is that we no longer duplicate page resources when building multilingual, single-host sites. This is a huge win which reduces build times, storage requirements, bandwidth consumption, and deployment times, ultimately reducing cost.

For those who wish to truly copy files, they should go in the static directory. That does not fit your use case, hence the revised shortcode above. Yes, the revised shortcode is longer, but only because I added some missing error checks.

To what are the "it"s in this sentence referring? I assume in “if it’s a content resource” it means “everything”. And then a content resource with one of the extensions becomes a “headless Page”? So, “iframe.html”, for example, is a headless Page in a bundle, a content resource, and a page resource, all at the same time?
I don’t want to pester you, but I find English grammar sometimes a bit ambiguous. Also, the term “headless page” is new to me, in the documentation I only found “headless bundle”.

Less time than what I hoped for … but thank you, that seems to work for the iframe. What I noticed is that it seems not to be backward compatible (I switched back to Hugo 0.122 to make my website work again before you posted your solution); this is certainly because of the changes you mentioned.

We’ll handle this here:
https://github.com/gohugoio/hugoDocs/issues/2428

@erichc

I would like to amend the shortcode above:

{{ with .Get "src" }}
  {{ $u := urls.Parse . }}
  {{ if $u.IsAbs }}
    {{ errorf "The src argument passed to the %q shortcode may not be an absolute URL. See %s" $.Name $.Position }}
  {{ else }}
    {{ with $.Page.Resources.Get $u.Path }}
      {{ $src := (.Content | resources.FromString (path.Join $.Page.Path .Name)).RelPermalink }}
      <iframe src="{{ $src }}"{{ with $.Get "h" }}style="height: {{ . }}"{{ end }}>The <a href="{{ $src }}">embedded content</a> cannot be displayed.</iframe>
    {{ else }}
      {{ errorf "The %q shortcode was unable to find %s. See %s" $.Name $u.Path $.Position }}
    {{ end }}
  {{ end }}
{{ else }}
  {{ errorf "The %q shortcode requires a src argument. See %s" .Name .Position }}
{{ end }}

This modifies line 7, changing it from:

{{ $src := (.Content | resources.FromString .Path).RelPermalink }}

to:

{{ $src := (.Content | resources.FromString (path.Join $.Page.Path .Name)).RelPermalink }}

The reason for this change? The Path method on a page resource is, at least for now, intentionally undocumented. See https://github.com/gohugoio/hugo/issues/12143.

I’ve update the test site:

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

One more thing that I noticed is that the new code changes the file names – they become all lowercase. This happens for first code suggestion and for the changed one with path.Join.

Probably one should not rely on case sensitivity anyway, but is there an apparent reason? I don’t see a .ToLower.

I’d have to look at a specific example, but with version 0.123.0 and later, the resource name is lowercase.

And you are correct. It is always best to use lowercase and hyphens instead of spaces.

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