I’m a truly terrible speller, so when I was testing out the search functionality on this site it became very clear to me how much I rely on Google’s spelling suggestions and how deficient any search without that feature feels. I was surprised to find that there were no existing WordPress plugins that could easily add this functionality, so I decided to see how hard it would be to implement that functionality myself. As it turns out, with the right API account a simple spelling suggest feature is fairly straightforward to build.
Getting the suggestions
The first hurdle in this project is where to get the spelling suggestions. A little bit of searching revealed that my best bet was probably to use the search APIs from one of the big boys in the search game. Google’s API unfortunately doesn’t include spelling suggestions, and Yahoo’s isn’t free (as much as I wanted this, I wasn’t willing to pay for it). That left Bing, and luckily they provide spelling suggestions in their web service and have an intro level of 5000 free queries per month (way more than I’ll ever need).
Getting started with the Bing API was a little frustrating at first because I immediately found this guide to working with the API, and it took me an embarrassingly long time to figure out that it was out of date and no longer correct. Once I got through that and found a proper guide, things got substantially smoother.
The PHP examples provided in the documentation are fairly thorough, and I followed them almost exactly. I was able to get the search query using WordPress’s built in get_search_query() function, although I did experience some issues with special character escaping misbehaving between WordPress and Bing. Eventually I discovered that calling get_search_query(FALSE) instead and then passing the resulting string through urlencode() solved the issue. I also did not wrap the query in single quotes before escaping it as recommended by the guide, as I was unable to get the API to function when used that way.
$acctKey = "YOUR_BING_SEARCH_ACCOUNT_KEY";
$query = urlencode(get_search_query(false));
$url = "https://api.datamarket.azure.com/Bing/Search/v1/SpellingSuggestions?Query=%27$query%27&Market=%27en-US%27&$format=json";
$auth = base64_encode("$acctKey:$acctKey");
$data = array(
'http' => array(
'request_fulluri' => true,
'ignore_errors' => true,
'header' => "Authorization: Basic $auth"
$context = stream_context_create($data);
$response = file_get_contents($url, 0, $context);
$responseObj = json_decode($response);
$suggestion = $responseObj->d->results->Value;
Using the suggestions
Once the suggestion has been gathered it needs to be presented to the site’s visitors in a usable way. While I can see some value to returning spelling suggestions with every search, because of the limited per-month nature of the API I decided to only query Bing for a spelling suggestion on searches that return no results. I accomplished this by placing the PHP above in the section of “search.php” that gets called when a search returns no results. This section of the file should be pretty easy to find, just look for your theme’s “Sorry, no results” text.
I wanted to display the suggestion text only if Bing actually responded with a suggestion, so I did a quick if... else block to check if the suggestion variable had a value, and fall back on generic “no results” text if it didn’t. I also inserted the suggestion as a link by running the suggestion through urlencode() and adding it to the query string to get a URL for a results page that used the suggested spelling.
if ($suggestion) : ?>
<p class="suggestionText">Did you mean <a href="<?php echo '/?s=' . urlencode($suggestion); ?>"><strong><em><?php echo $suggestion; ?></em></strong></a> ?</p>
<?php else : ?>
<p>Don't panic, we'll get through this together. Let's explore our options here.</p>
<?php endif; ?>
The result is a very clean and professional feature that considerably streamlines site search and does so without too much difficulty. To get a better look at the end result, try using the search box at the top of this page to search for “javascrpt” or “sharepont”.
Fun Fact: Even though this post includes the two misspellings above, it will not show in the results list if those misspellings are used as search terms. This is achieved by inserting one of the unused ISO-8859-1 entities (in this case ) in the middle of each word. This makes no visual difference when viewing the page, but changes the word in the search index.