Musings
ExpressionEngine autocomplete search / jump menu with jQuery
7th October 2009
This tutorial will show you how to build an text input that will give autocomplete / auto suggestions via AJAX straight from an ExpressionEngine template then redirect straight to the entry. It could be used for searching, or shortcuts to particular entries, I have it working for the latter on a recent project. It will allow you to …
- Start typing parts of an entry
- Scroll through the autocompleted suggestions that pop up
- Click one (or use the keyboard shortcuts)
- Get redirected to the relevant entry on the relevant page
- View the demo here (search for resorts)
- Download the template files here
I’ve recently altered the functionality recently to use $_POST rather than $_GET which makes it both more secure and easier to implement.

1) Get all the bits you need!
This functionality depends on the following bits, so go get them downloaded and included in your site:
2) The templates
Here’s a screenshot of the templates I’ve used in the demo:
- The index page is where we’ll house the autocomplete
- The 2 javascript files will do the work for us
- The single_entry template is where we’ll redirect to show the full entry
- The _autocompleter is the template that will dynamically look up the entries as we type them
If you so wish you can download all the templates instead of reading through all the code here.
The index template
Include the Javascript and add a little CSS for the markup, there is some default css included with the autocompleter plugin. Then we’ll need to make the form and that all important input text box:
<h2>Autocomplete</h2>
<!-- Form action can be anything - make sure it degrades nicely -->
<form id="quickjump" action="/index.php/autcomplete/results/" method="post">
<fieldset>
<p><label for="quickjump_title"></label><br />
<!-- We'll scan this text field for matching entries -->
<input type="text" size="20" id="quickjump_title" name="quickjump_title" /></p>
<!-- Again the search button is just so it degrades -->
<button type="submit">Go</button></p>
</fieldset>
</form>
We’ll then write the JavaScript to call the autocomplete plugin and handle the results
<script type="text/javascript">
$(document).ready(function(){
// Autocomplete
$("input#quickjump_title").autocomplete("/index.php/autocomplete/_autocompleter/",{
cacheLength: 0,
minChars: 3,
formatItem: function (row) { return row[0] },
formatResult: function (row){ return row[1] }
}).result(function(event, item) {
//redirect to the URL in the string
window.location.href = "{path="autocomplete/single_entry"}"+item[1];
});
});
</script>
You’ll notice the autocomplete url we’re calling is one of the templates, it must be referenced with /index.php/template_group/template/ with all slashes intact as well as index.php. The second part of that function will redirect the user to the single entry page with the correct url.
JAVASCRIPT ALTERATIONS
I mentioned I’d altered the script to use $_POST ajax calls rather than sending them in the url with $_GET. This means you can be a bit cleaner with the url you pass as well as enjoying a bit more security (if you enjoy that sort of thing;)
Firstly you’ll need to alter the jquery autocomplete source, lucky for us jQuery have made it really simple – we’ll use the $.ajaxSetup function to ensure we’re posting not getting the results. Download the complete pack and open the uncompressed file, then inside the request function we’re going to set the params for ajax calls just before the $.ajax({ call. At the time of writing that’s at about line 361. Just add the following:
$.ajaxSetup({ type: "POST" });
Make sure it’s before that $.ajax({ call.
You can now remove the /index.php/ part of the request url so it will look like
$("input#quickjump_title").autocomplete("/index.php/autocomplete/_autocompleter/",{
...
The _autocompleter template
This template needs to have PHP switched on at the input stage (see the template options)
Pretty simple once we’re in though:
{exp:weblog:entries weblog="thoughts" search:thought_body="<?php echo $_GET['q'] ?>"}
{exp:char_limit total="20"}{exp:html_strip}{thought_body}{/exp:html_strip}{/exp:char_limit}|{url_title}
{/exp:weblog:entries}
I’m using it to access my thoughts weblog, your settings will probably be different, you can adjust as you need. What we’re returning though are pipe separated rows “excerpt|url_title” the autocompleter plugin will do the rest. The PHP is just picking the variable from the url (passed by AJAX) and using the search parameter in the entries tag.
Single entry template
You probably don’t need me to help you here, it’s just a template to pick out the single entry based on the url:
{exp:weblog:entries weblog="thoughts" limit="1"}
<h2>{title}</h2>
{thought_body}
{/exp:weblog:entries}
Simples.
As usual, any questions post them up – I mean to revise and improve this post over time and I’d appreciate your feedback.
Discuss
Get involved in the discussion by using the comment form below.
12th October 2009
@Douglas my advice would be to use {query} to update the search term log (only upon successful relocation.) That would mean adding another AJAX call to the redirect callback to another template (or the same one with one conditional captures.)
Something like
userdata[‘screen_name’].”’,’”.$SESS->userdata[‘ip_address’].”’,”.time().”,‘site’,’”.$_GET[‘stuff_from_ajax’].”’”;
$DB->query($sql);
?>
I haven’t checked that, or even used a reference for the global classes, but it’s something like that
13th October 2009
Hi Wil,
Just wanted to say a massive thank you for this tutorial. Finally got it all working after figuring out why it wasn’t working for me. I was trying this all out on a localhost MAMP (OSX) installation and couldn’t get it to work for ages until I figured out that I needed to supply full URLs such as http://localhost:8888/index.php/ instead of just /index.php/autocomplete/results to the templates.
Once I did that then everything started working! ![]()
Not too sure why MAMP is different as I’m guessing there wouldn’t be any problem on a true server (haven’t tried that yet but I’m sure it will be fine).
Anyhow a really great tutorial so thanks for that.
Best wishes,
Mark
13th October 2009
That’s a great point @Mark - I’ve assumed the site is running on the root of the server. The url I have used is relative - handing an absolute would be more full proof.
21st October 2009
Help Needed!
I am using a web-method written in a code-behind (c#) to populate my autocomplete fields.
How can I access that data items in the autocomplete options(on client side) so as to make the “suggestions” redirect to a different webpage?
CodeBehind :
<WebMethod()> Public Shared Function GetProjects(ByVal filter As String) As String
Dim items As New List(Of Item)
Dim objconn As New SqlConnection(“Data Source=DEV;Integrated Security=SSPI;Initial Catalog=Panacea”)
objconn.Open()
Dim Projects As New SqlCommand
Projects.Connection = objconn
Projects.CommandType = CommandType.StoredProcedure
Projects.Parameters.Add(”@strFilter”, SqlDbType.NVarChar).Value = filter
Projects.CommandText = “hsp_GetProjects”
Dim datareader As SqlDataReader = Projects.ExecuteReader
While datareader.Read
Dim item As Item
item.value = “http://www.google.com”
item.name = datareader(“ProjectName”).ToString
items.Add(item)
End While
datareader.Close()
objconn.Close()
Dim json As New StringBuilder
Dim serializer As New JavaScriptSerializer
serializer.Serialize(items, json)
Return json.ToString()
End Function
Aspx file:
//txtProjectName is a text box.
$(”#txtProjectName”).autocomplete(“DJ_AddProject.aspx/GetProjects”, {});
22nd October 2009
Hi Wil,
I am working on the clickable-autocomplete functionality.
I get my data through a c# web method in the code-behind, in the format
[{“value”: “http://xyz1.com”, “name”:“Project1”},
“value”: “http://xyz2.com”, “name”:“Project2”}]
GetProjects is my webmethod which returns Json serialized string arryas in the aforementioned format.
$(”#ProjectName”).autocomplete(‘Add_Project.aspx/GetProjects ’ , {} );
I do not know how to use formatItem or formatResult in my case, and I have tried pretty much everything but, the returned result does not redirect.
Please help.
I have this delivery tomorrow!
Thanks.
Sid
22nd October 2009
@sid the formatting is essentially just returning the pipe separated string as an array.
The jQuery then just tacks on the second item to the ExpressionEngine path (”{path=“autocomplete/single_entry”}”+item[1];) you could just forgoe the formatting and stick the url_title you wanted in there. It’s just nicer to see the title than the url in the search results.
31st October 2009
@Joe yes I’m using Mark Croxton’s Search Fields plugin, it gives a whole lot more power to the search parameter.
Mine looks like:
search:title=”<?php echo $IN->clean_input_data($_GET[‘q’]) ?>” search:Res_Name=”<?php echo $_GET[‘q’] ?>” operator=“OR”
2nd November 2009
I’ve just updated the tutorial with some instructions to get the autocomplete to work with $_POST rather than $_GET which is safer, easier to implement and just all round a bit better
27th January 2010
Hey there,
Thanks for the article and code. It is very useful.
One thing to note however is that for this to work properly you MUST have the HTML Strip plugin in your EE installation. To get the plugin you can go here: http://expressionengine.com/downloads/details/html_strip/
This caused me a fair bit of grief thinking my javascript was wrong since I customized a lot. But eventually the problem showed to be that I hadn’t uploaded HTML Strip and once I did, it worked flawlessly.
Thanks again,
-Alex
7th February 2010
Hi,
Will this work for EE 2.0?
I’ve got it implemented, and if I type a letter, it seems to list the elements in the code e.g. <head><body> - then lists a few styles - ....
7th February 2010
Sounds like you’re getting the user message template. I’d check the template on it’s on (actually visit it in the browser) and check all is well.
7th February 2010
Hello,
I’m currently using this with EE 2.0 aswell - If I type “Ar” - then i would expect o see companies that are only starting with “Ar” e.g. Argos… But it’s showing all entries and only highlighting the “Argos” entry - I thought it worked by removing entries that do not start with the search query….
Can you assist please?
21st February 2010
Hi Wil,
Great product you have here.
I’m trying to do a search on the title e.g.
{exp:channel:entries channel=“make” search:title=”<?php echo $_POST[‘q’] ?>”}
The ajax search lists all entries but only highlights the related result/entry - it doesn’t remove all the results that don’t… so I have this massive list…
Any ideas please?
22nd February 2010
@Ben - that’s probably to do with the ‘search’ parameters limitations. My advice would be to use Mark Croxton’s search fields plugin - it’ll open up a load more fields you can search (including the title.)
23rd March 2010
Hey Wil,
This plugin is fantastc and your instructions made implementing it a breeze.
I want to extend this using Mark Croxton’s search plugin, but say for example I have a news weblog and an events weblog, each with different paths to the single entry page, how will this change the example: “[removed].href = “{path=“autocomplete/single_entry”}”+item[1];
” if there are potentially multiple paths?
Or did I miss something? :S
Many thanks,
Jordan
18th April 2010
Hi Wil,
Do you happen to know of any alternative or an update for Mark Croxton’s search plugin that works on EE 2? Thanks.
18th April 2010
Agreed, being able to search title within EE 2.0 using this plugin would be perfecto!
19th April 2010
I have been tinkering with plans to turn this into an addon, but in the mean time I’d suggest just using the query module in the search results template. That’ll tidy you over for now…
27th July 2010
Hi Will,
Thanks for the tutorial! I seem to be getting one problem though…no matter what the search term is, the autocomplete is only displaying the latest entries, instead of the ones that are relevant to the term being searched. Any idea how to fix that?


wil.linssen
8th October 2009
A great tip from Kenny Meyers will ensure the template we use to return the results is viewable by AJAX only http://eeinsider.com/tips/view/ajax-request-code/