Advertisement

Add jQuery Autocomplete to Your Site's Search

by

The function get_search_form() can (and should!) be used to display the search form for your site. It does the job, but it's very bland. Shipped with WordPress since 3.3, however, is a tool which can make using it a lot easier. In this tutorial I'll be showing you how to add jQuery Autocomplete to your search form.


Open Up Your Search Form

This tutorial assumes that your theme uses get_search_form() to display your search form and calls wp_footer().

First let's take a look at the TwentyEleven search form (searchform.php in your theme). Chances are, yours is very similar. If you can't find searchform.php in your theme, then it's probably using the default mark-up which is almost identical. If your search form is hard-coded I'd recommend putting it into searchform.php, and using get_search_form(); to display it.

<form method="get" id="searchform" action="<?php echo esc_url( home_url( '/' ) ); ?>">
	<label for="s"><?php _e( 'Search', 'twentyeleven' ); ?></label>
	<input type="text" name="s" id="s" placeholder="<?php esc_attr_e( 'Search', 'twentyeleven' ); ?>" />
	<input type="submit" name="submit" id="searchsubmit" value="<?php esc_attr_e( 'Search', 'twentyeleven' ); ?>" />
</form>

What we're after is the ID attribute of the search input, so we can target it with jQuery. In this case it's 's'.

Before we start, let's do a bit of ground work. This will also serve as a summary of what we shall be doing.


Step 1 Ground Work

All the following should go into your theme's functions.php. We are going to hook onto the 'init' hook with a function that will:

  • Register some CSS and JavaScript – We're going to need some of the jQuery UI styling. I'm just going to use the basic styling, but you can always roll your own theme to fit in with your site. You can add it to your theme's style.css or keep it in a separate file and register it as shown here. We are going to need some custom javascript too, which I will call myacsearch.js and store it in my theme's js folder.
  • Hook our JavaScript and CSS – We want to add our styling and javascript when (and only when) the search form is displayed. The get_search_form filter fires whenever this happens, and we'll use that to enqueue our scripts and styles.
  • Ajax actions – We need to add a callback function to process the request and return the results when WordPress receives our action via AJAX. To do this we use the hooks, wp_ajax_{action} and wp_ajax_nopriv_{action} where {action} is used as an identifier for the action we wish to perform (and so should be unique). I shall set it to myprefix_autocompletesearch.
add_action( 'init', 'myprefix_autocomplete_init' );
function myprefix_autocomplete_init() {
	// Register our jQuery UI style and our custom javascript file
	wp_register_style('myprefix-jquery-ui','http://ajax.googleapis.com/ajax/libs/jqueryui/1.8/themes/base/jquery-ui.css');
	wp_register_script( 'my_acsearch', get_template_directory_uri() . '/js/myacsearch.js', array('jquery','jquery-ui-autocomplete'),null,true);

	// Function to fire whenever search form is displayed
	add_action( 'get_search_form', 'myprefix_autocomplete_search_form' );

	// Functions to deal with the AJAX request - one for logged in users, the other for non-logged in users.
	add_action( 'wp_ajax_myprefix_autocompletesearch', 'myprefix_autocomplete_suggestions' );
	add_action( 'wp_ajax_nopriv_myprefix_autocompletesearch', 'myprefix_autocomplete_suggestions' );
}

Step 2 The AJAX URL

We'll be using AJAX to send the search form's input and return the matching posts as the user types. So we will need to give Autocomplete the URL to send the request to. WordPress has a specific URL which deals with AJAX requests, and this is given by admin_url( 'admin-ajax.php' ). This gives us the URL on the server side – but we want it in our javascript file. This can be done using wp_localize_script. This function was originally intended to help with localisation, but we can repurpose it for our use. Put this immediately after registering the custom javascript my_acsearch in step 1:

wp_localize_script( 'my_acsearch', 'MyAcSearch', array('url' => admin_url( 'admin-ajax.php' )));

This defines an object MyAcSearch which has a property 'url'. Such a method allows you to send settings stored in the database to the javascript file, but for our purposes we only need MyAcSearch.url which is the URL to direct our AJAX request.


