WordPress: Load more posts on page scroll

Note: This article has been marked for a quality review and will soon be updated.

Although I don't visit archive pages very often, when I do I like it when I don't have to trawl through pages and pages of 10 posts using tiny navigation buttons at the bottom of the page. A great way to prevent this annoyance for your users is to use AJAX to dynamically append posts to the end of your archive list. To do this in WordPress we need to abstract the process of getting the list of posts and then use some Javascript (in out case jQuery aided) magic to load in our content. So lets get started.

First off we need to create a function that we can call to spit out a list of posts. Usually on an archive page we would use the normal WordPress loop to accomplish this, but in our case we need to abstract the loop into a separate function so that we can access it from any file - more specifically our Javascript file. We also need to be able to pass an offset value to this function to make sure we don't load the same posts every time it is called. This function is going to differ slightly depending on your markup for your archive page, but this is how it would look for Tom's Big Box:

function getArchives($count,$offset){
	query_posts('posts_per_page='.$count.'&offset='.$offset);
	
	$posts = array();

	if(have_posts()) : while(have_posts()) : the_post(); 	
		$img = post_image($post->ID);
		$commentsNo = get_comments_number();
		if($commentsNo==0){
			$comments = 'No Responses';
		}else if($commentsNo==1){
			$comments = '1 Response';
		}else {
			$comments = $commentsNo . ' Responses';
		}
		
		$item = '<li id="'. get_the_ID() .'">
			<figure class="vignette left">
				<img src="'. get_bloginfo('template_url') .'/scripts/timthumb.php?src='. $img->src .'&w=180&h=120" alt="'. $img->alt .'" />
			</figure>
			<h3><a href="'. get_permalink() .'">'. get_the_title() .'
			<p class="article-meta left">'. get_the_time('jS M Y',$post->ID) .' ~ '. $comments .'

<p class="extract"> '. get_the_excerpt() .' </p> </li>'; array_push($posts,$item); endwhile; endif; return $posts; }*/

Stick this in your functions.php file, and we can walk through what this code is doing. Firstly the two parameters that we it accepts are $count - which tells our functions how many posts we want, and $offset - to ensure that we don't load the same posts every time our function is called. We then send these parameters to WordPress's query_posts() function which will give us a list of posts. We then set up the $posts array to sold our data and begin iterating through the posts. I created a separate image variable to hold information about each post's image because I don't use WordPress's inbuilt image resizing, this is something which may not apply to you. After that an if statement creates a nice string based on the number of comments per post - this is because the inbuilt functions return only the number of comments or directly outputs to the document - something we don;t want. Then we load our content into the $item variable using whatever markup we need, and finally use array_push() to add our $item variable to the $posts variable, before returning the final $posts variable in its entirety.

Phew! Well that's most of the server-side stuff done, but before we can say goodbye to PHP, we need to do one more thing. We need to create a file to which we will pass our parameters, and that will execute the function we just created, and return the code we need. Don't worry, this is far simpler than the function above, let's take a look at the code:

require( '../../../../wp-load.php' );
$posts = getArchives(20,$_GET['offset'],false); 
foreach($posts as $p){
	echo str_replace("'","'",$p);
}

So, ignoring the first line for a moment, this file simply passes the $_GET['offset'] variable to our newly created function, and then iterates over the output, making sure to replace any single quotation marks to stop it from breaking. "But hang on Tom, what does that first line do?!" I hear you cry, well the first line makes sure we can access the function we just created, and for that matter all the inbuilt WordPress functions, so it is vital that you keep it. You will also need to change the path in the require() statement to ensure it matches the root directory of your WordPress install. Pop the above code in a file called get-posts.php and stick it in your theme's directory. And with that, we can say hasta la vista to PHP, and buongiorno to jQuery (that's right, I'm cultured).

Now, having made sure jQuery is included on your page, paste in the following code:

var halfWay = ($(document).height()/2);
var offset = 20;
var inAction = false;
var reachedEnd = false;

$(document).scroll(function(){
   if($(document).scrollTop() > halfWay && inAction == false){
       inAction = true;
		
       $('.article-list').append($('
').load('http://example.com/wp-content/themes/myTheme/get-posts.php?offset='+offset, function(){ offset = offset + 20; halfWay = halfWay + 1775; inAction = false; })); } });

Lets go through what this does. We have a function that fires whenever the page scrolls, and within that we compare the current scroll amount to half the overall document height, if it is greater (meaning that the user has scrolled more than half way down the page), and the variable inAction (I'll get to that in a moment) is true, it executes the following code. If the conditions are satisfied we then use AJAX to load in some more posts. Now it may appear a rather convoluted way to be doing so, but in my experience this way of handling an AJAX request of this type is the best. So for this method we send a request to our file that we just created in our theme's directory, and pass it the variable offset, when the content is loaded we run the embedded function which increments our offset variable by 20, adds a suitable amount to our halfWay variable. We then reset the inAction variable. This variable is used to prevent a massive build up of requests because of page scrolling, we use it because every time the page scrolls even a pixel, the function is called, so we don't want it to be called 3 times before we have a chance to offset the next post, otherwise we will end up with a huge amount of duplicate posts being loaded in. The conditions in the if statement will stop being satisfied after the last posts are loaded in because our inAction will stay in it's true state forever after one request for no posts means the success() function isn't executed.

And that's it! It might be a good idea to have a loading graphic at the bottom of you page when doing this to give some user feedback, and I would suggest also adding pagination just incase your server stops responding and leaves your users hanging. But aside from that, I think I covered the basics of how to implement the AJAx loading in of content. Oh and by the way, you will now also be able to generate archives anywhere on your site using the function getArchives(), meaning you will write less code in the long run - two birds with one stone!