Algolia Search Integration

When trying to use algolia with trellis I get this error when I search. Has anyone succesfully integrated these solutions so I can use algolias widgets. The instant search works good but the site search breaks once I activate algolia

Notice : Theme without footer.php is deprecated since version 3.0.0 with no alternative available. Please include a footer.php template in your theme.

I would assume that it is overriding templates.

Looking at the docs it seems you can override them with your blade templates.

Give it a go and see how you get on.

This is a Sage issue, not a Trellis one. I expect you’d be able to customize the Algolia templates by adding them either to the root is the Sage theme directory, or to resources (it could be either depending on how the plugin is developed) and try removing the get_header() and get_footer() as a start.

I got the overide working yet I cant seem to route all the blade data into it. Not sure how I can integrate blade outisde of the views folder. The algolia files are in the resources folder but not in views with all the blade goodies.

As you can see here the app loads well yet all those nice blade includes that makes up the rest of the side will not render.

Someone please save me and I will buy you a nice import six pack of beer of your choice :slight_smile:

You can manually render a Blade with data with the template() function. The source code for it is here:

You just pass it the blade you want to render, and the data you want to use to render it:

// partials/example.blade.php
<h1>{{ $title }}</h1>

// some-file.php
namespace App;

echo template('partials.example', ['title' => 'Hello Kahlil']);

// <h1>Hello Kahlil</h1>

thank you Always Blank!
I got it started.
There are some errors still with navigation etc.

I posted the code on github so you could see what is going on in my resources folder

The footer part of the template looks great!
Not sure why the header has all those undefined variable notices also why the css for the menus is all mest along with broken logo code.

Hey, so it looks like the Controller data isn’t loading, so those variables are all unset.

What you probably need to do is somehow call the Controller (probably App) and put its data into the template() call.

Hey @withjacoby can you easily make a specific controller’s data available to a template called outside the normal Sage process? Like is there a function call you could make as the second argument in template()?

You should be able to use this filter to get variables from the controller.

$data = apply_filters('sage/template/app-data/data', []);
echo template('template', $data);

Replace app-data with the controller you want example-data.

2 Likes

I worked with @Kahlil_Calavas on this and here’s what we came up with:

Create Algolia’s template override

Per Algolia’s template-override instructions (adapted for Sage’s structure) create resources/algolia/instantsearch.php:

<?php
// resources/algolia/instantsearch.php
namespace App;

$data = apply_filters('sage/template/app-data/data', []);
echo template('algolia', $data);

Make our blade-friendly template that the above file includes

Create the partial referenced above, resources/views/algolia.blade.php:

{{-- resources/views/algolia.blade.php --}}
@extends('layouts.app')

@section('content')
  @include('partials.page-header')
  @include('partials.content-algolia')
@endsection

Make a separate partial as a .php file because Liquid and Blade aren’t friends

Since Algolia uses Liquid templates which conflict with the Blade syntax, make a plain PHP file for the actual Algolia markup, resources/views/partials/content-algolia.php

<?php 
 // Something like this. This is the default.
?>
<div id="algolia-search-box">
  <div id="algolia-stats"></div>
    <svg class="search-icon" width="25" height="25" viewBox="0 0 40 40" xmlns="http://www.w3.org/2000/svg"><path d="M24.828 31.657a16.76 16.76 0 0 1-7.992 2.015C7.538 33.672 0 26.134 0 16.836 0 7.538 7.538 0 16.836 0c9.298 0 16.836 7.538 16.836 16.836 0 3.22-.905 6.23-2.475 8.79.288.18.56.395.81.645l5.985 5.986A4.54 4.54 0 0 1 38 38.673a4.535 4.535 0 0 1-6.417-.007l-5.986-5.986a4.545 4.545 0 0 1-.77-1.023zm-7.992-4.046c5.95 0 10.775-4.823 10.775-10.774 0-5.95-4.823-10.775-10.774-10.775-5.95 0-10.775 4.825-10.775 10.776 0 5.95 4.825 10.775 10.776 10.775z" fill-rule="evenodd"></path></svg>
  </div>
  <div id="algolia-hits"></div>
  <div id="algolia-pagination"></div>

<aside id="ais-facets">
  <section class="ais-facets" id="facet-post-types"></section>
  <section class="ais-facets" id="facet-categories"></section>
  <section class="ais-facets" id="facet-tags"></section>
  <section class="ais-facets" id="facet-users"></section>
</aside>

