Customizing Autosuggest

Connecting Autosuggest to Your Theme’s Search Bar

When enabled, ElasticPress Autosuggest will automatically add itself to any input[type="search"] elements on the page, as well as any elements with the .ep-autosuggest or .search-field classes. You can add Autosuggest to additional elements yourself by adding selectors as a comma-separated list to the Autosuggest Selector setting under ElasticPress > Features > Autosuggest > Settings.

You can change or remove the default selectors used by the plugin with the ep_autosuggest_default_selectors filter:

PHP
add_filter( 'ep_autosuggest_default_selectors', '__return_empty_string' );

This example uses the __return_empty_string() function to remove the default selectors so that only the selectors entered into the settings are used.

Adding a Loading Indicator

While new suggestions are being fetched as the user types, an .is-loading class will be added to the parent <form> element. This class can be used to style the search form differently while suggestions are being loaded. One possible use case is to display a loading indicator. For example, if you have a loading gif in your theme’s search form:

PHP
<form role="search" method="get" action="<?php echo esc_url( home_url( '/' ) ); ?>">
	<label>
		<span class="screen-reader-text">Search for:</span>
		<input type="search" value="<?php echo get_search_query(); ?>" name="s">
	</label>
	<input type="submit" value="Search">
	<img src="<?php echo esc_url( get_theme_file_uri( 'images/loading.gif' ) ); ?>" width="32" height="32" class="loading-indicator">
</form>

You could display the loading gif while suggestions are being fetched with this CSS:

CSS
.loading-indicator {
	display: none;
}

.is-loading .loading-indicator {
	display: block;
}

Customize Suggestion Markup

The HTML for individual Autosuggest suggestions are filtered by the ep.Autosuggest.itemHTML JavaScript hook. You can add or remove fields on suggestions by adding a filter to this hook from your theme (or a plugin, if appropriate).

Filters for the ep.Autosuggest.itemHTML hook receive the original HTML as a string and 3 additional values related to the suggestion as parameters:

NameTypeDescription
itemHTMLstringThe suggestion HTML as a string.
optionobjectThe Elasticsearch record for the suggestion.
indexnumberThe index of the suggestion in the results set.
searchTextstringThe search term.

Filters must return HTML for the suggestion as a string.

This example uses the hook to add the post date to the suggestion:

JavaScript
const autosuggestItemHTML = (itemHTML, option, index, searchText) => {
	const text = option._source.post_title;
	const url = option._source.permalink;
	const postDate = new Date(option._source.post_date).toLocaleString('en', { dateStyle: 'medium' })

	return `<li class="autosuggest-item" role="option" aria-selected="false" id="autosuggest-option-${index}">
		<a href="${url}" class="autosuggest-link" data-url="${url}" tabindex="-1">
			${text} (${postDate})
		</a>
	</li>`;
};
wp.hooks.addFilter('ep.Autosuggest.itemHTML', 'myTheme/autosuggestItemHTML', autosuggestItemHTML);

Note that the classidrolearia-selecteddata-url, and tabindex attributes in the returned markup must match the default values for those attributes, as they do in the example, to ensure that Autosuggest functions as normal.

Customize Suggestions List Markup

The HTML for the entire list of suggestions is filtered by the ep.Autosuggest.listHTML JavaScript hook. You can append or prepend items to the suggestions list, or otherwise make edits to the entire list (rather than individual suggestions), by adding a filter to this hook from your theme (or a plugin, if appropriate).

Filters for the ep.Autosuggest.listHTML hook receive the original HTML as a string and 2 additional values related to the suggestion as parameters:

NameTypeDescription
listHTMLstringThe list HTML as a string.
optionsarrayThe Elasticsearch records for the suggestions.
inputElementThe input element that triggered Autosuggest.

Filters must return HTML for the suggestion list as a string.

This example uses the hook to add a “View All Results” link to the bottom of the suggestions list.

