How to implement Jetpack’s Infinite Scroll on your blog

So, you like how Facebook, Twitter, and other sites don’t break their content into pages. You’ve researched the technique and found out it’s elegantly named “infinite scroll”. Hopefully you did some reading and weighted the pros and cons for your own use-case. Finally, you decided that you want it on your WordPress blog. Of course, there are infinite solutions out there that will get your job done, but probably the easiest one is the one that Jetpack bundles. There are good chances that you theme already supports Jetpack’s Infinite Scroll, but you wouldn’t be reading this if it did, would you?

Jetpack’s documentation of its Infinite Scroll feature is pretty good explaining the feature’s parameters, but actually implementing it is a bit more tricky, depending on the theme you use. That’s why we’ll work on a real world scenario, grabbing a copy of our free Brittany Light theme, and adding infinite scrolling to it. Once you install the theme, create a child theme and activate it, as we don’t want to lose our changes when the next theme update is released. Now we are ready.

Enabling Infinite Scroll

First things first. Enabling infinite scroll requires a) declaring theme support, and b) setting a few parameters right. Since the theme doesn’t declare support just yet, what you’ll be seeing in Jetpack → Settings is this:

Fire up your favorite editor or IDE, open your child theme’s functions.php file and add the following:

add_action( 'after_setup_theme', 'my_child_setup' );
function my_child_setup() {
	add_theme_support( 'infinite-scroll' );
}

We just declared that our theme supports Infinite Scroll. This is enough to enable the feature, even though it won’t be working just yet. If you refresh the Jetpack’s settings page now, you should see:

For now, select “Load more posts in page with a button” and then press the “Save Settings” button on the top right. This is so that Infinite Scroll will not try to load posts automatically while we implement the feature.

If you now take a look at the blog page, right after the normal pagination (assuming you have enough posts, that is) you should see the “Older posts” button. Pressing it will do nothing, except momentarily show a loading spinner.

But wait. Shouldn’t the normal pagination be hidden? Well, yeah, it’s our job though. Infinite Scroll adds an .infinite-scroll class on the body element when it’s enabled, so we can simply add the following on our child theme’s style.css file:

.infinite-scroll .pagination {
	display: none;
}

Now pagination will be visible only when infinite scroll is disabled (either by removing theme support, or by selecting “Load more posts using the default theme behavior” in settings).

Setting a correct container

Infinite Scroll needs to know where in the page it should append the articles it fetches dynamically. You can do that by declaring the ID attribute of an element that contains the posts. Let’s take a look at the index.php file of Brittany Light:

<?php get_header(); ?>

<main class="main">
	<div class="container">
		<div class="row">
			<div class="col-md-8">
				<?php if ( is_archive() ): ?>
					<h2 class="section-title"><?php the_archive_title(); ?></h2>
				<?php endif; ?>

				<?php while ( have_posts() ): the_post(); ?>
					<?php get_template_part( 'item', get_post_type() ); ?>
				<?php endwhile; ?>

				<?php ci_theme_posts_pagination(); ?>
			</div>

			<div class="col-md-4">
				<?php get_sidebar(); ?>
			</div>

			<?php get_template_part( 'part-prefooter' ); ?>
		</div>
	</div>
</main>

<?php get_footer(); ?>

We can see that the loop lives inside the div.col-md-8 that opens on line 6. It doesn’t have an ID attribute however, so we can’t pass it to Infinite Scroll. Don’t try to think of clever solutions and hacks and workarounds. The solution is very simple. Copy index.php into the child theme, and add an ID to the element we need:

...

<div id="content" class="col-md-8">

...

Now we can tell Infinite Scroll about it via the ‘container‘ argument:

add_action( 'after_setup_theme', 'my_child_setup' );
function my_child_setup() {
	add_theme_support( 'infinite-scroll', array(
		'container' => 'content',
	) );
}

I’ve purposely added the ID as “content“, because it a) makes sense, and b) it’s the default the Infinite Scroll uses. So, we just pass an associative array of arguments, as the second argument of add_theme_support(). Since content is the default value for container, we could have left it out. We’ll explicitly pass it however, for completeness.

Infinite scrolling still won’t work on our theme though. While it knows where it should display posts, it doesn’t know how to display them.

Displaying posts

If you are familiar with The Loop, you already know that its main purpose is to display the posts. Usually, to keep the code inside the loop organized, theme authors refactor the code needed to display a single post inside a template part, so the loop continuously reads that template part to display each post. Infinite scroll assumes that the aforementioned code lives in a template part named content.php and tries to use that. In our case though, from the code taken from index.php above, we can see that Brittany Light uses a file named item.php instead, therefore the default won’t work. Of course you could make a copy of item.php as content.php, but what good would it do for the purposes of our tutorial?

In order to define a custom loop that infinite scroll will use, we can create a function that will hold this custom loop, and point infinite scroll to it via the ‘render‘ argument:

add_action( 'after_setup_theme', 'my_child_setup' );
function my_child_setup() {
	add_theme_support( 'infinite-scroll', array(
		'container'      => 'content',
		'render'         => 'my_child_infinite_scroll_render',
	) );
}

