Can't delimit variables from Pages

I can provide a more specific example, but let’s just say I would like to delimit .Site.RegularPages.Permalink. This would seem to be much more performant than using a range and appending them to a slice. However, I get an error:

can’t evaluate field Permalink in type page.Pages

However, I am able to delimit .Site.RegularPages which isn’t very helpful. Is the logic here basically that Pages aren’t evaluated until you use a range? Would it make sense for performance reasons to make a feature request for a function that can do that without a range?

There is no such thing as .Site.RegularPages.Permalink .

.Permalink is a .Page variable.
.Site.RegularPages does not have a .Permalink field because .Site.RegularPages is a collection of .Pages.

While I agree, there is indeed a .Permalink for each page in the slice. For example, if you do the following you can get the first one:

{{ (index .Site.RegularPages 0).Permalink }}

Additionally, it shows the type as a slice if I do:

{{ .Site.RegularPages | reflect.IsSlice }}

Maybe I’m misunderstanding, but should there not be a function in Go to get a common variable in each slice based on a predictable key?

.Site.RegularPages is a collection of Pages.

.Site.RegularPages can be thought of as [Page1, Page2, Page3] etc

(index .Site.RegularPages 0) = .Site.RegularPages[0] 
                             = Page1 
                             = .Page

(index .Site.RegularPages 0).Permalink 
            = .Site.RegularPages[0].Permalink 
            = Page1.Permalink 
            = .Page.Permalink
            = valid

.Site.RegularPages.Permalink = [Page1, Page2, Page3].Permalink, 
                             = not valid.
1 Like

You don’t write Go in Hugo. Only Go Template plus the functions and methods the maintainers have had the time and energy to add on. Assuming that all your needs should be covered by a given tool is not very helpful to you or the members of this community.

Now, back to the topic at hand: what you’re looking for is apply which applies a function to the elements inside your slice and return a slice with the function’s returned values.

For what you’re trying to achieve though, it’s not out of the box. There is no global function to retrieve the permalink, only a Page object’s method and as index cannot be used on a page object the following:

  {{ $pagesPermalinks := apply site.RegularPages "index" "." "RelPermalink }}

Is not going to work.

If you really do not want to use a range or are confident that it would be slower than apply then what you should do is:

  1. Create a returning partial to return said permalink (say in layouts/partials/GetPermalink.html):
{{ return .RelPermalink }}
  1. Call said partial using apply
  {{ $pagesPermalinks := apply site.RegularPages "partial" "GetPermalink" "."  }}

Now you’ve got a slice populated with your site.RegularPages permalinks.

1 Like

Thank you. I didn’t want to come off as being demanding or unappreciative. I had tried using apply, but didn’t fully understand how to do it in this scenario. What you describe works great. I could be wrong in my assumption that using a range is slower. It is my understanding that a range works like a loop, having to iterate over each page. I tried validating this by running hugo --templateMetrics in a loop 30 times and totaling the result, however testing is pretty inconclusive and only shows small benefits to this technique over using a range. It still may prove useful though in simplifying some aspects of my templates.

1 Like

I think apply is a good optimization if your project will scale big and you might end up ranging over thousands of pages many times during the build.

For a small project or if you’re confident this “range” will only happen once, the power of Hugo should have your back.