basnotes

 

Hugo Search

tip

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:

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