Friday, May 1, 2020

Create Filter using Algolia

Algolia is a hosted search engine. To make it simple we need the example for that. Let say we have a bunch of data, and hard for we to search all of our data. Then Algolia is the solution. Algolia offering full-text, numerical, and faceted search, capable of delivering real-time results from the first keystroke. The next question is, how we Algolia do that?




Below is some step that we need before we can use algolia:


1. Include Algolia script

1.1 Install Plugin

First we need to install plugin, we can found the plugin detail from here.
We also need to remove some code from this plugin, so need to follow this instruction carefully.

1.2 Enqueue script from Algolia

look here for more detail:


2. Sync our data with Algolia

In this section we will explain how to do the initialize Algolia index, add data to algolia and finally filtering the data.

2.1 Initialize the client

We already have the source we need.  Now we need to go to plugin folder and edit “algolia-custom-integration.php” replace the appID and API key.

global $algolia;
$algolia = \Algolia\AlgoliaSearch\SearchClient::create("5FGBFCLK4X", "***************************");
Note: you need to remove or comment the code below this code. 


2.2 Add Data to Algolia 

To add data to Algolia I use example data that easily created by this website https://www.mockaroo.com/ .
Now we will add the data using this code below. We can use shortcode for this code, but to make it save add the paramater in the url to run this shortcode. So we can check, if  there is paramater n the url (using $_GET) then run the shortcode. 

global $algolia;
$index = $algolia->initIndex('test');
$index->clearObjects()->wait();

$data2 = [[
  "id"=> 1,
  "first_name"=> "Lonnard",
  "last_name"=> "Birchenhead",
  "email"=> "lbirchenhead0@ca.gov",
  "gender"=> "Male",
  "city"=> "Bonpland",
  "Job"=> "Statistician II",
  "race"=> "Melanesian"
], [
  "id"=> 2,
  "first_name"=> "Jacquelyn",
  "last_name"=> "Horbart",
  "email"=> "jhorbart1@php.net",
  "gender"=> "Female",
  "city"=> "Triánta",
  "Job"=> "Research Assistant II",
  "race"=> "Cambodian"
]];
$index->saveObjects($data2, ['autoGenerateObjectIDIfNotExist' => true]);

3. Filtering

Now we will create the advance filtering using face. What we need to prepare is template, js function and php file.
Here is the what the filter will look like in the final

3.1 Prepare Facet

We need to prepare facet for gender and race those 2 attributes will be used as select filter. You can set facet in your algolia dashboard.
Follow this link for more detail:
https://www.algolia.com/doc/guides/managing-results/refine-results/faceting/how-to/declaring-attributes-for-faceting/#using-the-dashboard

3.2. Call facet list
Now we need to call all the facet list and value from Algolia. We call all those inside .php file. Below is the code.


global $algolia;
$index = $algolia->initIndex('test');
$settings = $index->getSettings();
$facetsResult = $index->search('', ['facets' => ['*']]); 
$facets_value = $facetsResult['facets'];
$facet_json = json_encode($facets_value);
echo "<input type='text' id='data_facet' value='".$facet_json."'>";

In the code on top you can see, that we trying to get all facet value. After we got all the value, then we convert it as json and print it using echo. Below I will explain why we print all those data.

3.3. Create template file

Now we need to create template file.


<div id="searchbox"></div>
<div class="filter-container">
     <div id="filter_gender" class="filter-combo"></div>
     <div id="filter_city" class="filter-combo"></div>
     <div id="filter_race" class="filter-combo"></div>
</div>
<div class="filter-container_default" style="display:none;">
    <div id="filter_gender_def" class="filter-combo-def"></div>
    <div id="filter_city_def" class="filter-combo-def"></div>
    <div id="filter_race_def" class="filter-combo-def"></div>
</div>
<div id="hits"></div>

We have 2 filter-container. The first filter-container class is used for our custom filter faced. The second filter-container_default class is used for default facet filter from algolia. Actually, I don’t want to use the default facet filter, but if we delete it, we can’t use our custom filter. 

3.4. Create Js Function

3.4.1. Generate Select for Facet Filter 
The first thing we need to do is create custom select for those 2 facets. We will get the data facet from step. 3.2.
below is the script.


/*-- select filter --*/
var data_facet_str = $("#data_facet").val();
var data_facet = JSON.parse(data_facet_str);

// add data to gender
var select_gender = $('<select/>');
select_gender.prepend('<option value="" selected >Please select</option>');
$.each(data_facet.gender, function( index, value ) {
  select_gender.append($("<option>").attr('value',index).text(index));
});
$("#filter_gender").append(select_gender);
$("#filter_gender select").selectpicker();

// add data to race
var select_race = $('<select/>');
select_race.prepend('<option value="" selected>Please select</option>');
$.each(data_facet.race, function( index, value ) {
  select_race.append($("<option>").attr('value',index).text(index));
});
$("#filter_race").append(select_race);
$("#filter_race select").selectpicker();

function filter_funtion(){
  var filter_val_gender   = $("#filter_gender select").val();
  var filter_val_race   = $("#filter_race select").val();
  console.log(filter_val_gender);
  console.log(filter_val_race);

  search.helper
    .toggleFacetRefinement('gender', filter_val_gender)
    .toggleFacetRefinement('race', filter_val_race)
    .search();
}

$("#filter_race select").on('changed.bs.select', function (e, clickedIndex, newValue, oldValue) {
  filter_funtion();
});
$("#filter_gender select").on('changed.bs.select', function (e, clickedIndex, newValue, oldValue) {
  filter_funtion();
});
/*-- select filter end --*/


3.4.2. Declare Instantsearch

//declare instant searh
const search = instantsearch({
  indexName: 'test',
  searchClient: algoliasearch(
  '5FGBFCLK4X',
  '29b1ba62e9906612e399819b63f71962'
  ),
  showLoadingIndicator:true,
}); 


3.4.3. Add Widget

// add widget
search.addWidgets([
  instantsearch.widgets.searchBox({
    container: '#searchbox',
  }),
  instantsearch.widgets.configure({
    hitsPerPage: 8,
  }),

  instantsearch.widgets.menuSelect({
    container: '#filter_gender_def',
    attribute: 'gender',
    templates: {
      defaultOption: 'All Gender',
    },
  }),
  instantsearch.widgets.menuSelect({
    container: '#filter_race_def',
    attribute: 'race',
    templates: {
      defaultOption: 'All Race',
    },
  }),
  instantsearch.widgets.infiniteHits({
    container: '#hits',
    templates: {
      item: `
       <div>
         <div class="hit-name">
           <p>id: with helper {{#helpers.formatNumber}}{{id}}{{/helpers.formatNumber}} </p>
           <p>id Normal: {{id}} </p>
           <p>first_name: {{first_name}} </p>
           <p>last_name: {{last_name}} </p>
           <p>email: {{email}} </p>
           <p>gender: {{gender}} </p>
           <p>city: {{city}} </p>
           <p>Job: {{Job}} </p>
           <p>race: {{race}} </p>
         </div>
        
       </div>
      `,
    },
  }),
]);


3.4.4. Custom filter & Execute the Instantsearch 
Before call the instant search we can do the filter like code below. The final thing we do is execute the instantsearh.


var filter = {
    filters: 'status:publish',
    hitsPerPage: 8
};
search.addWidgets([
  instantsearch.widgets.configure(filter),
]); 

search.start();

No comments:

Post a Comment