Note: ‘AJAX’ simply meaning ‘getting data via JavaScript’, not Jesse James Garrett’s more holistic approach.
For a project I’ve been working on I needed a way to easily grab data from the backend without reloading the page. I didn’t want to fight with any of the big AJAX plugins, as the ones I looked into seemed to have their own complicated approaches involving magic markup or pre-formatted output, or didn’t seem to work. I also wasn’t interested in spending the time to learn about writing my own plugin.
After some hunting I came across a explanation (dead; temporary cache) stolen from another site (also dead) that led me to my eventual solution.
The essence is as follows: if you want to dynamically pull in, say, search
results, add the following to the top of your search.php file:
<?php
if ('1' == $_GET['ajax']) {
?>
<ul>
<? php
if (have_posts()) {
while (have_posts()) : the_post();
?>
<li id='post-<?php the_ID() ?>'><a href='<?php the_permalink() ?>'><?php the_title() ?></a></li>
<?php
endwhile;
} else {
?>
<li class='empty'>No results.</li>
<?php
}
?>
</ul>
<?php
} else {
?>
(See also: simplified WordPress post loop)
This means that if you load /index.php?s=foo&ajax=1 you might get something like:
<ul>
<li id='post-5'><a href='http://example.com/?p=5'>foo baz!</a></li>
<li id='post-3'><a href='http://example.com/?p=3'>foo bar!</a></li>
</ul>
Let’s hook it up
Assume our search form’s search box has the id #s (as is standard for
WordPress). With the assistance of Andreas
Lagerkvist’s liveSearch jQuery plugin (also dead
currently, but code here) we can get a dynamically-updated
list of search results.
$("#s").liveSearch({url: 'index.php?ajax=1&s='});
Make it multi-purpose
With a slight adaptation, the above approach can be used to get various
other data out. For example, if we use WordPress’ built-in
wp_list_categories() function…
<div id='categories'>
<?php wp_list_categories() ?>
<div id='in_category'></div>
</div>
The wp_list_categories() function will give markup like the following:
<li class='categories'>Categories
<ul>
<li class='cat-item cat-item-3'><a href='http://example.com/?cat=3' title='View all posts filed under Demo'>Demo</a></li>
<li class='cat-item cat-item-2'><a href='http://example.com/?cat=2' title='View all posts filed under Sample'>Sample</a></li>
<li class='cat-item cat-item-1'><a href='http://example.com/?cat=1' title='View all posts filed under Uncategorized'>Uncategorized</a></li>
</ul>
</li>
If we copy the PHP we used for our search
results into the top of the category.php file, we can pull in a list of a
given category’s entries:
$(".categories .cat-item a").click(function () {
theURL = $(this).attr("href") + '?ajax=1';
$.get(theURL), function (data) {
$("#in_category").html(data);
return false;
});
});
This means that if the user clicks a link for a category, instead of going
to the actual page it’ll get the link’s address, tack on our ajax
parameter, and stick the resultant data into the #in_category <div>.
(return false cancels the click event, thus preventing the link
from clicking through.)
A complication involving nice permalinks
All the above examples have assumed that the WordPress installation is
using the default permalink structure (i.e.
?p=n for posts, ?cat=n for categories, and so on). Thus we used
&ajax=1, because we our pages will have already have something like
?cat=3. But this assumption breaks the moment the user switches away from
the default permalink structure, because our links will now have the form
/category/uncategorized. Note: the old
URLs will still work, they just won’t be
exposed — so our search code is unaffected.
So what can we do?
Well, the easiest solution is to simply check if the
URL we’re working with has a ?:
if (undefined === $(this).attr("href").split('?')[1]) {
// using nice permalinks
} else {
// default permalinks
}
This works by splitting the URL
string into an array, using ? as a separator. Nice permalinks won’t have a
question mark, so the array will only have one element (remember, arrays
are zero-indexed).
Rather than repeating this code everywhere, we can write a little function that simplifies the process:
var ajaxURL = function (url) {
var token = (undefined === url.split('?')[1] ? '?' : '&';
return url + token + 'ajax=1';
}
And we adapt our jQuery to:
$(".categories .cat-item a").click(function () {
theURL = ajaxURL($(this).attr("href"));
$.get(theURL), function (data) {
$("#in_category").html(data);
return false;
});
});
Finally
This approach of listening for ajax=1 will work on probably any page
type. In the project that inspired this entry, I’m using it for searching,
categories, pages, and date-based archives.
