Index Pagination & Adjacent Post Navigation

The Settings admin screens are among the first, on a fresh WordPress install, that a user will visit before they open their site’s doors up to the public. In the Settings > Reading screen, the user is able to adjust the “Blog pages show at most” option. Defaulting to 10 posts per page, its left as an exercise for the theme designer to implement the actual, front-facing paging links.

From the index listing page of your theme, you’ll need to navigate to the set of posts available. i.e., from posts page #1 to posts page #2. In addition, because its great UX, its worth giving a thought to post-to-post navigation (adjacent post navigation). That is, from any given entry, a user should be able to navigate to the immediately adjacent posts on either side (if chronologically ordered, previous post or earlier post).

Unless you’re implementing infinite scroll or something similar (and even then), your default blog/index view will need to be paginated.

Defining the function

If you’ve been theming for a while, you’re probably used to manually defining the <?php next_posts_link(); ?> and <?php previous_posts_link(); ?> directly in your theme’s index template. Its not at all wrong to do this, just inefficient. It makes much more sense to DRY up your template code and define this functionality in the functions.php. This way, as your specific theme grows to include more templates, you’re simply using a once-defined function and adjusting it accordingly.

For the average index view, you’ll want a function that does a few things:

  1. Doesn’t output anything if there’s only one page of posts
  2. Appends a CSS class to the parent element (e.g. <ul>) if one is defined. Otherwise defaults to a set CSS class.
  3. In addition, because its good practice, you’ll want to make this function pluggable. i.e. overwrittable from a child themes.

To accomplish the above, in the functions.php we define an index paging function like this:

// make function pluggable
if ( ! function_exists( 'butter_index_paging' ) ) :

// define the actual function AND set a default
// $index_paging_class value (our default CSS class)
function butter_index_paging($index_paging_class = “default-paging-css-class") {
  
  // make sure there's more than 1 index page otherwise show nothing
  if ( $GLOBALS['wp_query']->max_num_pages < 2 ) {
    return;
  }
  
  // if there's more than 1 page print out the pagination links
  <ul class="<?php echo $index_paging_class; ?>">
  <?php if ( get_next_posts_link() ) : ?>
    <li class="nav-previous">
     <?php next_posts_link( __( '← Older Entries', 'butter' ) ); ?>
    </li>
  <?php endif; ?>
  
  <?php if ( get_previous_posts_link() ) : ?>
    <li class="nav-next">
      <?php previous_posts_link( __( 'Newer Entries →', '_s' ) ); ?>
    </li>
  <?php endif; ?>
  </ul>
  
  <?php
}
endif;

Notice that even though we’re running a check to see if, indeed, we should output our navigation links altogether, we’re still checking to see that we actually have next and previous posts and deciding whether or not to output those individually by wrapping our links in <?php if ( get_next_posts_link() ) : ?> and <?php if ( get_previous_posts_link() ) : ?> respectively.

Using the Function

To output the previous and next posts links, in your index.php template, or wherever you output the pagination, you’d then call:

<?php butter_index_paging(); ?>

from within the index loop. Given a standard loop, you’d have something like this:

<?php if ( have_posts() ) : ?>

  <?php while ( have_posts() ) : the_post(); ?>

    <?php get_template_part( 'content', get_post_format() ); ?>

  <?php endwhile; ?>

  <?php butter_index_paging(); ?>

<?php else : ?>

  <?php get_template_part( 'content', 'none' ); ?>

<?php endif; ?>

As defined in the functions.php, this will output an unordered list of next/previous posts links. The <ul> element will have a class of “default-paging-css-class“. To give the element a different class, e.g. “im-in-a-new-class”, simply do this:

<?php butter_index_paging('im-in-a-new-class'); ?>

Adjacent Posts (get_adjacent_post)

Within your single post entries, you’ll want to afford the user the same ability to page back and forth through adjacent posts.

Again, as with the index pagination, you could “manually” use <?php previous_post_link(); ?> and <?php next_post_link(); ?> directly in your single posts’ templates to output the relevant links, however, defining a function for this gives you infinitely more flexibility.

For adjacent post navigation, you want to make sure that there is, indeed, a previous or next post before you output the markup. To that end, we define a function like this:

// make the function pluggable
if ( ! function_exists( 'butter_adjacent_post_nav' ) ) :

function butter_adjacent_post_nav() {
  
  // define the variables for use in the function
  $previous = get_adjacent_post( false, '', true );
  $next     = get_adjacent_post( false, '', false );
  
  // confirm that an adjacent post (previous or next) actually exists. otherwise do nothing
  if ( ! $next && ! $previous ) {
    return;
  }
  ?>
  
  // if an adjacent post is present, output the following markup
  <nav class="adjacent-post-nav">
  <?php
  previous_post_link( '%link', __( 'Previous Post: %title', 'butter' ) );
  next_post_link( '%link', __( 'Next Post: %title', 'butter' ) );
  ?>
  </nav>
  <?php
}
endif;

To use the adjacent post navigation defined above, from within e.g. the single.php loop, make a call for the function like so:

<?php butter_adjacent_post_nav(); ?>