<script type="text/html" id="tmpl-instantsearch-hit">
  <article itemtype="http://schema.org/Article">
    <# if ( data.images.thumbnail ) { #>
    <div class="ais-hits--thumbnail">
      <a href="{{ data.permalink }}" title="{{ data.post_title }}">
        <img src="{{ data.images.thumbnail.url }}" alt="{{ data.post_title }}" title="{{ data.post_title }}" itemprop="image" />
      </a>
    </div>
    <# } #>

    <div class="ais-hits--content">
      <h2 itemprop="name headline"><a href="{{ data.permalink }}" title="{{ data.post_title }}" itemprop="url">{{{ data._highlightResult.post_title.value }}}</a></h2>
      <div class="excerpt">
        <p>
    <# if ( data._snippetResult['content'] ) { #>
      <span class="suggestion-post-content">{{{ data._snippetResult['content'].value }}}</span>
    <# } #>
        </p>
      </div>
    </div>
    <div class="ais-clearfix"></div>
  </article>
</script>


<script type="text/javascript">
  jQuery(function() {
    if(jQuery('#algolia-search-box').length > 0) {
      if (algolia.indices.searchable_posts === undefined && jQuery('.admin-bar').length > 0) {
        alert('It looks like you haven\'t indexed the searchable posts index. Please head to the Indexing page of the Algolia Search plugin and index it.');
      }
      /* Instantiate instantsearch.js */
      var search = instantsearch({
        appId: algolia.application_id,
        apiKey: algolia.search_api_key,
        indexName: algolia.indices.searchable_posts.name,
        urlSync: {
          mapping: {'q': 's'},
          trackedParameters: ['query']
        },
        searchParameters: {
          facetingAfterDistinct: true,
    highlightPreTag: '__ais-highlight__',
    highlightPostTag: '__/ais-highlight__'
        }
      });
      /* Search box widget */
      search.addWidget(
        instantsearch.widgets.searchBox({
          container: '#algolia-search-box',
          placeholder: 'Search for...',
          wrapInput: false,
          poweredBy: algolia.powered_by_enabled
        })
      );
      /* Stats widget */
      search.addWidget(
        instantsearch.widgets.stats({
          container: '#algolia-stats'
        })
      );
      /* Hits widget */
      search.addWidget(
        instantsearch.widgets.hits({
          container: '#algolia-hits',
          hitsPerPage: 10,
          templates: {
            empty: 'No results were found for "<strong>{{query}}</strong>".',
            item: wp.template('instantsearch-hit')
          },
          transformData: {
            item: function (hit) {
              function replace_highlights_recursive (item) {
                if( item instanceof Object && item.hasOwnProperty('value')) {
                  item.value = _.escape(item.value);
                  item.value = item.value.replace(/__ais-highlight__/g, '<em>').replace(/__\/ais-highlight__/g, '</em>');
                } else {
                  for (var key in item) {
                    item[key] = replace_highlights_recursive(item[key]);
                  }
                }
                return item;
              }
              hit._highlightResult = replace_highlights_recursive(hit._highlightResult);
              hit._snippetResult = replace_highlights_recursive(hit._snippetResult);
              return hit;
            }
          }
        })
      );
      /* Pagination widget */
      search.addWidget(
        instantsearch.widgets.pagination({
          container: '#algolia-pagination'
        })
      );
      /* Post types refinement widget */
      search.addWidget(
        instantsearch.widgets.menu({
          container: '#facet-post-types',
          attributeName: 'post_type_label',
          sortBy: ['isRefined:desc', 'count:desc', 'name:asc'],
          limit: 10,
          templates: {
            header: '<h3 class="widgettitle">Post Type</h3>'
          },
        })
      );
      /* Categories refinement widget */
      search.addWidget(
        instantsearch.widgets.hierarchicalMenu({
          container: '#facet-categories',
          separator: ' > ',
          sortBy: ['count'],
          attributes: ['taxonomies_hierarchical.category.lvl0', 'taxonomies_hierarchical.category.lvl1', 'taxonomies_hierarchical.category.lvl2'],
          templates: {
            header: '<h3 class="widgettitle">Categories</h3>'
          }
        })
      );
      /* Tags refinement widget */
      search.addWidget(
        instantsearch.widgets.refinementList({
          container: '#facet-tags',
          attributeName: 'taxonomies.post_tag',
          operator: 'and',
          limit: 15,
          sortBy: ['isRefined:desc', 'count:desc', 'name:asc'],
          templates: {
            header: '<h3 class="widgettitle">Tags</h3>'
          }
        })
      );
      /* Users refinement widget */
      search.addWidget(
        instantsearch.widgets.menu({
          container: '#facet-users',
          attributeName: 'post_author.display_name',
          sortBy: ['isRefined:desc', 'count:desc', 'name:asc'],
          limit: 10,
          templates: {
            header: '<h3 class="widgettitle">Authors</h3>'
          }
        })
      );
      /* Start */
      search.start();
      jQuery('#algolia-search-box input').attr('type', 'search').select();
    }
  });
</script>

You could even break out some of the elements into @stacks!

EDIT: you could PROBABLY rewrite the Liquid syntax to be echoed by Blade correctly but… meh?

3 Likes

Thank you so much. If you see above in the thread I offered a six pack of your beer of choice to whomever helped me figure this out. So what will it be good sir?!!?

This topic was automatically closed after 42 days. New replies are no longer allowed.