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 query
  • mediaThumbBar is a media thumbnail bar ID
  • searchSuggestions is a search suggestions bar ID
  • wordToDefine is a word to be defined in a dictionary widget
  • link is the clicked link element
  • event 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();

» Private Search Engines