HUGO

How to iterate over headless pages?

That works, but I can’t dynamically iterate over my references anymore.

As @bep said a headless bundle exists outside of the section loop.

A headless bundle is only available through .GetPage

So to render your references pages (that are not headless bundles) you need to range through them separately in your template.

Yes, I understand that.

Currently we have something like a ignore file on the deployment server, which deletes all the files which Hugo generated and we don’t need (about 140 pages). Is there really no other way than this script?

Would a PR be appreciated, which adds another flag to prevent Hugo from outputting pages for flagged content files?

I am already doing what you describe without server scripts.

In Hugo there are disableKinds and many other ways to filter content.

But you need to share your repo for people in this forum to see what you mean by flagged content.

Regarding sending a PR for this in the Hugo repo @bep is the maintainer so he is the one who reviews these things.

But again there are ways to filter content and prevent it from being rendered. We need to see what the use case is before adding more code.

1 Like

Thank you for your answer @onedrawingperday.

I’ve checked out disableKinds before. Unfortunately I can not disable a specific section. Like in the example above, I want to stop Hugo from rendering everything from references.

disableKinds = ["references"] 

This doesn’t have any effect, because according to the docs I can only disable all sections or none.

What are the other ways?

disableKinds is global configuration.

But there is a known hack to disable a specific section.

Unfortunately this pages are still in the sitemap then.

It seems like there is no other way around than do some kind of post-processing after Hugo rendered. :frowning:

You can exclude them from the sitemap with a front matter parameter.

Search the forum. There have been topics about this.

You are talking about this? I’ve found this before. I’ve added hidden = true to all references, but they are still in the sitemap.xml. The documentation didn’t tell me anything about this parameter.

Let me formulate my question again, maybe we understand us wrong.

I’ve a list of references. I use them as a part of the home page and I make them visible there. I just use the content, but Hugo doesn’t need to output anything from this files to rendered pages, to the sitemap or to anything else.

Currently we have a whitelist of file we need and the rest is deleted from the output of Hugo. We realized, that we also need to post-process the sitemap.xml. The only thing which kind of worked so far, is to have empty templates for this sections.

Maybe we are using Hugo in a wrong way?

Front Matter Parameters are user defined. You can name them any way you want.

Here are the contents of a sitemap.xml from a Hugo project of mine

<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
  {{ range .Pages }}{{ if not .Params.hidden }}
  <url>
    <loc>{{ .Permalink }}</loc>
    {{ with .Sitemap.ChangeFreq }}
    <changefreq>{{ . }}</changefreq>{{ end }}{{ if ge .Sitemap.Priority 0.0 }}
    <priority>{{ .Sitemap.Priority }}</priority>{{ end }}
  </url>
  {{ end }}{{ end }}
</urlset>

Every content page with the front matter param hidden = "true" is excluded from the sitemap.

Thank you for this answer.

We started to flag the files and use your template for the sitemap xml.

{{ if .Params.hidden }}
{{ "<!--hidden-->" | safeHTML }}
{{ end }}

And then on the CI/CD we run grep -iRl '<!--hidden-->' --include '*.html' . | xargs -0 rm -f --. That works quite well so far :slight_smile:

This can be improved by deleting the whole folder of the file, so also resources are removed.

grep -iRl '<!--hidden-->' --include '*.html' . | xargs -0 dirname | xargs rm -rf

I’ve been trying to accomplish a similar result as well. I have a section that has a mixture of headless and non-headless pages. On the main listing page I’ve been trying to range over all the pages (both headless and non) to display their name and logo and only the ones that are not headless have a link to their own page for more information.

Unfortunately, the only work around I have right now is to remove them on the sitemap through front-matter. I can’t disableKind the section since there is some I want to have a permalink/page.

1 Like

Would this be too complicated to create a new site variable along the line of .Site.RegularPages.?

We already have an .AllPages to display pages from every languages, so not sure how to call this new .PagesHeadlessOrNot site variable… but we could also only add .Site.HeadlessPages as a site variable and let the user manage the where clause in order to retrieve what he needs.

I think people will need to range on their headless pages eventually, I see a lot of use cases where people use them as data with a bundle… (sponsors, ads, team member) resulting in dozens of headless pages which, at some point in a template, needs to be conveniently iterated over.

As of today, I don’t see any easy way. You have to know where to look in order to create a range on their filename and then use .GetPage on each of them inside the range…

6 Likes

I had the same issue.

To iterate over a folder of headless pages, here is what I did:

{{- $services := slice -}}
{{ range (readDir "content/services") }}
    {{ $services = $services | append ( $.Site.GetPage ( print "services/" .Name ) )  }}
{{ end }}

I was able to do something similar i.e. I needed to access pages programatically without rendering them.

Basically, you need to use readDir and readFile along with unmarshall which allows you to get the front matter at least in a “data” format/interface.

I, too, used readDir for this. I didn’t use readFile or unmarshal though:

You can replace

{{ range .Pages }}
...
{{ end }}

with

{{ $page := . }}
{{ range where (readDir (print "content/" .File.Dir)) ".IsDir" true }}
{{ with $page.GetPage .Name }}
...
{{ end }}
{{ end }}
1 Like

Fairly recently (around start of 2020), Hugo added support for nolist and norender , see:

and:

With that change, it’s now possible to iterate over pages that are essentially “headless”.

I’m doing it this way (the new way) with gallery items on my site. I was previously setting them to headless and using readDir , but I wanted to paginate them, and pagination only works with an actual Pages collection:

My gallery’s _index.html looks like this, to make all the gallery items get listed but for no physical pages to get generated for them:

+++
title = "Gallery"
layout = "gallery"

[_build]
render = "always"

[cascade._build]
render = "never"
list = "local"
+++
<p>Photo gallery for this site.</p>

Can see the result at: Gallery - Jaza's World Trip

Note that in the above front matter, I’m setting list = "local" , which works for my use case, but might not work for all use cases (i.e. if you want to list the “no render” items anywhere else on the site, other than on their parent page). At the moment, if you set list = "always" , then a whole lot of empty items get added to the sitemap (because “no render” items have no permalink). I’ve submitted a bug fix for this at Sitemap: exclude "no render" pages by Jaza · Pull Request #8201 · gohugoio/hugo · GitHub . Once that gets in, it should be safe to set list = "always" if you need to.