Recently I was asked by a client to do some customisation of a Wordpress site to enable a site visitor to load posts from a certain category into the same part of the page via AJAX. This could have been done in a couple of different ways – using AJAX as requested; or all the posts could’ve been printed to the page, with javascript then used to hide all but one and also used to navigate between them in some sort of hide/show, fading/sliding effect. I’ve done similar things like this before using jQuery, but there were two reasons why I didn’t go that route on this occasion:
- With javascript turned off, all the posts from the selected category would’ve been displayed on the page and as the design called for three short columns of text on the page, having one column much, much longer than the other two would really have looked wrong.
- The client specifically asked for AJAX to be used.
So, to do this with AJAX and Wordpress I used two Pages, using two different templates. The first template is the one that is part of the main site and has the same design as surrounding pages, and the other is a stripped down template with no <html>, <head> or <body> tags which retrieves the requested posts from the database and just prints out the content of each.
Let’s look at these two templates, but first view the working example.
The post-retrieval template
<?php
/*
Template Name: Ajax example - retrieve posts
*/
query_posts('showposts=1&cat=1,2&offset='.$_GET['offset']);
if (have_posts()) :
while (have_posts()) : the_post();
the_title();
the_excerpt(); ?>
<p><a href="<?php the_permalink(); ?>">Read the rest of this entry »</a></p>
<?php
endwhile;
endif;
?>
The Wordpress function query_posts is used to select which category or categories of posts to display (in my example I’m displaying posts from the Wordpress and ExpressionEngine categories), showposts is set to 1 because only one post is going to be displayed at one time and offset is used because each time this template is requested, a new post, the next one along from the previous one, will be displayed. The querystring is being sent from the page requesting the AJAX content which we’ll look at next. What you put inside the Loop is up to you, but in my example I’m displaying the title, the excerpt and then a link to read the rest.
The post-display template
This template is made up of three parts:
-
A loop to count the number of posts in the category or categories to be displayed which will be used to help step through the posts using the
offsetparameter.<?php /* Template Name: Ajax example - display posts */ get_header(); $ajaxcount = 0; $cat1 = new WP_Query('category_name=wordpress&showposts=9999'); while ($cat1->have_posts()) : $cat1->the_post(); $ajaxcount++; endwhile; $cat2 = new WP_Query('category_name=expression-engine&showposts=9999'); while ($cat2->have_posts()) : $cat2->the_post(); $ajaxcount++; endwhile; ?>This looks a bit clunky, but I couldn’t find a way to pass multiple categories to the WP_Query function. I’m using this function because the Wordpress documentation says:
The query object
my_queryis used because you cannot use the globalhave_posts()andthe_post()since they both use$wp_query. Instead, call into your new$my_queryobject.This would only be necessary if you wanted to display posts from more than one category and it’s only really used to get a number of the posts we want to display.
-
Another separate loop to display the default post, i.e., the one you see when you first visit the page and the link to view the rest of the posts.
<?php query_posts('showposts=1&cat=1,2'); if (have_posts()) : while (have_posts()) : the_post(); ?> <h2><?php the_title(); ?></h2> <?php the_excerpt(); ?> <p><a href="<?php the_permalink(); ?>">Read the rest of this entry »</a></p> <?php endwhile; endif;?> <p><a href="/path/to/your/category/" class="ajax-link">Read more articles from this category</a></p>The
query_postsfunction here is the same as it is for the other template except that as this page will be displaying the first post from the categories, we don’t need to offset it, so that parameter is omitted.Note that there is an actual path to the category you want to display in the link. Even though the link is disabled by the javascript, if javascript is turned off, you want your visitors to still be able to access a page. Unfortunately, you can only link to a page for a single category, but there has to be a small price to pay for not having javascript enabled.
-
The jQuery javascript to request the AJAX content.
<script type="text/javascript" src="http://www.google.com/jsapi"></script> <script type="text/javascript">google.load("jquery", "1.2.6")</script> <script type="text/javascript"> $(document).ready(function(){ var ajaxcount = <?php echo $ajaxcount; ?>; var offset = 1; $('.ajax-link').click(function(){ $('#ajax-content *').fadeOut(500); $('#ajax-content + p').fadeOut(500); $('#ajax-content').load('/examples/ajax-handler/?offset='+offset); $('#ajax-content + p').fadeIn(1); offset++; if (offset == ajaxcount) { offset = 0 }; return false; }); }); </script>First we load jQuery using the Google JS loader, and then after checking that the document is ready, set up two variables: one,
ajaxcount, which contains the number of posts there are to display and the second for theoffsetwhich is set to 1 for the first instance. Each time the link is clicked, theoffsetvariable will increase until it’s equal to the count of posts at which point it will be reset to 0 so that we can display the originally displayed post again (and the loop can start all over again).Then a function is set up to perform the actions whenever the link is clicked and
return falseis used to prevent the browser redirecting to the link destination. The first actions in the function are to fade out the current content of thedivholding the content to be changed and also the paragraph holding the link that follows it (jQuery handles all CSS selectors fine so we can use the adjacent sibling selector here).Next we fetch the page with jQuery’s AJAX
loadfunction and give it a querystring equal to the current offset value.(It should be noted that if you wanted to display posts randomly instead of in any particular order, you wouldn’t need to send an offset value to the template that retrieves the posts, but because Internet Explorer thinks an AJAX request for the same URL, regardlesss of whether the content has changed or not, is the same as the previous request and displays the same content each time, you need to append a different querystring to the URL so that IE thinks the page is different each time. You could do this by generating a random number to append to the querystring – no-one is going to see the querystring anyway, except for the template retrieving the posts.)
Once the new content has been loaded, we fade the link back in. jQuery has a number of different effects for showing and hiding content, so you could change the way the old posts are removed and the new posts are loaded; I’ll leave that up to you.
Creating the effect for ExpressionEngine
To create the same effect for ExpressionEngine would be very similar to the process for Wordpress. ExpressionEngine has an offset parameter too, so the javascript would be exactly the same. There would also be the same two templates: one for fetching posts and the other for displaying them. The only things that would be different would be the code used to retrieve the posts from the database.
Because you can have as many weblog entries tags in a template as you like, to count the number of entries to display would be a little more straightforward:
{exp:weblog:entries weblog="your_weblog" category="1|2" dynamic="off" disable="member_data|pagination|trackbacks"}
var ajaxcount = {count}
{/exp:weblog:entries}
You can have multiple categories by separating them with the | character.
You’d then use a similar weblog tag to display both the first post in the displaying posts template and the retrieving posts template with the only difference being the offset parameter for the latter (remember to enable PHP parsing for the template; it’s turned off by default):
{exp:weblog:entries weblog="your_weblog" limit="1" offset="<?php echo $_GET['offset']?>" category="1|2" dynamic="off" disable="member_data|pagination|trackbacks"}
Your content goes here.
{/exp:weblog:entries}
You could also possibly send the value of the offset as an additional URL segment and use offset="{segment_X}" instead which means you wouldn’t need to enable PHP for the template.
There’s probably ways that some of the above could’ve been accomplished differently, so if anyone’s done something similar but in a different way, I’d like to hear from you.