function my_child_infinite_scroll_render() {
	while ( have_posts() ) {
		the_post();
		get_template_part( 'item', get_post_type() );
	}
}

In this case, the my_child_infinite_scroll_render() function simply contains a loop and a get_template_part() call, but it could be as complex as needed.

Go ahead an check your blog now. Push the “Older Posts” button. It should work!

Showing a consistent number of posts

For some reason, the Jetpack’s developers decided that when infinite scroll is set to show the “Older Posts” button, the number of posts defined in Settings → Reading is followed, but when posts load just by scrolling, the number of posts loaded is seven (7). Why? I don’t know ‘s but it seems arbitrary. Anyhow, if you need to set a specific number for whatever reason, especially if your blog shows posts in columns, the you can use the ‘posts_per_page‘ argument. For example, in order to load just 3 posts (small number, I know, but it’s useful during development so you don’t need a large number of test posts):

add_action( 'after_setup_theme', 'my_child_setup' );
function my_child_setup() {
	add_theme_support( 'infinite-scroll', array(
		'container'      => 'content',
		'render'         => 'my_child_infinite_scroll_render',
		'posts_per_page' => 3,
	) );
}

Test it out! You may see a discrepancy between the number of posts shown when the page loads and the posts loaded dynamically, but that’s to be expected. The infinite scroll setting affects only the number of posts is fetching itself. If you always want a consistent number, you can have infinite scroll obey the Settings → Reading option by doing this:

add_action( 'after_setup_theme', 'my_child_setup' );
function my_child_setup() {
	add_theme_support( 'infinite-scroll', array(
		'container'      => 'content',
		'render'         => 'my_child_infinite_scroll_render',
		'posts_per_page' => get_option( 'posts_per_page' ),
	) );
}

Now it’s a good time to change the behavior from displaying the button, to “” in Jetpack → Settings which is what we really wanted from the start. The reason we worked with the button up until now is that you can’t really test the number of posts loaded if more posts keep appearing while you scroll, don’t you think?

Other configuration options

At this point, we got Infinite Scroll to work on our blog and we can stop. It does accept a few more configuration options though, that you may or may not need, depending on your use-case. While we don’t need them for this tutorial, I’ll just mention them for completeness.

  • type – Set the method of loading to ‘scroll‘ or ‘click‘. Overrides the user’s selection from Jetpack → Settings.
  • wrapper – Enable/disable/configure wrapping of new posts in a div. Enabled by default.
  • footer_widgets – Determine if there are footer widgets to show. If there are, type is set to ‘click‘ so that users have a chance of seeing the widgets.
  • footer – Enable/disable/configure the footer that Infinite Scroll adds.

For more information about these options, you should consult with the Infinite Scroll documentation.

Conclusion

Adding Infinite Scroll to our blog is a great way to increase engagement. Jetpack makes it easy to implement it in our theme, by writing only a few lines of code. Case in point, the complete code of our tutorial is just 15 lines:

add_action( 'after_setup_theme', 'my_child_setup' );
function my_child_setup() {
	add_theme_support( 'infinite-scroll', array(
		'container'      => 'content',
		'render'         => 'my_child_infinite_scroll_render',
		'posts_per_page' => get_option( 'posts_per_page' ),
	) );
}

function my_child_infinite_scroll_render() {
	while ( have_posts() ) {
		the_post();
		get_template_part( 'item', get_post_type() );
	}
}

Have fun infinitizing your blog!

6 comments

  1. Lim says:

    The problem is that I want to load only posts in the same category for infinite scroll. How do I do this?

    1. Anastis Sourgoutsidis says:

      Infinite Scroll will use your existing environment to display the appropriate posts.
      On the “blog”, all posts will appear, in chronological order. If you are on a category’s listing page, then posts from a specific category will appear. Similarly with a tag’s listing page.

      So, it really depends on what exactly you want to do, and ignore Infinite Scroll. Do you want to show on posts from specific categories on your Blog listing? It’s a matter of hooking to pre_get_posts.

      Infinite Scroll will work with the posts that are brought back.

  2. Jane Atieno says:

    I am kind of lost here: Copy index.php into the child theme, and add an ID to the element we need:

    How do I change my class div.col-md9 to div#content in the index.php into the child theme? I am stuck there.

    In my case it should be:

    1. Nik Vourvachis says:

      Hello Jane.

      Assuming you have a

      <div class="col-md-9">

      in your index.php file.

      Copy over the index.php file to the child theme’s folder and modify the line above to:

      <div id="content" class="col-md-8">

      that should do the trick.

  3. Wilfried says:

    I have a loop that resides in a template called testing. So do I still have to use this line of code?

    get_template_part( ‘item’, get_post_type() );

    and just replace item with testing?

    1. Anastis Sourgoutsidis says:

      No. The template that holds the loop, testing.php in your case, or index.php/archive.php/etc more commonly, is the file that needs to have the correct HTML container, the div with the id=”content” in the case of the tutorial.
      The get_template_part() line should call whatever template file is responsible for displaying a single post/item, i.e. what is displayed inside the loop.

Leave a Reply

Your email address will not be published. Required fields are marked *