PRO: Advanced Faceted Search with JSON and JCI

Challenge:

You have a JSON-API which gives realtime-data. The user should be able to search this data with a faceted search to set options for selecting items.
Click here for a simple Faceted Search.

In action:

see api.json-content-importer.com/pro-faceted-search-in-action/


Example-Data:

https://api.json-content-importer.com/extra/json/travel.json has data on hotels at different locations, different prices etc.


Step 1: Create a page with the search-results

Create a JCI-template with these settings:

Name:

facetedresults

URL:

https://api.json-content-importer.com/extra/json/travel.json

urlparam4twig (parameters for the search):

cres#vmax#vmin#ch#sort#page#stxt

Template-Text / twig-code:

<!--
sort: {{urlparam.sort}}<br>
stxt : {{urlparam.stxt}}<br>
price: {{urlparam.vmin}} - {{urlparam.vmax}}<br>
-->
{% set maxp = 999999999999999999 %}
{% set minp = 0 %}
{% if urlparam.vmin %}{% set minp =urlparam.vmin %}{% endif %}
{% if urlparam.vmax %}{% set maxp =urlparam.vmax %}{% endif %}

{% set nof = 0 %}
{% set sort = 'desc' %}{% if urlparam.sort=="sortup" %}{% set sort = '' %}{% endif %}
{% set stxt= '' %}{% if urlparam.stxt %}{% set stxt = urlparam.stxt %}{% endif %}
<script type="text/javascript">
var outitems = {};
{% for i in Offers  | sortbyjsonfield("Sellprice,"~sort~",num") %}
{% set out = '' %}
{% if (i.Sellprice<=maxp  and i.Sellprice>=minp ) %}

{% if  (urlparam.ch=="") or (urlparam.ch matches '/'~  (i.Resortname | md5) ~'/') %}

{% if  (urlparam.stxt=="") or (i.Resortname matches '/'~(urlparam.stxt)~'/i') %}

{% set nof = nof + 1 %}
{% set out = out ~ '<div class="table-row"><div class="table-col">' %}
{% set out = out ~ '<b>' ~ nof  ~ ": " ~ i.Hotelname ~ '</b><br>' %}
{% set out = out ~ 'Location: ' ~ i.Resortname ~ '<br>' %}
{% set out = out ~ i.Sellprice ~ ' Euro<br>' %}
{% set out = out ~ i.Areaname ~ ': ' ~ i.Outdepdate ~ ' - ' ~ i.Indepdate ~ '<br>' %}
{% set out = out ~ 'Flight: ' ~ i.Depaptname~ ' to ' ~ i.Arraptname ~ ',<br>operated by ' ~ i.Flightsuppler %}
{% set out = out ~ '<br><a href="/trip-details?refnum=' ~ i.Refnum ~ '">more</a>' %}
{% set out = out ~ '</div></div>' %}
outitems["ch{{nof}}"] = '{{out  | url_encode }}';
{% endif %}
{% endif %}
{% endif %}
{% endfor %}
<\/script>
<div class="divtable">{% if nof >0 %}
<div class="table-row"><div class="table-col">
{% set itemsperpage = 5 %}
{% set noofpages = ((nof /itemsperpage) | round(0, 'ceil') )%}
{% if noofpages>1 %}
{{nof }} Found, Pagination: <select class=psgeofpagination name=page>
{% for p in (0.. (noofpages-1)) %}{% set lowend = (p*itemsperpage +1) %}{% set highend = ((p+1)*itemsperpage) %}{% if highend >nof  %}{% set highend =nof %}{% endif %}<option name="pag" lowend="{{lowend}}" value="{{p}}"> {{lowend }} - {{highend}}</option>{% endfor %}</select></div></div>
{% endif %}
<div id="resultareaitems"></div>
{% else %}
<div class="table-row"><div class="table-col">
Nothing found, change selection please
</div></div>
{% endif %}
</div>

<script type="text/javascript">
doPag({{nof }});
$j('.psgeofpagination').change(function(){  
doPag({{nof }});
});