Thank you - a really useful post!
I am new to ajax but my learning goes ahead as per usual. I managed to make to work your animated image-links using jQuery (the one from your earlier tutorial), with it links menus look much better than with animated gif images. Ta.
nice post
I’m confused by two things here..
What do you name the first template file? How is it called? I don’t get it.
Also, can you please explain the very basics of where each of these parts of code should go within the wordpress template? i’m guessing by your example page that the script needs to go at the very bottom, maybe in the footer file, or just at the end of the index? you also don’t show what goes into the “ajax-content” div and what doesn’t… it’s just a little hard to piece together for a newbie, and it means i’ll be doing a bit of trial and error now figuring it out.
Thanks for the demonstration, I’m just confused about those basics. I guess including them would make a more complete tutorial for readers anyway.
Hi Steve,
It doesn’t matter as long as you have
/*
Template Name: XXX
*/
at the beginning of it so Wordpress knows it’s a template file.
You can put it anywhere on the page that you like but it’s generally considered for better performance that js should be at the bottom of the page.
Everything from the third code example in the article (ie that includes
while (have_posts()) : the_post();etc.) goes inside the ajax-content div because that’s the content that will be replaced by the script.hello, great tutorial- very handy. i don’t quite understand the significance of the:
while ($cat2->have_posts()) : $my_query2->the_post();these lines have something to do with inner Wordpress workings? is it possible to run two separate instances of your magic code within two (or more) loops. i almost have this working using your code, but not quite and wondered if you had any ideas.
ajaxcount doesn’t seem to produce anything other than ‘0’ for me.
i’m using multiple loops based on this how-to. they work great!
if you could explain the $cat code that would be a help… why doesn’t it read:
while ($cat2->have_posts()) : $cat2->the_post();seems to make more sense to me!
- Callum
Hi Callum, you’re quite right, it was a typo which I’ve now corrected. Thanks for pointing it out.
… and what if i wanted to offset 5 posts at a time?
what variable do I alter?
Thank you for writing this tutorial. It has given me a great start on AJAXing wordpress themes.
I’ve had lots of trouble though, which I thought I would share.
First, instead of loading the the first code snippet (‘Ajax example - retrieve posts’), when I click the jQuery enabled link, the post simply fades out, and nothing replaces it. I noticed that your jQuery seems to load the ‘Ajad example - retrive posts’ document without revealing where it is on your web server. The jQuery code: .load(‘/examples/ajax-handler/). Because of this, I’m not sure where to put the document on my own wordpress installation.
I managed to hardcode a url into the .load() function, like so: .load(‘wp-content/themes/uprising/ajax-handler.php?offset=’+offset). But that seems to be a problem, since the PHP document, once loaded, is outside of the wordpress system. So it chokes on query_posts(), with the error “undeclared function”.
To get around this, I added code to manually load wordpress, to the ajax-handler.php document:
define(‘WP_USE_THEMES’, false);
require(‘../../../wp-blog-header.php’);
But this only works once. So I can load a post by AJAX once, but the second time, it doesn’t work anymore (it goes to the category page, as if javascript were disabled).
So I reorganised so that the “ajax-link” button is now outside of the “ajax-content” div. Which has finally resulted in a functional system.
Anyway, I just thought I would share in case I made a fundamental error earlier on that would save a lot of the trouble I’ve gone through.
PS: one of the code snippets mistakenly says: $(‘.internal’).click(function(). In your working example, it says: $(‘.ajax-link’).click(function().
Hi Trevor, the pertinent part of the article that relates to your problem is this:
/examples/ajax-handler/ is actually a page I created within Wordpress, (i.e. by going to Pages > Add New) which the Ajax example - retrieve posts template is applied to.
Thanks for the heads-up about the typo.
Thank you for sharing this ! However, my implementation always display same two entries. Here’s my code:
have_posts()) : $cat1->the_post();$ajaxcount++;
endwhile;
?>
<a href="">
» »
Read more articles from this category
$(document).ready(function(){
var ajaxcount = ;
var offset = 1;
$('.ajax-link').click(function(){
$('#ajax-content *').fadeOut(500);
$('#ajax-content + p').fadeOut(500);
$('#ajax-content').load('http://localhost:8080/xampp/wordpress/?page_id=111/?offset='+offset);
$('#ajax-content + p').fadeIn(1);
offset++;
if (offset == ajaxcount) { offset = 0 };
return false;
});
});
Oops … I put in my prev comment code inside the <code> tags, but it came out strange … It didn’t display all …
Well, anyway, you probably have idea why the script is always displaying same first two post … ( my showpost is set to 2).
I cant’t post here my code, but I’ll be glad to mail it to you, if you’re willing to help me …
Thanks …
Alen, if you’re getting the same two posts each time it indicates that the offset isn’t working correctly. So check the javascript where the offset variable is created and make sure you’ve included
query_posts('showposts=1&cat=1,2&offset='.$_GET['offset']);in the post retrieval template.Oh I got it … It was the offset and it was the typo problem. Stupid, really …
But now … If you for example would want to display 3 posts at the time and you have total of, let’s say, 11 posts, the 12th post will not display … ? Or … ? I belive that the if (offset == ajaxcount) { offset = 0 }; part should look rather different. Am I right ?
Alen, the project I was working on when I originally developed this only required showing one post at a time and I didn’t take into account what would happen if you were displaying more than one at a time.
So, yes, you’re right, it’s not going to show the same number of posts at the end if the number of posts to display doesn’t divide equally into the number of posts that there are.
To get it to work in your situation, you’d probably have to modify the post-retrieval template to include some conditional logic that calculates the difference between the offset and the total number of posts and then divides that number by your number of posts to display. If the that final number is less than 1, you’d have to insert a second loop whose offset starts at 0 and displays the number of posts that weren’t displayed in the original loop.
Sorry, it’s me again. I won’t bother you anymore but I wanted to say I got the solution for problem in my previous comment and perhaps you can use it.
I changed:
to:offset++;
if (offset == ajaxcount) { offset = 0 };
… ( i need to display 4 posts…).offset+=4;
if (offset >= ajaxcount) { offset = 0 };
I suppose there is more subtle way to do this, perhaps to set php var for offset before the first loop (just a suggestion… )
Anyway, BIG THANKS !
How about if I want to go backwards? What is the JavaScript to offset negatively, and when you’re at the beginning the negative offset will go to the ajaxcount -1 (last post)? Basically it will go forward and backwards through all the posts. Can you please demonstrate? Any help would be very appreciated.
Hi Derek,
If you wanted your posts to go backwards, wouldn’t you just reverse the order of your query?
Nevermind, I created my own plugin for cycling through my query.
I don’t think you understood what I was asking. I want to go forward and backwards by clicking two different links. More like the previous and next posts link.
Don’t worry, I figured it out and made it unobtrusive and not rely on an arbitrary page to fetch content.
Thanks for the inspiration though.
hi again, this must be one of the most useful and straightforward tutorials i’ve ever found. thanks again, i’ve learned so much about jquery from this one little piece of code.
one thing i can’t get a hang of is how to insert a ‘loading…’ item into the list of commands. a mixture of .document.getElementById and CSS trickery will do it, where do I append my code to add this function?
you could do with a loader on your example (for atheistics) as the div changes size dramatically on load, for example.
*cough* typo: aesthetics. hah.
Just curious, did you try this approach, and get it to work, in Expression Engine?
It seems that ee doesn’t automatically parse the weblog tags when they are loaded via Ajax, so the approach above results in the tags themselves being outputted rather than the content.
NM, I had mistakenly added .php to the end of my template name URL. If you give it the template name instead of the file name it works great. Thanks for the tutorial!
First off - thanks a million for this code.
My problem: I’m not querying the_excerpt of posts, but am querying the_content. And if one post is shorter in length than the next one that loads up, the next one gets cut off (because the div doesn’t resize). I can’t quite understand why this would be - the div is fading out, loading new content, then fading back in - so it seems like it should know to resize! Any advice?
Hi Ryan, this sounds like it’s probably an issue with your CSS.
@Ryan You need to not set the height of the div and clear any floats you have in there, as well. It sounds like you told the div you wanted it to be XXpx in height and it is not resizing because of it.
Thanks guys. I also didn’t mention that I’m using jscrollpane on that page. I think I just need to add a bind event to it.
@ John & Derek:
I’m also interested to move forward and backward through posts.
I tried something with offset- , but I didn’t make it …
John, any idea how to solve that ?
Derek, could you share your solution with through posts ?
Thanks for any help !
@Alen
You can view source and see what I did on http://workawesome.com
Trying to share what I did in the comments of this posts would be a bit overwhelming. As well, the js and php is very different from what was done here. This post helped get the ball rolling but in the end I didn’t use this code at all.
I might write a post about it on my blog when I get some free time.
hi john, is it possible to use this code to fetch the post from local wordpress-site into a standard html site. All i’m looking for is, to display one post a time with side-bar having five posts displayed and also pagination. a live example is something like this. My site at the moment can be viewed from here.
kind regards,
venkat
Venkat, you wouldn’t be able to pull content from a Wordpress database and display in an HTML-only site; you’d at least have to be running PHP to be able to interact with the database and display the information. You also wouldn’t have access to the same WP functions mentioned in the article if you’re working outside of WP; you’d have to write your own functions to provide similar functionality.
You would not need to write your own functions, you would just need to include the WordPress blog headers like so:
include(‘../../../wp-blog-header.php’);
But your path may be different than mine so you need to test to make sure you have included the file by testing a WP function.
@john and derek, i’ve managed to pull recent post into my div on the site using php connecting to database. well, its a matter of a minute to change the .htm to .php with some scripting inside it. Am looking to add the side bar with all previous posts too.. i’ll forward a link soon, so you can have a look at what am looking to do!! please do have a look at it and let me know any availabilities..!! link to be attached soon in a minute or two in my next post!