Scott Boms

Our December 2004 Back Catalogue

Implementing Livesearch (Updated)

It’s been a while since I’ve done a tutorial on anything so as a last-minute holiday treat I’ve got one cooked up on a feature that I’ve wanted to explore implementing here for some time.

Resources

Let’s get the resources out of the way so you know where to get the relevant pieces of open-source code and can see a nice implementation of what we’re going to build.

Laying The Groundwork

Follow along and you should have a basic framework for implementing livesearch functionality on your own site. Start by downloading the required BitFlux JavaScript file and take note of the installation details. We’ll go over them here, but read through the content on the topic there first.

Take the ‘livesearch.js’ file and copy it to your site wherever you keep your Javascript files. For the purposes of this tutorial, I’ll assume this file will be located in the root directory of your site.

In the livesearch.js file locate the first line that contains /livesearch.php?q= near the end of the file. To specify the search variable as something other than “q”, change this here and in the lines that follow. There are a total of three instances that will need to be changed.

As an example, to rename the variable to “s”, the replacement text would be /livesearch.php?s=. Also note that you can rename the livesearch.php file to something else if desired. This script will do the work of performing the search and returning the results back to the browser. Just be sure to make the same changes in the Javascript if you rename the file.

Determine the necessary SQL query to search your Movable Type entries. Exactly how you decide to do this is really up to you. The SQL here is more of a quick example and you may want something more robust.


SELECT entry_id, entry_title, entry_excerpt, 
DATE_FORM(entry_created_on, '%Y_%m') AS date 
FROM mt_entry WHERE entry_text LIKE '%$s%' 
ORDER BY entry_created_on DESC

The $search variable included in the SQL should also match the name passed from the search form. Exactly what is returned is entirely up to you. In this case, the query returns the entry ID, title, and excerpt with the results sorted by date in descending order.

To restrict the results to a single blog if you have more than one, you would also want to filter by the entry_blog_id in the WHERE clause. For example, WHERE entry_blog_id = '1' AND entry_text LIKE '%$s%', etc.

It would be useful to split the results into multiple pages if a large result set is sent back (eg. 10 results at a time) but that’s outside the scope of this tutorial.

The next piece of the puzzle is to return the results in a standard XML format to be parsed by the XMLHTTPRequest JavaScript object. The Wiki page describes the format required but you can see it more clearly here in context of the PHP you will need to return a correctly formatted result set.


echo "<?xml version='1.0' encoding='utf-8' ?>"
echo "<ul class='LSRes'>\n"
while ($row = @mysql_fetch_array($query_results)) {
  echo "<li class='LSRow'>Link text</li>"
}
echo "</ul>\n"

You may not want to copy this verbatim, but it should be enough to give you a good start on how to return the results. Include links and such where appropriate and watch out for whitespace parsing and validation issues with the XML returned. Note that you don’t have to use an unordered list here, this is just a suggestion to keep thing clean and arguably semantically correct. It’s also easy to style with CSS.

Once your PHP script is completed, test it manually to see if it’s returning results as expected. Upload the file to your server and call it along with the appropriate search query appended. For example,

yoursite.com/livesearch.php?s=querystring

If all goes well and matches are returned you should see a nicely formatted list of results. If not, you’ve got some SQL or PHP debugging to do.

Implementation

Implementing livesearch into Movable Type, replacing the default search functionality is straightforward, but presents a few challenges. The first thing to take into account is where search is located throughout the site. For now, I’m assuming that search functionality is only available within the Main Index template.

In that Main Index template, locate the search form code. The default search form in Movable Type does not include an ID/name attribute and uses a button we technically will no longer need. Change the form code to:


<form name="searchform" id="searchform" action="archives/" method="get">
  <input type="text" name="s" id="livesearch" onkeypress="liveSearchStart();">
  <div id="LSResult" style="display: none;"><div id="LSShadow"></div></div>
</form>

Formatting is important here. Make sure the third line with the DIVs has any whitespace removed. Whitespace appeared to cause problems returning results during my testing.

Next, in the HEAD section of the template, include the livesearch.js file and initialize the livesearch script by attaching an onload event to the BODY tag.

<body onload="liveSearchInit();">

There are better ways to handle this, especially if you need to be able to execute multiple functions on the DOM when the page loads, but this is suitable for this simple example. Save the template changes and style as desired with CSS. Repeat as required wherever the search form appears.

Caveats

This isn’t foolproof of course. It doesn’t work in some browsers, or in some cases, not completely. It doesn’t work at all in IE 5 for the Mac or Opera 7.x (and one can assume earlier versions as well). It mostly works in OmniWeb 5.1 beta 5 based on very minimal testing. And there’s also the issue of graceful degradation. Users with Javascript turned off are out of luck with search since livesearch relies entirely on Javascript. Providing a fallback for those users would be a worthwhile addition.

Last Updated: December 22, 2004

Moving Your MT Install

Sorry for the lack of posts over the last few days. I’ve been occupied with a small (large?) issue that I (accidentally) noticed and which seems to have occurred during the period back in October when I moved and upgraded the site to Movable Type 3.1.

During the process of the move and upgrade, I cleaned up the post IDs (kind of accidentally actually) and during one of the import processes, the actual entries for the blog got a bit messed up. In the body/summary fields, certain words somehow ended up capitalized wherever they appeared. Not coincidentally these words were all special reserved keywords in MySQL — such as DISTINCT, SELECT, DELETE, CHECK, FROM, UPDATE, etc.

I’m not sure how this happened and it’s been a real nuisance to fix, but it did provide me with an opportunity to update the archives to all use the Markdown with SmartyPants text formatting plug-ins along with cleaning up some of the less than semantically correct HTML throughout.

Overall things are generally better now, allowing me to get back to the next big feature (and the last) that will likely make an appearance after this weekend or early next week given my current holiday schedule; leaving me time to finish the design and architecture phase of a long-overdue redesign. This will also coincide with the even longer overdue launch of the Wishingline Design Studio, Inc. site.

I’ve said it before, but the right dose of inspiration hit and I’m on a bit of a roll with things so far. Hopefully I can keep up the pace for as long as I need to get it done.

Anyway, back to MT… The lesson here is: be very careful when you import or export your entries. I don’t know which method is better — using a MySQL dump or the built-in Movable Type export/import functions. One of those two produced the problem I ran into and I’m debating testing with a local MT install to figure out which one. If I do, I will post the results here.

Update

It appears that Movable Type was able to export/import the entries cleanly and also did not exhibit the problems I encountered with phpMyAdmin did.

« November 2004January 2005 »