Step 3 The JavaScript

jQuery's autocomplete comes with a fair bit of functionality packed into it, but we'll be sticking to the basics. You can see all its features on the demo page. The data we send to the AJAX URL will include an action variable whose value is the action identifier we set in step 1. In our case it's myprefix_autocompletesearch. So, now in our javascript file, add the following.

var acs_action = 'myprefix_autocompletesearch';

This allows us to identify the request, perform the search and return the results. Next we apply the Autocomplete function to the search form (here we use the ID attribute of the form input):

$("#s").autocomplete({
	source: function(req, response){
		$.getJSON(MyAcSearch.url+'?callback=?&action='+acs_action, req, response);
	},
	select: function(event, ui) {
		window.location.href=ui.item.link;
	},
	minLength: 3,
});

The source function should return an array of objects. Each object should have the property 'label' (to display in the suggestion list), and we'll be adding the property 'link', the URL of the post. The select function is fired when a user clicks one of the suggestions. In this example, clicking the suggestion takes you to that page. The minLength indicates the number of characters the user must type before the autocomplete kicks in.

We'll wrap this all in a .ready handler, so it's only run when the page has fully loaded. Then the complete javascript is:

jQuery(document).ready(function ($){
	var acs_action = 'myprefix_autocompletesearch';
	$("#s").autocomplete({
		source: function(req, response){
			$.getJSON(MyAcSearch.url+'?callback=?&action='+acs_action, req, response);
		},
		select: function(event, ui) {
			window.location.href=ui.item.link;
		},
		minLength: 3,
	});
});

Step 4 Enqueuing Our Scripts and Styles

Whenever the search form is displayed using the get_search_form(); function, our function myprefix_autocomplete_search_form will fire. In this function we enqueue the scripts and styles that we need for Autocomplete. We don't need to load jQuery or Autocomplete directly, WordPress already knows that we need it and will handle that for us.

function myprefix_autocomplete_search_form(){
	wp_enqueue_script( 'my_acsearch' );
	wp_enqueue_style( 'myprefix-jquery-ui' );
}

All that remains is to handle the AJAX request.


Step 5 Handling the AJAX Request

Recall that in our myprefix_autocomplete_init function we called something like the following:

add_action( 'wp_ajax_{action}', 'my_hooked_function' );
add_action( 'wp_ajax_nopriv_{action}', 'my_hooked_function' );

The first action is fired when WordPress receives an AJAX request with action given by {action} and the user is logged in. The second is fired when the user is not logged in. This can be particularly useful if you only want to process an AJAX request if the user is logged in. For our purposes we want it to work for both logged in and non-logged in users, so we hook our function onto both. Here we define that callback function, again this goes in your functions.php:

function myprefix_autocomplete_suggestions(){
	// Query for suggestions
	$posts = get_posts( array(
		's' =>$_REQUEST['term'],
	) );

	// Initialise suggestions array
	$suggestions=array();

	global $post;
	foreach ($posts as $post): setup_postdata($post);
		// Initialise suggestion array
		$suggestion = array();
		$suggestion['label'] = esc_html($post->post_title);
		$suggestion['link'] = get_permalink();

		// Add suggestion to suggestions array
		$suggestions[]= $suggestion;
	endforeach;

	// JSON encode and echo
	$response = $_GET["callback"] . "(" . json_encode($suggestions) . ")";
	echo $response;

	// Don't forget to exit!
	exit;
}

Let's go through this a bit at a time. The input the user has typed is sent along with the AJAX request, and is given by $_REQUEST['term']. We simply use get_posts' search attribute to search our posts with that term.

We then go through each of the returned posts, and for each one we construct a suggestion array. That array contains the post's title (we call it 'label' so Autocomplete will recognise it and use it for the suggestion list) and the post's permalink, so that clicking a post will direct the user to that page. We add each suggestion array to a suggestions array.

Next, we JSON encode the suggestions, and echo the result. Finally, we exit! And we're done!

Let us know what you think in the comments, and if you have any suggestions on how to extend on this, we'd love you to share those too.

Advertisement