WordPress to Jekyll part 3 - Site search

Part of my series on migrating from WordPress to Jekyll.

  1. My history & reasoning
  2. Comments & commenting
  3. Site search
  4. Categories & tags
  5. Hosting & building

Site search is a feature that WordPress got right and, importantly, analytics tell me is popular. A static site is once again at a big disadvantage but we have some options to address that.

Considering options

My first consideration was to use Google Site Search but that was deprecated last year. There are alternative options but few are free. I’m not opposed to people being paid for their services, something has to keep the lights on, but a small personal blog with no income stream can’t justify the cost.

My next thought was to generate reverse index JSON files during site build and then write some client-side JavaScript that would utilize them as the user types in the search box to find the relevant posts. It’s an idea I might come back to but the migration had already taken longer than I anticipated and I like to ship fast and often :)

Algolia

I soon came across Algolia which not only provides a simple API and a few helper libraries but also a Jekyll plug-in to generate the necessary search indexes AND has a free tier that requires just a logo placement and link to their site! Awesome.

Setup was a breeze and Algolia have a specific guide to indexing with Jekyll that was useful. Once you’ve signed up the main parts are configuring indexing and integrating with your site.

Index integration

First install the jekyll-algolia gem making sure it’s specified in your gemfile.

Then configure your Jekyll _config.yml so it knows what to index and where as well as what document attributes are important:

algolia:
  application_id: {your-algolia-app-id}
  index_name: {your-algolia-index-name}
  settings:
    searchableAttributes:
      - title
      - excerpt_text
      - headings
      - content
      - categories
      - tags
    attributesForFaceting:
      - type
      - searchable(categories)
      - searchable(tags)
      - searchable(title)

Finally you’ll need to run the indexing. You need to ensure the environment variable ALGOLIA_API_KEY is set to your private Admin API Key from your Algolia API Keys page then run the following command after your site is built:

bundle exec jekyll algolia

Site integration

Wiring up the search box can be a little overwhelming as they have so many clients, options and APIs available. I went with a design that presents the results as you type like this:

This uses two of their libraries - the search lite and the search helper plus some code to wire it up to my search box and render the results in a drop-down list. I’ll probably further tweak the result format and maybe consider wiring up to the API directly as two libraries for such a simple use case seems a bit overkill.

<script src="https://cdn.jsdelivr.net/npm/algoliasearch@3/dist/algoliasearchLite.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/algoliasearch-helper@2.26.0/dist/algoliasearch.helper.min.js"></script>
<script>
  let searchForm = document.getElementById('search-form')
  let hits = document.getElementById('hits')
  let algolia = algoliasearch('{your-algolia-app-id}', '{your-algolia-search-token}')
  let helper = algoliasearchHelper(algolia, '{your-algolia-index-name}',
    { hitsPerPage: 10, maxValuesPerFacet: 1, getRankingInfo: false })
  helper.on('result', searchCallback)

  function runSearch() {
    let term = document.getElementById('s').value
    if (term.length > 0)
      helper.setQuery(term).search()
    else
      searchForm.classList.remove('open')
  }

  function searchCallback(results) {
    if (results.hits.length === 0) {
      hits.innerHTML = '<li><a>No results!</a></li>'
    } else {
      renderHits(results)
      searchForm.classList.add('open')
    }
    let credits = document.createElement('li');
    credits.innerHTML = "<img src=\"https://www.algolia.com/static_assets/images/press/downloads/search-by-algolia.svg\" onclick=\"window.open('https://www.algolia.com', '_blank')\" />"
    hits.appendChild(credits)
  }

  function renderHits(results) {
    hits.innerHTML = ''
    for (let i = 0; i < results.hits.length; i++) {
      let li = document.createElement('li')
      let title = document.createElement('a')
      title.innerHTML = results.hits[i]._highlightResult.title.value
      title.href = results.hits[i].url
      li.appendChild(title)
      hits.appendChild(li)
    }
  }
</script>

Analytics

I’m a big proponent of analytics when used purely for engineering improvement and Algolia provides a useful dashboard to let you know how performance is doing, what topics are being searching for and what searches might not be returning useful content.

I’ll dig through that when I have a little more time however. The backlog of ideas for posts is taking priority right now!

[)amien Note: I did not and do not receive any compensation from Algolia either directly or via any kind of referral program. I’m just a happy user.

No responses yet