HUGO

Avoid empty pages, display page types in search

Hey everyone! I’m sorry to take up your time, but I’ve got a bit of a puzzle and I’m having a hard time sorting it out.

I am using LunrJS to search my website based on the guide here.

In short: I use hugo’s build process to build out an index.json file at root/index.json and then search that with Lunr.

I modified the tutorial code to take search input via URL parameters so search can be done from any page (dumps you on a SERP).

The problem I’m having is two-fold:

  1. I want to somehow catch and display my page type in the SERP
  2. I want to avoid indexing empty pages.

Relevant Links:

Now to the first problem

I’m currently having trouble displaying even the category! Much less catching and displaying the page type, or making the category display conditional.

Here is the relevant code:

function renderSearchResults(results){

    if (results.length > 0) {

        // show max 10 results
        if (results.length > 9){
            results = results.slice(0,10)
        }

        // reset search results
        searchResults.innerHTML = ''

        // append results
        results.forEach(result => {
        
            // create result item
            var article = document.createElement('article')
            article.innerHTML = `
            <div class="p-4">
              <div class="h-full bg-gray-300 hover:shadow-xl transition-all duration-200 bg-opacity-75 px-8 pt-16 pb-24 rounded-lg overflow-hidden text-center relative">
                <h2 class="tracking-widest text-xs title-font font-medium text-gray-400 mb-1">${documents.[result.ref].categories}</h2>
                <a href="${result.ref}">
                  <h1 class="title-font sm:text-2xl text-xl font-medium text-gray-900 mb-3">
                    ${documents[result.ref].title}
                  </h1>
                </a>
                <p class="leading-relaxed mb-3">${truncateString(documents[result.ref].content, 175)}</p>
                <a href="${result.ref}" class="text-indigo-500 inline-flex items-center">Learn More
                  <svg class="w-4 h-4 ml-2" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2" fill="none" stroke-linecap="round" stroke-linejoin="round">
                    <path d="M5 12h14"></path>
                    <path d="M12 5l7 7-7 7"></path>
                  </svg>
                </a>
              </div>
            </div>
            `
            searchResults.appendChild(article)
        })

    // if results are empty
    } else {
        searchResults.innerHTML = '<p>No results found.</p>'
    }
}

Link to full page

Next, Avoiding Empty Pages.

I’ve tried using {{- with .Content -}} before my JSON, but that wacks my variable scoping for everything else, and I’m not smart enough to understand variable scoping lol

Here’s the relevant code for the JSON build:

[
  {{ range $index, $value := .Site.Pages }}
    {{ if $index }}, {{ end }}
    {
      "url": "{{ .RelPermalink }}",
      "title": "{{ .Title }}",
      "content": {{ .Content | plainify | jsonify }}{{- with .Params.categories -}},
      "categories": {{ . | jsonify }}{{- end -}}
    }
  {{ end }}
]

On Repo
Link To Built JSON File

I hope my questions make sense! Let me know if I need to add anything or clarify anything. I’ve put everything I could think of in here, and I appreciate your help!

Okay. I’ve partially solved my problem. I gave up on the categories bit and switched over to page-type instead - which I’m fine with.

I’ve got that working with the following code:

[
  {{ range $index, $value := where .Site.Pages "Type" "ne" "Page" }}
    {{ if $index }}, {{ end }}
    {
      "url": "{{ .RelPermalink }}",
      "title": "{{ .Title }}",
      "content": {{ .Content | plainify | jsonify }},
      "type": {{- if ( eq .Type "blog") -}}"Blog Post"{{- else if ( eq .Type "concord") -}}"Book of Concord"{{- else if ( eq .Type "answers") -}}"Questions & Answers"{{- else -}}{{ .Type | jsonify }}{{- end -}}

    }
  {{ end }}
]

So now my JSON file is building correctly with page type, and using custom values for some of the page types. (yay!)

What I want to know is how can I exclude regular pages from the build? You can see I’m trying to filter the range with no luck:

{{ range $index, $value := where .Site.Pages "Type" "ne" "Page" }}

Ideas?

I’m also trying to avoid ranging through pages that don’t have any content other than front-matter (which I don’t believe counts as content). To that end I’ve also got this that doesn’t work:

{{ range $index, $value := where .Site.Pages "Content" "ne" nil }}

Check for a page’s .Kind: Page Variables | Hugo

Or range over site.RegularPages: Site Variables | Hugo . - edit: you said to exclude

Check for len .Content : len | Hugo

So something like this, untested:

{{ $pages := slice }}
{{ range site.Pages }}
  {{ if  and (gt (len .Content) 0) (ne .Kind "page") }}
    {{ $pages = $pages | append . }}
  {{ end }}
{{ end }}

{{ range $pages }}
...

Thank you for the help! I modified the file thus:

{{ $pages := slice }}
{{ range site.Pages }}
  {{ if  and (gt (len .Content) 0) (ne .Kind "page") }}
    {{ $pages = $pages | append . }}
  {{ end }}
{{ end }}
[
  {{ range $index, $value := $pages }}
    {{ if $index }}, {{ end }}
...

I went that route because the {{ if $index }}, {{ end }} bit adds the necessary comma to the JSON format on every pass except the last one. However now I’m getting an empty JSON file.

I puzzled on it a bit more and decided that, instead of using content or page type, I could simplify this process by creating a variable in the page front matter and scanning for that, building the page if the variable is false.

Thus, in every page I don’t want built into my JSON file, I included this new Param: avoid: true

Then built my JSON file with the following range

[
  {{ range $index, $value := where .Site.Pages "Params.avoid" "ne" "true" }}
    {{ if $index }}, {{ end }}
...

Works like a charm!

Thank you for the help! You got me thinking about the logic of it and pulled me to the answer.

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