Customising Search Link Behaviour
Search Expander widgets will often contain links to internal search results pages. In order to create these links, Search Expander needs a method to construct their URLs. In many cases this can be accomplished via the searchUrlTemplate
setting, for example:
sxpr({
se: 'your-search-engine-id',
searchUrlTemplate: '/?q={searchTerms}'
});
Given the search URL template above, a widget link for the query "climate change" will have the URL
/?q=climate+change
.
By default, in appropriate situations Search Expander will add a query string containing an ID for a media thumbnail bar, a word to define via the dictionary widget, and/or an ID for search suggestions. For example:
/?q=example&sxprmedia=eyJxIjoiQXN0&sxprsearchsugg=oiQXN0eyJxIj&sxprdict=example
If you wish for greater control over the way search link URLs are constructed, you can specify how these values are inserted into search URLs, for example:
/?q={searchTerms}&customMediaThumbBarKey={mediaThumbBar}&customSearchSuggestionsKey={searchSuggestions}&customDictWordKey={wordToDefine}
Taking control of search requests
You may need more complex or dynamic behaviour than the above URL templating approach allows for. For example, you may want to use a POST
submission for searches, or you may need to add URL query values which cannot be known ahead of time. In this case, you can pass a handleSearchClick
function as part of the sxpr()
settings object. When this function is provided, search link clicks are intercepted, and an object containing data about the link is passed to handleSearchClick
. This object has the following interface:
{
q: string;
mediaThumbBar: string | undefined;
searchSuggestions: string | undefined;
wordToDefine: string | undefined;
link: HTMLAnchorElement;
event: MouseEvent;
}
q
is the search querymediaThumbBar
is a media thumbnail bar IDsearchSuggestions
is a search suggestions bar IDwordToDefine
is a word to be defined in a dictionary widgetlink
is the clicked link elementevent
is the click event
(Note that the link's default behaviour is prevented automatically, so there is no need to call event.preventDefault()
.)
The q
, mediaThumbBar
, searchSuggestions
and wordToDefine
values (where available) must be made available to sxpr()
once your search results have rendered. They can be added to the sxpr()
settings object directly or provided as HTML input values. The best approach to take will depend on your particular setup.
JavaScript example
sxpr({
se: 'your-search-engine-id',
q: 'example',
mediaThumbBar: 'eyJ0eXBlIjoiYWxidW1z...',
searchSuggestions: 'oiYWxidW1zeyJ0eXBlIj...',
wordToDefine: 'example'
});
Markup example
<input type="search" name="q" value="example" data-sxpr-input>
<input type="hidden" name="sx-media-thumb-bar" value="eyJ0eXBlIjoiYWxidW1z...">
<input type="hidden" name="sx-search-suggestions" value="oiYWxidW1zeyJ0eXBlIj...">
<input type="hidden" name="sx-word-to-define" value="example">
If desired, you can use searchUrlTemplate
and handleSearchClick
together, in which case the object passed to handleSearchClick
will have a url
property containing the populated URL template.
Example 1: POST requests
<!-- Simplified PHP example -->
<form id="search-form" method="POST">
<input type="search" name="q" value="<?= htmlspecialchars($_POST['q']) ?>" data-sxpr-input>
<input type="hidden" name="sx-media-thumb-bar" value="<?= htmlspecialchars($_POST['sx-media-thumb-bar']) ?>">
<input type="hidden" name="sx-search-suggestions" value="<?= htmlspecialchars($_POST['sx-search-suggestions']) ?>">
<input type="hidden" name="sx-word-to-define" value="<?= htmlspecialchars($_POST['sx-word-to-define']) ?>">
<button type="submit">Search</button>
</form>
<div id="search-results">
...
</div>
function handleSearchClick(data) {
const form = document.getElementById('search-form');
form.querySelector('[name="q"]').value = data.q;
form.querySelector('[name="sx-media-thumb-bar"]').value = data.mediaThumbBar || '';
form.querySelector('[name="sx-search-suggestions"]').value = data.searchSuggestions || '';
form.querySelector('[name="sx-word-to-define"]').value = data.wordToDefine || '';
form.submit();
}
sxpr({
se: 'your-search-engine-id',
handleSearchClick,
});
Example 2: JavaScript Fetch API
// This function is called on page load, to fetch and render initial search results
async function initPage() {
const q = new URL(location.href).searchParams.get("q"); // Get initial search query somehow
const results = await fetchSearchResults(q);
renderSearchResults(results);
callSxpr(q, results);
}
// Handles Search Expander widget search link clicks
async function handleSearchClick(data) {
const results = await fetchSearchResults(data.q);
renderSearchResults(results);
callSxpr(data.q, results, data.mediaThumbBar, data.searchSuggestions, data.wordToDefine);
}
// Calls the sxpr() function
function callSxpr(q, results, mediaThumbBar, searchSuggestions, wordToDefine) {
sxpr({
se: 'your-search-engine-id',
handleSearchClick,
q,
results,
mediaThumbBar,
searchSuggestions,
wordToDefine,
});
}
// Fetches search results from an external API and returns them as an array of
// { url: string, title: string } objects.
async function fetchSearchResults(q) {
const url = `https://example.com/my-search-api?q=${encodeURIComponent(q)}`;
const response = await fetch(url);
return await response.json();
}
// Renders the fetched search results on the page
function renderSearchResults(results) {
// ...
}
initPage();