Fetching posts in Wordpress and ExpressionEngine with jQuery and AJAX

By John Faulds

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:

  1. 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.
  2. 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 &raquo;</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:

  1. 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 offset parameter.

    <?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_query is used because you cannot use the global have_posts() and the_post() since they both use $wp_query. Instead, call into your new $my_query object.

    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.

  2. 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 &raquo;</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_posts function 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.

  3. 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 the offset which is set to 1 for the first instance. Each time the link is clicked, the offset variable 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 false is used to prevent the browser redirecting to the link destination. The first actions in the function are to fade out the current content of the div holding 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 load function 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.

Update (24 March 2013): A couple of people have made comments suggesting they're having trouble understanding how the templates are put together, so I've uploaded the actual templates I used when this site used to run on Wordpress.

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.