Hugo Search
Although my site does not yet contain much content, I thought it would be nice to have some kind of search functionality. I found some nice solutions and this is what I did:
I looked for hugo search plugin and ran into the search for your hugo website page which references several nice solutions.
Going over them, I had the following requirements:
- should not require server side functionality
- should not depend on a 3rd party solution
- should preferably not change my work-flow for deploying my site
These requirements narrowed the options down to match Github Gist for Fuse.js integration.
Basic working
The basic working is fairly simple. Hugo allows to create a template for multiple formats including JSON. So, a
index.json
template is defined which results in a big json file in the root of the site containing all relevant
information for client-side search.
Some Javascript on the search page then scoops up that file using a jQuery
$.getJSON()
call and feeds it to the Fuse.js
library which is doing the searching. The results are then shown in
the search page.
Modifications
I made some changes to the JSON template to remove the tags I’m not using, to include the date of a post and to exclude the search page.:
layouts/_default/index.json
---
+++
@@ -1,5 +1,7 @@
{{- $.Scratch.Add "index" slice -}}
{{- range .Site.RegularPages -}}
- {{- $.Scratch.Add "index" (dict "title" .Title "tags" .Params.tags "categories" .Params.categories "contents" .Plain "permalink" .Permalink) -}}
+ {{- if not (in .Params.categories "search") -}}
+ {{- $.Scratch.Add "index" (dict "title" .Title "date" (.Date.Format "January 2, 2006") "categories" .Params.categories "contents" .Plain "permalink" .Permalink) -}}
+ {{- end -}}
{{- end -}}
{{- $.Scratch.Get "index" | jsonify -}}
In the search.js
file I added the date key to include when rendering the template:
static/js/search.js
---
+++
@@ -65,13 +65,13 @@
if(snippet.length<1){
snippet += contents.substring(0,summaryInclude*2);
}
//pull template from hugo templarte definition
var templateDefinition = $('#search-result-template').html();
//replace values
- var output = render(templateDefinition,{key:key,title:value.item.title,link:value.item.permalink,tags:value.item.tags,categories:value.item.categories,snippet:snippet});
+ var output = render(templateDefinition,{key:key,title:value.item.title,date:value.item.date,link:value.item.permalink,tags:value.item.tags,categories:value.item.categories,snippet:snippet});
$('#search-results').append(output);
$.each(snippetHighlights,function(snipkey,snipvalue){
$("#summary-"+key).mark(snipvalue);
});
Initially the search.html
file didn’t work for me, because it tried to include files not present in my site. So I
updated it to integrate without errors and have the same look-and-feel as the rest of the site:
---
+++
@@ -1,27 +1,28 @@
-{{ define "footerfiles" }}
+{{ partial "header" . }}
+{{ partial "searchbar" . }}
+
+<div id="search-results">
+
+ <h1>Search results</h1>
+
+</div>
<script src="https://code.jquery.com/jquery-3.3.1.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/fuse.js/3.2.0/fuse.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/mark.js/8.11.1/jquery.mark.min.js"></script>
<script src="{{ "js/search.js" | absURL }}"></script>
-{{ end }}
-{{ define "main" }}
-<section class="resume-section p-3 p-lg-5 d-flex flex-column">
- <div class="my-auto" >
- <form action="{{ "search" | absURL }}">
- <input id="search-query" name="s"/>
- </form>
- <div id="search-results">
- <h3>Matching pages</h3>
- </div>
- </div>
-</section>
-<!-- this template is sucked in by search.js and appended to the search-results div above. So editing here will adjust style -->
<script id="search-result-template" type="text/x-js-template">
- <div id="summary-${key}">
- <h4><a href="${link}">${title}</a></h4>
- <p>${snippet}</p>
- ${ isset tags }<p>Tags: ${tags}</p>${ end }
- ${ isset categories }<p>Categories: ${categories}</p>${ end }
+<article>
+ <div class="meta">
+ <p class="date">
+ ${date}
+ </p>
+ <p class="category_in_list"><a href="/categories/${categories}">${categories}</a></p>
+ <a href="${link}"><h1>${title}</h1></a>
+ <p>
+ ${snippet}
+ </p>
+ <a href="${link}" class="button">read more</a>
</div>
+</article>
</script>
-{{ end }}
+{{ partial "footer" . }}
Conclusion
eddiewebs gist has worked well for me to add a search feature to my site without too much hassle.
September 15, 2020