How to iterate over headless pages?

#1

Dear community

On my home page I render a list of references. The tree looks like this:

  • Root / home page
    • References
      • Reference A
        • index.md
        • index.en.md
      • Reference B
        • index.md
        • index.en.md
      • Reference C
        • index.md
        • index.en.md

In this index.md files I set headless to true. As expected the file is not rendered, but the reference is also not rendered on my home page, where I use the following template code:

<section id='references'>
    {{ with .Site.GetPage "section" "references" }}
    <h2>{{ .Title }}</h2>
    {{ .Content }}
    <div class='references-container'>
        {{ range .Pages }}
        <span class='reference'>
            <a href='{{ .Params.website }}'>
            {{ with .Resources.GetMatch .Params.logo }}
            {{ $image := .Fit "1000x100" }}
            <img src='{{ $image.RelPermalink }}'>
            {{ end }}
            </a>
        </span>
        {{ end }}
    </div>
    {{ end }}
</section>

How can make the references appear and stop Hugo from rendering unused files?

Thank you in advance!

#2

Please read Requesting Help for tips on getting help in the forums.

You include a lot of information in your posts, but in order to reproduce the issues, we’d have to build a Hugo project and paste in snippets and produce dummy content… not fun!

So please share a link to a repo that one can clone and see your issue.

#3

Thank you for your response @maiki.

I totally get your point. Here is an example repository: https://github.com/openscript/hugo-headless-example

Here is a short gif which explains my question quite well (I hope at least):

How can I render the “first” reference in this case, but prevent Hugo from outputting a separate file for this reference?

Thank you in advance :slight_smile:

#4

Try:

Site.GetPage "references"  "first"
#5

Headless pages are not a member of any of the site collections, and you will then not see it in {{ with .Site.GetPage "section" "references" }}.

They have a very specific intended use case: A collection of reusable page snippets, images etc., but you have to be explicit when doing lookups.

#6

I understand your answer and thank you for that, but how do I prevent the output of unnecessary files in this case?

#7

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

#8

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.

#9

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?

#10

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
#11

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?

#12

disableKinds is global configuration.

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

#13

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:

#14

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

Search the forum. There have been topics about this.

#15

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?

#16

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.

#17

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
#18

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
#19

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…

5 Likes
#20

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 }}