# Algolia Search Integration

**URL:** https://discourse.roots.io/t/algolia-search-integration/15047
**Category:** sage
**Created:** 2019-03-12T17:01:35Z
**Posts:** 10

## Post 1 by @Kahlil_Calavas — 2019-03-12T17:01:35Z

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.

---

## Post 2 by @codepuncher — 2019-03-12T18:16:11Z

I would assume that it is overriding templates.

Looking at the [docs](https://community.algolia.com/wordpress/customize-search-page.html) it seems you can override them with your blade templates.

Give it a go and see how you get on.

---

## Post 3 by @MWDelaney — 2019-03-13T04:51:08Z

This is a Sage issue, not a Trellis one. I expect you’d be able to [customize the Algolia templates](https://community.algolia.com/wordpress/customize-search-page.html) 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.

---

## Post 4 by @Kahlil_Calavas — 2019-03-19T21:57:38Z

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.

 ![34%20PM](https://discourse.roots.io/uploads/default/original/2X/c/cfcca50ea26e68b9236fc6b05ad580649a274fc7.png)

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.

 ![52%20PM](https://discourse.roots.io/uploads/default/original/2X/a/ac54f831fba9aa694795fbbe0fa4eedc902a045c.png)

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

---

## Post 5 by @alwaysblank — 2019-03-19T22:14:20Z

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

> <https://github.com/roots/sage/blob/f3e794a09374d2f110742d15b9b975490fcddbee/app/helpers.php#L48-L56>

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>
```

---

## Post 6 by @Kahlil_Calavas — 2019-03-20T03:17:16Z

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

 ![05%20PM](https://discourse.roots.io/uploads/default/original/2X/a/a308839832381daf3691556f0393ead1ef37d323.png)

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

> **[theme/resources at master · pdxor/theme](https://github.com/pdxor/theme/tree/master/resources)**
>
> master/resources

**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.**

---

## Post 7 by @MWDelaney — 2019-03-20T12:02:03Z

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()`?

---

## Post 8 by @codepuncher — 2019-03-20T12:27:45Z

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`.

---

## Post 9 by @MWDelaney — 2019-03-20T18:36:38Z

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](https://discourse.roots.io/t/how-blade-stacks-make-my-life-better/10121)!

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

---

## Post 10 by @Kahlil_Calavas — 2019-03-20T21:14:55Z

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?!!?

---

## Post 11 by @system — 2019-04-23T17:01:36Z

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