function doPag(noall) {
let z = $j('.psgeofpagination').children("option:selected").text();
if (z=="") { z= "1-"+noall; }
let lowhigh = z.split("-");
let low = parseInt(lowhigh[0].trim(), 10);
let high = parseInt(lowhigh[1].trim(), 10);
let textout = "";
for (ui = low ; ui <= high; ui++) {
  textout += decodeURIComponent(outitems["ch"+ui]);
} 
$j("#resultareaitems").html(textout);
}
<\/script>

Leave the other settings like cache, twig-parser etc. as they are (default settings).
Create a WordPress-Page with this Shortcode:

[jsoncontentimporterpro nameoftemplate="facetedresults"]

Preview of this page should give you something like this: https://api.json-content-importer.com/get-faceted-results/.
Name this page “get-faceted-results” and publish it. The URL then should be DOMAIN/get-faceted-results/

Step 2: Check jQuery-Libs

The faceted search uses the jQuery-JavaScript-Libraries. Depending on the used WordPress-Template those libraries are already available. If not you can load them via ther JCI-options, Tab “Extra”.
Check what your template is offering here (like a css-grid or JS-libs).
In case of need load

  • jQuery: Basic jquery-Lib
  • jQuery-UI, jQuery-UI CSS: Libs for using a slider etc.
  • jQuery-UI Touch Punch: for using sliders on mobile devices
  • jQuery mobile JS, jQuery mobile CSS: for using on mobile devices

Step 3: Create a page with the facet-search-form and the results

Create a JCI-template with these settings:
Name:

facetedform

URL:

https://api.json-content-importer.com/extra/json/travel.json

Template-Text / twig-code:

{% set loop = Offers %}
{% set resortList = [] %}
{% set anz = 0 %}
{% set maxprice = -1 %}
{% set minprice = -1 %}
{% set stxt = '' %}
{% for r in loop %} 
{% set resortList = resortList | merge(  {(r.Resortname) : 1 }) %}
{% if r.Sellprice > maxprice  %}{% set maxprice  = r.Sellprice %}{% endif %}
{% if r.Sellprice < minprice or  minprice <0 %}{% set minprice = r.Sellprice %}{% endif %}
{% endfor %}
<table border=1>
    <tr><td valign=top>
    <div class="large-4 columns">
    <form class=retform>
    <h3 class="smtxt">Text-Search:</h3>
    <input type="text" name="stxt" value="" class="smtxt" placeholder="Resortname-Search: Insert Text for search here">
    <h3 class=smtxt>Price-Sort:</h3>
    <input type="radio" name="sort" id="sortup" value="sortup"><label for="sortup"> <span class=smtxt>low to high</span></label>
    <br><input type="radio" name="sort" id="sortdown" value="sortdown"><label for="sortdown"> <span class=smtxt>high to low</span></label>

<h3 class=smtxt>Price:</h3>
<div id="selectslider" class="smtxt"></div>
<input id="slidervalmin" type="text" /><input id="slidervalmax" type="text" />

    <h3 class=smtxt>Location:</h3>
    {% set resortList = (resortList | sortbyarray("ksort")) %}
    {% for k,v in resortList %}
        <input type="checkbox" class=ret id="{{k|md5}}" value=""><span class=smtxt>{{k}}</span><br>
    {% endfor %}
    </form>
    </td><td valign=top>
        <div class="large-8 columns">
        <div id="resultarea">select settings on the left side</div>
        </div>
    </td></tr></table>


<script type="text/javascript">
var zrt ="/get-faceted-results/?show=oc";
var $j = jQuery.noConflict();

