Sep 14

Adding Google Custom Search to Your WordPress Blog

For our website redesign, I wanted to do a 404 page that would be able to show Google Custom Search suggestions based on what the requested page’s URL was.  There are several plugins that do something similar to this, but they were either too convoluted or not exactly what I wanted.  So here’s what I came up with instead.  It can also take over the standard WordPress search.

What you need

This will take some code editing for whatever WordPress theme you’re using.  I’ll assume that your theme of choice is using standard file locations.  If you don’t already have jQuery loading on your theme, you’ll have to add some code to do that.  Add the following to your header.php before the wp_head() call.


Overview of steps

  1. Setup Google Custom Search and Google API Console
  2. Create AJAX Request Wrapper
  3. Create jQuery JavaScript
  4. Modify 404 page
  5. Modify search page
  6. (optional) Setup Google Analytics site search

Setup Google Custom Search and Google API Console

This is really simple.  You just sign up for Google Custom Search and create a new search engine.  Put your blog’s URL into the sites list.  It might also help if you add your site to Webmaster Tools to make sure it’s being indexed by Google correctly.  In the CSE control panel, make a note of your “Search engine unique ID” on the Basics page.  You’ll need this later.

Then sign up for Google API Console.  This will let you use your own code for the custom search instead of Google’s.  Make sure you turn on the API for Custom Search and then make a note of the API key for later.

Create AJAX Request Wrapper

This PHP script is just a generic AJAX pass-through that will allow some (older) browsers to do cross-domain JavaScript requests.  It uses PHP’s CURL library, which every web host should have installed for you already.  Just copy the following code and replace where it says YOUR_CSE_ID and YOUR_API_KEY with your Custom Search ID and Google API key respectively.  Then save this script somewhere in your blog theme—typically, it would go in your /functions directory.

$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, "" . urlencode(trim($_GET['num'])) . "&q=" . urlencode(trim($_GET['q'])));
curl_setopt($ch, CURLOPT_HEADER, false);
curl_setopt($ch, CURLOPT_TIMEOUT, 5);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);

if (($google_results = curl_exec($ch)) !== false) {
	print $google_results;

If you want to test at this part of the process, you can just call your script and pass it the following parameters.  Remember that this script will be at the location of your theme files, so something like this:  The script will return JSON data.

  • num — an integer for the number of results to return
  • q — a string containing your search query

Create jQuery JavaScript

This JavaScript code makes the AJAX request and converts the JSON into useful output.  It will also automatically redo the search if there was a spelling correction.  The search AJAX can be called repeatedly if you have a search box on the page, as well; so the page doesn’t have to reload to search again.

If you want to customize how the results look on the page, you may want to edit some of the code here if adding CSS styles aren’t enough.  Save this script somewhere in your theme files—typically, in either /scripts or /js.

function cseGetResults(q) {
	jQuery("#cse-results").html('<div class="loading-anim"></div>');
	jQuery.getJSON(cseSettings.wrapperScript + '?num=' + cseSettings.numResults + '&q=' + q, function(data) {
		var results = [];
		if (data.items) {
			jQuery.each(data.items, function(key, val) {
				results.push('<li id="result-' + key + '"><h3 class="result-title"><a href="' + + '">' + val.htmlTitle + '</a></h3><div class="result-snippet">' + val.htmlSnippet + '</div><div class="result-url">' + val.htmlFormattedUrl + '</div></li>');
			jQuery("#cse-results").html('<ul>' + results.join('') + '</ul>');
		} else if (data.spelling) {
			if (data.spelling.correctedQuery) return cseGetResults(data.spelling.correctedQuery);
		} else {
			jQuery("#cse-results").html('<p>Your search returned no results.</p>');
	return false;

jQuery(document).ready(function() {
	if (jQuery("#cse-results").length != 0) {
		if ((typeof cseSettings == 'object') && cseSettings.wrapperScript.length) {

Modify 404 page

Now it’s time to actually include the search on the WordPress pages.  Open your theme’s 404.php.  In the top of this page, before the header template code is output, insert the following code. Be sure to change the first line so it points to your JavaScript file and the third line so it points at your PHP wrapper script.

You might also fiddle with the ‘query’ formatting. Here the str_replace() function is just removing some junk from the requested URL like slashes and question marks. You can also change numResults to the number of results you want returned.

wp_enqueue_script('cse', get_bloginfo('template_url') . '/scripts/cse.js', array('jquery'), false, true);
wp_localize_script('cse', 'cseSettings', array(
	'wrapperScript' => get_bloginfo( 'template_url' ) . "/functions/cse_request.php",
	'numResults' => "6",
	'query' => str_replace(array('/', '\\', '?', '&', "_", "-"), " ", $_SERVER['REQUEST_URI'])

Later in the page, you’ll insert this next block of HTML code that will actually be where the results are placed.  So you’ll want this code to go right after your typical “sorry. that page does not exist” message.

<div id="cse-results">
	<div class="loading"></div>

You’ll notice that this code has an element with a class of “loading”. You’ll style this element with whatever CSS that you want to see while the results are loading. This would usually be a loading animation. You can find your choice of loading animation at, save it to your theme files, and use the following CSS rule in your theme’s style.css to show the animation.

#cse-results .loading {
	background: url("images/loading.gif") no-repeat scroll center center transparent;
	height: 64px;
	margin: 100px auto;
	width: 64px;

You might need to fiddle with the height and width of this rule to fit the image if it’s larger than 64 pixels.

You can now test out the 404 page by trying to go to a URL on your blog that doesn’t exist. After a brief loading animation, the Google Custom Search results should appear.

Modify search page

The search page code has some similarities to the 404 page code, but it also includes a search box.  Put the following code in your search.php file’s header area and update the file locations, same as for the 404 page.

wp_enqueue_script('cse', get_bloginfo('template_url') . '/scripts/cse.js', array('jquery'), false, true);
wp_localize_script('cse', 'cseSettings', array(
	'wrapperScript' => get_bloginfo( 'template_url' ) . "/functions/cse_request.php",
	'numResults' => "10",
	'query' => $_GET['s']

And then put this code where you want the results to appear in the page.

<form action="<?php get_bloginfo('wpurl') ?>" onsubmit="return cseGetResults(this.s.value)" id="searchform" method="get" role="search">
	<input type="text" id="cse-search-box" class="search-box" name="s" value="<?php the_search_query(); ?>">
	<input type="submit" id="cse-submit" class="submit-button" value="" title="Search">
<div id="cse-results">
	<div class="loading"></div>

And that’s it for your search page. You can use whatever search box you have on your blog (e.g. a search widget in your sidebar) and it will show your Google Custom Search results. You can also test this page by passing the “s” parameter in a URL to your blog, i.e. And that segues us nicely into the next optional step.

Site Search Menu in Analytics

(Optional) Setup Google Analytics site search

If you use Google Analytics on your blog, you can also set up that to work with your site search. Go into the Custom Search admin, select your custom search engine, and go to the page for Google Analytics. This is a rather confusing page, but basically you just have to set the “query parameter” to “s” (without quotes) for your blog’s Analytics profile. And that’s all. You’ll find site searches in Analytics under the menu at right.

Leave a Reply

Your email address will not be published.