JavaScript
const autosuggestListHTMLFilter = (listHTML, options, input) => {
	const allUrl = new URL(input.form.action);
	const formData = new FormData(input.form);
	const urlParams = new URLSearchParams(formData);

	allUrl.search = urlParams.toString();

	const url = allUrl.toString();

	listHTML += `<li class="autosuggest-item" role="option" aria-selected="false" id="autosuggest-option-all">
		<a href="${url}" class="autosuggest-link" data-url="${url}" tabindex="-1">
			View All Results
		</a>
	</li>`;

	return listHTML;
};

wp.hooks.addFilter('ep.Autosuggest.listHTML', 'myTheme/autosuggestListHTMLFilter', autosuggestListHTMLFilter);

Note that the classrolearia-selected, and tabindex attributes in any new items must match the default values for those attributes, as they do in the example, to ensure that Autosuggest functions as normal. Items must also contain a link with the href and data-url attributes set to the URL that the item should link to.

Customize the Suggestions Container

When ElasticPress inserts the markup for Autosuggest into the search form the element to be added is filtered by the ep.Autosuggest.element JavaScript hook. You can modify the markup of the Autosuggest container by adding a filter to this hook from your theme (or a plugin, if appropriate).

Filters for the ep.Autosuggest.element hook receive the DOM element that will be inserted and the element it will be inserted after as parameters:

NameTypeDescription
elementElementThe autosuggest container element.
inpreviousElementputElementThe element the container will be inserted after.

Filters must return a DOM element for the Autosuggest container.

This example uses the hook to add a “Powered by ElasticPress” message to the Autosuggest dropdown.

JavaScript
const autosuggestElementFilter = (element, previousElementput) => {
	const poweredBy = document.createElement('div');

	poweredBy.textContent = 'Powered by ElasticPress';

	element.appendChild(poweredBy);

	return element;
};

wp.hooks.addFilter('ep.Autosuggest.element', 'myTheme/autosuggestElementFilter', autosuggestElementFilter);

Customize the Autosuggest Query

To get suggestions for Autosuggest, ElasticPress sends an AJAX request containing an Elasticsearch query to your Autosuggest endpoint. Before this request is sent the Elasticsearch query is filtered by the ep.Autosuggest.query JavaScript hook. You can modify the query by adding a filter to this hook from your theme (or a plugin, if appropriate).

Filters for the ep.Autosuggest.query hook receive the query as a JavaScript object and 2 additional values related to the request as parameters:

NameTypeDescription
queryobjectThe Elasticsearch query as a JavaScript object.
searchTextstringThe search term.
inputElementThe input element that triggered Autosuggest.

Filters must return an Elasticsearch query as an object.

This example uses the function to add the value of a wp_dropdown_categories() field as a filter to the search query:

JavaScript
const autosuggestQueryFilter = (query, searchText, input) => {
	const formData = new FormData(input.form);
	const category = formData.get('cat');

	if (category) {
		query.post_filter.bool.must.push({
			term: {
				'terms.category.term_id': parseInt(category, 10),
			},
		});
	}

	return query;
};

wp.hooks.addFilter('ep.Autosuggest.query', 'myTheme/autosuggestQueryFilter', autosuggestQueryFilter);

Customize Behavior when navigating an Autosuggest Item

To customize the behavior of an Autosuggest Item, you can use the ep.Autosuggest.navigateCallback filter. This can be used for example if you want to add a query parameter, a behavior like opening a link in a new tab, etc. The filter gives you two parameters: the search term and the URL.

This example changes the behavior to add a “cypress” query arg with value “foobar”:

JavaScript
const myNavigateCallback = (searchTerm, url) => {
	let cypressQueryArg = new URLSearchParams(window.location.search)
	cypressQueryArg.set('cypress', 'foobar');
	var newURL = url + '?' + cypressQueryArg.toString();
	window.location.href = newURL;
};
wp.hooks.addFilter(
	'ep.Autosuggest.navigateCallback', 'myTheme/myNavigateCallback',
	() => myNavigateCallback,
);