This article allows you to easily implement in-page search results in any Movable Type page. What exactly does this mean? Your standard Movable Type blog has a nifty search form on every page. One thing I have always wanted is to display the search results IN the page without refreshing to another page. This is quite easy to do using Javascript and a few commands [notably XMLHttpRequest() ] that make up something we call AJAX.
To implement in-page search results, you must complete 5 easy steps.
To get started I suggest you copy the code below into a file called "ajax.tmpl".
<div id="search-results">
<div class="search-results-string">
Search results for "<em><MTSearchString></em>" <div><!-- class="search-results-string" -->
<MTNoSearch>
<div class="search-results-blank">
You must search for something!
</div><!-- class="search-results-blank" -->
</MTNoSearch>
<MTNoSearchResults>
<div class="search-results-none">
No results found.
</div><!-- class="search-results-none" -->
</MTNoSearchResults>
<MTSearchResults>
<div id="item-<$MTEntryID$>" class="search-results-item">
<a href="<$MTEntryLink$>" title="<$MTEntryExcerpt encode_xml="1"$>"><$MTEntryTitle$></a>
<div class="search-results-date">
<$MTEntryDate$>
</div><!-- class="search-results-date" -->
</div><!-- id="item-<$MTEntryID$>" class="search-results-item"-->
</MTSearchResults>
</div><!-- id="search-results" -->
Save this file and upload it into MT_PATH/search_templates/ where MT_PATH is the path of your Movable Type installation. For my site this is /mt/search_templates/ajax.tmpl.
Don't worry, this step is REALLY easy. You only need to add AltTemplate ajax ajax.tmpl to your mt-config.cgi file. Add it in the Alternate Search Templates section. This section should be located around line 433. If you want, just search for "AltTemplate".
For those that are curious, the reason for adding a new template is to allow you to keep the existing search page template. This might be helpful if you want to provide "Advanced Search" since the default template has "Match case" and "Regex" searching options. When we modify the search form, we will tell Movable Type to use this new "ajax" search template.
Save and upload the mt-config.cgi file to your server.
The most simple way to implement this search method is to add the script to your existing javascript template. If you're not familiar with this don't worry, its a piece of cake. Log in to Movable Type and go to Templates. You will see a template called Site Javascript (mt-site.js). Click to edit it and add the code below to the bottom of the template.
var url = "/mt/mt-search.cgi?"; // The server-side script function handleHttpResponse() { document.getElementById("search-button").disabled=true; if (http.readyState == 4) { document.getElementById('searchstring').value = ""; document.getElementById('search-results-container').innerHTML = http.responseText; document.getElementById("search-button").disabled=false; } } function searchMT() { var searchstring = document.getElementById("searchstring").value; var template = document.getElementById("template").value; var poststr = "search=" + encodeURI(searchstring) + "&Template=" + encodeURI(template); http.open("GET", url + poststr, true); http.onreadystatechange = handleHttpResponse; http.send(null); } function getHTTPObject() { var xmlhttp; /*@cc_on @if (@_jscript_version >= 5) try { xmlhttp = new ActiveXObject("Msxml2.XMLHTTP"); } catch (e) { try { xmlhttp = new ActiveXObject("Microsoft.XMLHTTP"); } catch (E) { xmlhttp = false; } } @else xmlhttp = false; @end @*/ if (!xmlhttp && typeof XMLHttpRequest != 'undefined') { try { xmlhttp = new XMLHttpRequest(); } catch (e) { xmlhttp = false; } } return xmlhttp; } var http = getHTTPObject(); // We create the HTTP Object
You must modify the first line of the javascript to point to your Movable Type search script (mt-search.cgi). For those of you that have installed Movable Type in the root of your web site and named the folder /mt/, you shouldn't have to change anything. If you happen to have your Movable Type installation in a cgi-bin folder, you will need something like this: /cgi-bin/mt/mt-search.cgi? Don't forget the question mark at the end!
This is probably the most tedious step in the tutorial but it's really not that bad. In this step we must modify the search form to interact with the AJAX Javascript instead of sending you to the search results page.
Let's start with the Main Index template for your site.
Locate the HTML that starts with <form and ends with </form> Delete it! Uncomfortable? Well, to be sure, here is some sample code that you should delete.
<form method="get" action="<$MTCGIPath$><$MTSearchScript$>">
<input type="hidden" name="IncludeBlogs" value="<$MTBlogID$>" />
<label for="search" accesskey="4">Search this blog:</label><br />
<input id="search" name="search" size="20" />
<input type="submit" value="Search" />
</form>
Once you've blown that away, go ahead and add the following code in its place:
<input name="search" type="text" id="searchstring" size="18" />
<input id="template" type="hidden" name="Template" value="ajax" />
<input id="search-button" type="submit" name="search-button" value="Search" onClick="searchMT();"/>
That's all you need to do for this step, but you're not done until you complete the next step. Go ahead and move on before you repeat this step with all of your other template pages. Don't forget to come back!
I know you've seen all the <div> tags in Movable Type. Don't worry if you don't quite understand what they are. To complete this tutorial you merely need to add the following code to your templates:
<div id="search-results-container"></div>
Where? you ask??? That's a great question. Remember, this is the block that will contain all of the results from your search. You are free to put this anywhere on your page. But I suggest you keep it in the vicinity of the search form or else your users will become confused (stupid users!). You will see that I put the results right underneath the search form at the top of this page. It wouldn't have been very useful for me to place the results all the way down here, but I could have!
Ok, now that you've added the div tag you should be able to test this out. Remember to rebuild your Main index template and the Javascript (mt-site.js) template first.
If everything is working you can go back and repeat steps 4 and 5 for each of your other templates. Keep in mind that you can add search to ANY page on your web site, regardless of whether or not it is a Movable Type generated page. This very page provides search for my blog, but this is not a Movable Type generated page..
The rest of this article is optional. If you are done, please read "Parting Thoughts."
Notice how my search results above look different from the ones on your site? This is because I have added styles for the various elements returned from the search form.
Are you using a default Movable Type style template? If you've never modified any of the styles in Movable Type you may be confused with how to change the look of the search results. It is really quite simple once you get the hang of it. To get started, copy the following into your styles-site.css template:
#search-results {
margin: 10px;
padding: 10px;
width: 300px;
border: thin solid #990000;
}
#search-results a { text-decoration:none; color:#990000; font-family:Arial, Helvetica, sans-serif; font-size:12px; }
#search-results a:hover { text-decoration:underline; }
.search-results-blank,
.search-results-none {
margin-top:10px;
font-weight:bold;
}
.search-resutls-string {
color:#990000;
}
.search-results-item {
margin-top:10px;
}
.search-results-date {
font-size:10px;
color:#666666;
}
This code can go anywhere in the styles-site.css style sheet but I recommend you put it at the very bottom. Just do an Internet search for "CSS tutorial" if you would like to learn more about formatting.
Search only one blog (Thanks to Joseph for this addition.)
In order to search only one blog we need to pass the IncludeBlog parameter into the mt-search.cgi file.
In order to do this, we need to pass a variable from the search form into the Javascript file to let the system know what blog to search for. This is only helpful if you have multiple blogs on your site AND you want to limit the search results to just one blog (something I never needed to do). First, you need to add a way to send the blog ID from the search page into the Javascript. The most simple way is to add a HIDDEN form field like so:
<input type="hidden" name="IncludeBlog" id="IncludeBlog" value="6" />
NOTE: If desired, you could use a drop down menu to allow the user to select the blog to search.
Next, we need to modify the searchMT() function in the Javascript file. We are going to make two changes. The first is to set a variable to the hidden form value. The second is to add this paramater to the POST string.
function searchMT() {
var searchstring = document.getElementById("searchstring").value;
var includeblog = document.getElementById("IncludeBlog").value;
var template = document.getElementById("template").value;
var poststr = "search=" + encodeURI(searchstring) + "&IncludeBlog=" + includeblog + "&Template=" + encodeURI(template);
http.open("GET", url + poststr, true);
http.onreadystatechange = handleHttpResponse;
http.send(null);
}
Incorporating keyword clouds
This addendum covers how to return instant results from a keyword or category cloud.
A keyword cloud typically looks something like this...
hokies basketball virginia
tech football acc
To invoke the search using keywords we only need to make a few minor changes. We will keep the two hidden inputs that specify the blog to search as well as the search template to use. However, instead of having a textbox for the user to input a search term, we will hook up each of the keyword link to call the search function. We will also drop the "search" button. Please keep what is in black and drop what is in red.
<input id="template" type="hidden" name="Template" value="ajax" /> <input id="IncludeBlog" type="hidden" name="IncludeBlog" value="6" /> <input name="search" type="text" id="searchstring" size="18" /> <input id="search-button" type="submit" name="search-button" value="Search" onClick="searchMT();"/>
Each of the keywords or categories are linked. In this example we are going to modify this to invoke the AJAX search when a keyword is pressed. Using the "hokies" tag as an example...
<a href="javascript:searchKeywordMT('hokies')" title="Search for this keyword">abstract</a>
You will need to output your page to automatically generate the links above. Once you have done this you have sucessfully passed a parameter into the function. This will take the place of the searchstring textbox. Now we must change the JavaScript functions. Let's start with the handleHttpResponse() function. Delete the following lines of code:
document.getElementById("search-button").disabled=true;
document.getElementById('searchstring').value = "";
document.getElementById("search-button").disabled=false;
Now the final change involves the searchMT() function. We will create a new function called searchKeywordMT(). Copy the following into your JavaScript file:
function searchKeywordMT(searchstring) {
var includeblog = document.getElementById("IncludeBlog").value;
var template = document.getElementById("template").value;
var poststr = "search=" + encodeURI(searchstring) + "&IncludeBlog=" + includeblog + "&Template=" + encodeURI(template);
http.open("GET", url + poststr, true);
http.onreadystatechange = handleHttpResponse;
http.send(null);
}
You should now be able to return results by simply clicking on the keywords. Here's an example of this in action: Jyoseph.com.
This concludes my brief tutorial on adding in-page search results to Movable Type. I hope it went smoothly and without error. If not, feel free to contact me with any questions. No hate-mail please.