Insights

Customizing Coveo For Sitecore With Init

Introduction

Coveo for Sitecore has a method for customizing your UI and UX that doesn't involve changing the renderings, making custom components, or changing hive at all.

It can even be customized per language and answers the question "Where do I bind my events now?" that comes up when upgrading from older UI setups.

Where Is It?

It's the field called Initialization File Name on the search interface item for your search page. The Hive example search page puts this item in $searchpage/example/example-search-interfaces.

Initialization File Name in Sitecore

The the actual file location is in $instanceDirectory/Coveo/Hive/Init.

What Do We Do With It?

Here's the original file's javascript:

<script type="text/javascript">
    document.addEventListener("CoveoSearchEndpointInitialized", function() {
        @*
            setTimeout(function() { }, 0) defers the initialization just enough to execute other DOMContentLoaded or CoveoSearchEndpointInitialized events in the page.
            This is required by some components to allow them to register before initialization.
        *@
        setTimeout(function() {
            var searchInterface = document.getElementById("@Model.Id");
            @if (Html.Coveo().IsEditingInPageEditor()) {
                @: if (typeof(CoveoForSitecore) !== "undefined" && typeof(Sitecore) !== "undefined") {
                    @: CoveoForSitecore.initializeSearchInterfaceForExperienceEditor(searchInterface);
                @: }
            } else {
                @: if (typeof(CoveoForSitecore) !== "undefined") {
                    @: CoveoForSitecore.initSearchInterface(searchInterface);
                @: }
            }
        }, 0);
    });
</script>

 

This part is really basic; it just starts the Coveo interface, though notice it has a different start for Experience Editor.

Let's start with something simple. Say you have a lot of facets, and you want the UI to load up nice and clean. It'll be simpler for your users. Maybe you just want the page to be shorter, you've already limited the number of results to four because you're doing a graphic-heavy gallery presentation.

So let's collapse all the facets, and show only the headings.

First, we move the line defining the search interface to the start of the script element, and then bind a function to the afterComponentsInitilization event.

This makes sure the facets are ready to accept the collapse command.

var searchInterface = document.getElementById("@Model.Id");
Coveo.$$(searchInterface).on(Coveo.InitializationEvents.afterComponentsInitialization, function() {
	var facets = [...searchInterface.querySelectorAll(".CoveoDynamicFacet")]; //old style facets use .CoveoFacet, if you have those instead

	facets.forEach(facet => {
		var myFacetElement = Coveo.get(facet);
		myFacetElement.collapse();
	});
});

 

You could also use this to preselect the facets, like this: Interacting with facets.

What's Next?

There are a whole ton of events available now. Coveo has a big list here with a nice flowchart: Search Framework Events

For now, let's do two more examples, then wrap up. The first example is query filtering. One on project, users were pasting in dollar signs from text on the website, and that's special Coveo syntax. So we saw an error, and it doesn't actually affect the results. So we'll strip it out.

Building on the previous example, we'll add this just before the SetTimeout call.

Coveo.$$(searchInterface).on('doneBuildingQuery',
	function(e, args) {
		var q = args.queryBuilder.expression.parts[0];
	
		if(q && q.indexOf("$") !== -1){
			args.queryBuilder.expression.parts[0] = q.replace("$", ""); 
		}
	});

 

Here, q is the query text entered by the user, and we have some guard code in case it is an empty search. If you really wanted to, you can use this same code to inject search terms if you were on a customized search page.

We bind to the doneBuildingQuery event to make sure Coveo is done setting everything up for the query, and any other custom code you have is finished.

This is a place where per-language customization would be useful, too. That you do just by creating different files for each language and assigning the file name in the language version of the search interface.

Customizing Results

Let's say you have some analytics data about your user and want to customize the presentation of the results based on that. Maybe you add a border or a "look here" icon to certain results on your catalog search page.

Which event do you want? Well, there are two that are good for this. newResultDisplayed, which fires on rendering each new result, and newResultsDisplayed, which fires at the end of displaying all of the new results.

This one also goes right before the SetTimeout call. Always register your event handlers before the CoveoForSitecore.initSearchInterface call, otherwise, you can end up with race conditions, or if you are unlucky, it won't fire at all. This example also assumes your analytics data is already handy.

Coveo.$$(searchInterface).on('newResultDisplayed',
	function(e, args) {
		if(userData.raw.jobtitle.toLowerCase() == "developer" && args.result.raw.category.toLowerCase == "computer"){
			var iconLocation = args.item.QuerySelector(".icon-container");
			iconLocation.classList.add("special-interest");ƒ
		}
	});

 

This example uses hardcoded English strings for simplicity, but you could easily use Sitecore's dictionary strings here, or take advantage of the multi-language setting for the init files. All of the HTML of the item template is available here, fully filled in with data, so you can make any changes you need. If you need to change tabindex or aria-* settings for accessibility reasons, this is also the place to do it, after Coveo's default code has run.

Wrap up

That's it! Now you know how to add any customizations that depend on the state of all sorts of Sitecore data, make any styling that couldn't be done with pure CSS and handle different things for different languages.

👋 Hey Sitecore Enthusiasts!

Sign up to our bi-weekly newsletter for a bite-sized curation of valuable insight from the Sitecore community.

What’s in it for you?

  • Stay up-to-date with the latest Sitecore news
  • New to Sitecore? Learn tips and tricks to help you navigate this powerful tool
  • Sitecore pro? Expand your skill set and discover troubleshooting tips
  • Browse open careers and opportunities
  • Get a chance to be featured in upcoming editions
  • Learn our secret handshake
  • And more!
Sitecore Snack a newsletter by Fishtank Consulting
 

Meet Ryan Allan

Senior Developer

⚙️💻👪

Ryan is a seasoned Senior Developer at Fishtank and is Sitecore Developer Certified. In a nutshell, he describes his role as "building extremely fancy websites". Ryan has a degree in Mechanical Engineering and previously worked on power plants and compressors, and now builds websites for the same company as a client! Outside of work, his interests are science + physics and spending time with his kids.

Connect with Ryan