$j('input[type=radio][name=sort][value=sortup]').prop('checked', true);
doaj(); 
$j('.retform').change(function(){  doaj();  });
$j('.retform').keyup(function(){  doaj();  });
function doaj() {
let postpayload = {};  let chk = "";
$j('.ret:checked').each(function(){
    chk = chk  + $j(this).attr('id') + "-";
});
postpayload["ch"] = chk ;
postpayload["stxt"] = $j('input[name=stxt]').val();
postpayload["vmin"] = $j("#slidervalmin").val();
postpayload["vmax"] =  $j("#slidervalmax").val();
postpayload["sort"] = $j('input[name=sort]:checked').val();
postpayload["ds"] = $j("#datestart").val();
postpayload["de"] = $j("#dateend").val();

$j.ajax({
url: zrt, type: "POST",
data: postpayload, dataType: "text",
success: function(result){ 
$j("#resultarea").html(result);},
error: function(result){ var resulterror ="Request failed. Try again later, please"; $j("#resultarea").html(resulterror); }
});
}
$j( "#selectslider" ).slider({
      range: true,
      min: {{minprice}},
      max: {{maxprice}},
      values: [ {{minprice }}, {{maxprice}}],
      step: 0.01,
      slide: function(event, ui) {
          $j("#slidervalmin").val(ui.values[0]);
          $j("#slidervalmax").val(ui.values[1]);
          doaj();
     }
});

$j("#slidervalmin").val($j("#selectslider").slider("values", 0));
$j("#slidervalmax").val($j("#selectslider").slider("values",1));
<\/script>
<style type="text/css">

#secondary {
    display: none;
}

#primary {
    width: 100%;
}

.smtxt {
    font-size: 12px  !important;
}

#slidervalmax, #slidervalmin{
  background-color: #ddd;  
}
.divtable {
  display: table;         
  width:  100%;     
table-layout: fixed;        
  border: 1px solid #666666;    
  border-spacing: 5px; /* cellspacing:poor IE support for  this */
}
.table-row {
  display: table-row;
 width: auto; 
  clear: both;
}
.table-col {
  float: left; /* fix for  buggy browsers */
  padding: 12px;   
  display: table-column;         
}
.divtableall {
  display: table;    
table-layout: auto;     
 width: auto;         
    font: 15px Arial, sans-serif;
  border-spacing: 5px; /* cellspacing:poor IE support for  this */
}
.tablerowall {
  display: table-row;
  clear: both;
}
.tablecolall {
  float: left; /* fix for  buggy browsers */
  padding: 15px;   
  display: table-column;         
  background-color: #eee;  
}
.tablecolall25 {
  width: 25%;
}
.tablecolall75 {
  width: 75%;
  background-color: #ddd;  
}

.row input[type=text] {
    width: 35%;
    padding: 5px;
}
.row h3 {
margin-bottom: 6px;
}


@media only screen and (max-width: 768px){
.site-main .entry .entry-header {
    margin: calc(3 * 1rem) calc(5% + 60px) 1rem;
}
.site-main .entry .entry-content, .entry .entry-summary {
    padding: 0;
}
.site-main .row input[type=text] {
    display: inline-block;
    margin-top: 25px;
}
.site-main .ui-widget.ui-widget-content {
    margin-left: 13px;
    margin-top: 15px;
}
[type="checkbox"] {
    float: right !important;
}
.site-main .divtable {
    margin-top: 25px;
}
b,strong {
    font-weight: bolder;
    font-size: 34px  !important;
}
}
</style>

Leave the other settings like cache, twig-parser etc. as they are (default settings).
Create a WordPress-Page with this Shortcode:

[jsoncontentimporterpro nameoftemplate="facetedform"]

Preview of this page should give you something like this: https://api.json-content-importer.com/pro-faceted-search-in-action/.

Step 4: Create a page with the details of an item

Create a JCI-template with these settings:
Name:

faceteddetail

URL:

https://api.json-content-importer.com/extra/json/travel.json

urlparam4twig (parameters for the search)):

refnum

Template-Text / twig-code:

{% for i in Offers %}
    {% if urlparam.refnum==i.Refnum %}
        {{i |json_encode() }}
    {% endif %}
{% endfor %}

Leave the other settings like cache, twig3 etc. as they are (default settings).

Saving this JCI-template gives you a number for this template. Use this on a page like that:

[jsoncontentimporterpro nameoftemplate="faceteddetail"]

Name this page “trip-details” and publish it. A click on “more” in the facet-result-list should take you to this page.


Well – that’s it. For other JSON you have to alter the twig-code to sum up the facet-options.