Question: is `page` supposed to work inside of a shortcode?

A while back the page method was introduced, giving us access to the current page object. I thought that this is supported anywhere, in any layout, but when I run my website with a specific shortcode that is loading page resources via page.Resources. inside of the shortcode this is not working the first time when I run the server - the page object contains the archive page for all subsequent shortcode calls (created via content/archive/index.md. The first shortcode call works as expected. Every subsequent time it is called (all markdown files inside of a section have that shortcode) the return of page.Resources is empty (the archives page has no resources). After changing any arbitrary part of the specific shortcode layout file and waiting for the server to reload, the page object is filled properly and the resources exist.

Using .Page.Resources. instead of page.Resources in the shortcode fixes this behaviour.

So my question is: Do we expect page to work inside a shortcode? It feels like the output/content of the function is, when working, different too (.Page gives more elements than page).

I couldn’t find a documentation page for page (4 characters seem not enough to filter through the index to show usable entries in the search), so I am going only from the release notes in the link above.

If wanted I can write up a use case to re-create the issue, my repo is a bit complicated structured and the shortcode in question is inside of a module, specifically here.

If page is not expected to return something usable, it should show some warning or error. Else I am 50/50 on this being a bug in Hugo or my own layout files. That it brings up the “Archives” page feels like an “sort alphabetically” thing on the pages-index.

Edit: hugo v0.114.1-e9b716ad9869b79e7c374bbdae4daf5ee6406bd4+extended linux/amd64 BuildDate=2023-06-23T11:02:58Z VendorInfo=gohugoio

be careful, page function always point to current page being executed

with this content structure

content/
  _index.md
  first-post.md
  second-post.md
  third-post.md

with this home layout, layouts/_default/home.html, home page being executed.

{{ range .Pages }}
  
  {{ . }} --> this is first-post,second-post, and third-post page object
  {{ page }} --> page function always point to home page object
  {{ .Content }} --> contains `foo` shortcodes
  
{{ end }}

with layouts/shortcodes/foo.html:

{{ page }} <-- still point to home page object
1 Like

Right. I missed to note that I am talking about single pages. The shortcode is not visible on list pages.

Edit: On a second thought, you might have a point. Maybe there is content cached via a partial call on that archive page. I’ll check that, but food for thought: WHY is the first component having proper data. WHY is changing content fixing the issue in all pages using the shortcode (using --disableFastRender). It feels like that is not the cause of the issue.

Edit2: not cached.

Once Hugo evaluates a page’s content, the content is cached, as it should be.

The following page variables force evaluation of a page’s content:

  • Content
  • FuzzyWordCount
  • Plain
  • PlainWords
  • ReadingTime
  • Summary (regardless of whether or not it is defined in front matter)
  • TableOfContents
  • Truncated
  • WordCount

So if you do this on a list page (and you do)…

{{ range .Pages }}
  <h2><a href="{{ .RelPermalink }}">{{ .LinkTitle }}</a></h2>
  {{ .Summary }}  <-- FORCES CONTENT TO BE EVALUATED AND CACHED
{{ end }}

… each page’s content is evaluated and cached when building the list page.

And within each iteration, the page function is the context of the top level page in the template (in this case, the list page).

So, if each page calls a shortcode like this…

{{ with page.Resources.Get "cover.jpg" }}
  <img src="{{ .RelPermalink }}" width="{{ .Width }}" height="{{ .Height }}" alt="">
{{ end }}

… then page.Resources.Get isn’t going to find anything—it’s looking for resources associated with the list page. It all depends on whether the regular page is rendered (and cached) before the list page, but with concurrency that’s out of your control. In short, the results are unpredictable.

Use .Page.Resources.Get in your shortcode.


As @pamubay pointed out, you need to be really careful about how you use the page function. My favorite example:

layouts/home.html

{{ range site.Sections }} <-- 3 sections
  {{ range .Pages }}  <-- 10 pages in each section
    {{ page.Title }}
  {{ end }}
{{ end }}

This will print the title of content/_index.md (the home page) 30 times. Probably not you want.

While this is a very nice explanation of the traps we can fall in using that code, it does not explain the main question: In a single page (e.g. Robots ↭ GoHugo Components ↭ KOLLITSCH.dev*), a shortcode using page should show the table you can see now. It does not. The page method returns values for a page Archives which is not in that specific section. It’s the first page object in the filesystem of content.

.Page shows the right information. Replacing with .Page solves the issue, so I am closing this topic.

This doesn’t explain why page works on the first occurrence of the single pages (the latest entry in the section) and not on subsequent ones.

Using .Summary on list pages is another way not to get trapped by the context of the function.

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