Can I Show Category Pages in Autocomplete Results?

My products have a “tags” field I use to categorize them. Each category has a dedicated “list” page at http://mysite.com/tags/[tag_name] where [tag_name] is the name of the tag. How can I show these tag pages in my autocomplete?

You can extend the Swiftype jQuery autocomplete plugin using the following code. An explanation of what it’s doing is below:

// Given a collection of Swiftype results (results), return a
// collection of count hashes like:
//       [{tag: "jacket", count: "5", url:"http://mysite.com/tags/jacket"}, ... ]
//
// Requires Underscore.js.
//
var mostPopular = function(results, attribute) {
  var allTags = [];
  var base_url = "http://MYSITE.com/tag/";

  jQuery.each(results, function(idx, result) {
    allTags = allTags.concat(result[attribute]);
  });

  // Removes undefined, null, "" etc...
  allTags = allTags.filter(function(e){return e});

  var counts = {};
  for (var i = 0, j = allTags.length; i < j; i++) {
     counts[allTags[i]] = (counts[allTags[i]] || 0) + 1;
  }

  // Customize this to how you URLify tags.
  var urlify = function(tag) {
    return tag.toLowerCase().replace(/ /g,'-');
  };

  counts = jQuery.map(counts, function(count, tag) {
    return {tag: tag, count: count, url: base_url + urlify(tag)};
  });

  return _.sortBy(counts, function(c) {
    return c.count;
  }).reverse();
};

// Returns the highlighted title if it exists. Falls back to the
// title field if not.
var getTitle = function(item) {
  return item.highlight['title'] || item['title'];
}

var customResultRenderFunction = function(ctx, results) {
  var $list = ctx.list,
    config = ctx.config;

  // Change this if using the Swiftype API.
  var document_type = "page";
  var field_name = "tags";
  var maximum_results = 5;
  var maximum_categories = 3;

  var categories = mostPopular(results[document_type], field_name);
  results = results[document_type];

  categories = categories.slice(0, maximum_categories);
  results = results.slice(0, maximum_results);

  jQuery('<li class="heading">Categories</li>').appendTo($list);
  jQuery.each(categories, function(idx, category) {
    ctx.registerResult(jQuery('<li class="result">' + category.tag + '</li>').appendTo($list), category);
  });

  jQuery('<li class="heading">Products</li>').appendTo($list);
  jQuery.each(results, function(idx, item) {
    ctx.registerResult(jQuery('<li class="result">' + getTitle(item) + '</li>').appendTo($list), item);
  });
};

jQuery(handle).swiftype({
  resultRenderFunction: customResultRenderFunction,
  engineKey: "YOUR_KEY"
});

How does this work?
First, tell the autocomplete plugin to render results using a custom function customResultRenderFunction

jQuery(handle).swiftype({
  resultRenderFunction: customResultRenderFunction,
  engineKey: "YOUR_KEY"
});

customResultRenderFunction first takes a list of records and passes them to the mostPopular function. mostPopular returns an array of results and an attribute name and converts them to a counted array, ordered by count, formatted like:

[{tag: "jacket", count: "5", url:"http://mysite.com/tags/jacket"}, ...

customResultRenderFunction then limits the categories and results using the maximum_categories and maximum_results variables and prints them according to the code below:

jQuery('<li class="heading">Categories</li>').appendTo($list);
jQuery.each(categories, function(idx, category) {
  ctx.registerResult(jQuery('<li class="result">' + category.tag + '</li>').appendTo($list), category);
});

The actual results are then rendered in their own section.

jQuery('<li class="heading">Products</li>').appendTo($list);
jQuery.each(results, function(idx, item) {
  ctx.registerResult(jQuery('<li class="result">' + getTitle(item) + '</li>').appendTo($list), item);
});

It’s likely you’ll want to change the following variables in customResultRenderFunction:

var document_type = "page";
var field_name = "tags";
var maximum_results = 5;
var maximum_categories = 3;

You’ll probably also want to change these items in mostPopular:

var base_url = "http://MYSITE.com/tag/";

// Customize this to how you URLify tags.
var urlify = function(tag) {
  return tag.toLowerCase().replace(/ /g,'-');
};