How to add post navigation for a blog post – the better way

The advantage of WordPress is, there are multiple ways to build a particular piece of data.

We don’t have to code anything by ourselves. All we have to do is use existing WordPress functions to achieve the desired outcome.

Introducing get_adjacent_post()

The get_adjacent_post() function is used to retrieve the adjacent post of the current single blog post. You can either retrieve a previous post or next post. But only one post at a time.

This function accepts four parameters.


get_adjacent_post( $in_same_term, $excluded_terms, $previous, $taxonomy );

All the above four parameters are optional. By default, this function returns the previous post of the current post even if you call this function without any parameters.

1) $in_same_term : ( boolean ): ( Default False ):  As the parameter name suggests, if we provide True for this parameter, the function will pull the adjacent post which belongs to the same term as the current blog post.

In WordPress, a term would belong to one of the following taxonomies:

  • Category
  • Tag
  • Or Custom Taxonomy like Book Genre

Also, If you specify true for this parameter, we should also specify the taxonomy as the last parameter. For example,


get_adjacent_post( true, '', false, 'tag' );

For example, If the current post is assigned to “Friendship” tag, in the above line of code, we are instructing get_adjacent_post() function to pull the next adjacent post which is assigned to “friendship”  tag only.

2) $exclude_terms : ( array or string ):  As the parameter name suggests, using this parameter, you can skip the adjacent post which belongs to a particular term.


get_adjacent_post( 'true', 'respect', false, 'tag' );

For example, If the current post is assigned to “Friendship” tag, in the above line of code, we are instructing get_adjacent_post() function to pull the next adjacent post which is assigned to “friendship” tag. But, if the next adjacent post is assigned with ‘respect’ tag also, the post will be skipped even if it is assigned to the “friendship” tag.

3) $previous_post : ( boolean ): ( Default True )  If we set this parameter to False, this function will retrieve the next post of the current post. Otherwise, the previous post is retrieved.

You already know about the fourth parameter!

The  get_adjacent_post() function returns a WP_Post object.

A WP_Post object contains all the information about a particular post. For example, Post title, Post ID and even the Post content.

object(WP_Post)#1217 (24) { 
    ["ID"]=> int(633)
    ["post_author"]=> string(1) "1" 
    ["post_date"]=> string(19) "2019-04-16 06:17:01" 
    ["post_date_gmt"]=> string(19) "2019-04-16 06:17:01" 
    ["post_content"]=> string(5250) "..."
}

Note: This is a standard PHP object. If you are not familiar with object-oriented concepts of PHP, you better learn it. Although it is not mandatory, it helps you master WordPress.

Anyway, always remember, If some WordPress function returns a WP_Post object, using this object, you can literally pull out and output any piece of information about a particular post.

“How?”

If you notice the above WP_Post object data, the first property in the object is the ID of the post. And, The most vital information we ever need about a particular post is its ID. There are a ton of WordPress functions which outputs specific pieces of information about a particular post when you provide them the ID of the post. So, it is powerful and we are about to experience the technique.

The Setup

First, open up the functions.php file and put the following definition at the end of the file:


/*
 * Outputs the post's thumbnail and title when ID of the post is provided
 */
function nd_dosth_output_post_thumb_and_title( $post_id ){ ?>
    <div class="post-info">
        <?php // Output Post's Thumbnail ?>
        <?php $page_thumb = wp_get_attachment_image_src( get_post_thumbnail_id( $post_id ), 'thumbnail' ); ?>
        <?php if( ! empty( $page_thumb[0] ) ) : ?>
            <a href="<?php echo get_the_permalink( $post_id ); ?>" class="post-thumb">
                <img src="<?php echo $page_thumb[0]; ?>" />
            </a>
        <?php endif; ?>
        <?php // Output Previous page Title ?>
        <a class="post-title" href="<?php echo get_the_permalink( $post_id ); ?>">
            <?php echo get_the_title( $post_id ); ?>
        </a>
    </div>    
<?php }

Note: If you define a function inside the functions.php file, you can call it anywhere inside your theme’s template files. 

Next, create a new file called post-navigation.php inside the parts directory of our theme.

nd-dosth/parts/post-navigation.php

Next, put the following code inside the post-navigation.php file.


<?php
    //Getting Next Adjacent Post
    $next_post      = get_adjacent_post( false, '', false, 'category' );
    
    //Getting Previous Adjacent Post
    $previous_post  = get_adjacent_post();
?>
<div class="next-previous-articles">
    <?php if ( ! empty( $previous_post ) ) : ?>
        <div class="previous-article">
            <h4><?php _e( 'Previous Article','nd_dosth' ); ?></h4>
            <?php nd_dosth_output_post_thumb_and_title( $previous_post->ID ) ?>  
        </div>
    <?php endif; ?>
    <?php if ( ! empty( $next_post ) ) : ?>
        <div class="next-article">
            <h4><?php _e( 'Next Article','nd_dosth' ); ?></h4>
            <?php nd_dosth_output_post_thumb_and_title( $next_post->ID ) ?>    
        </div>
    <?php endif; ?>
</div>

Next, replace the_post_navigation() code from the single.php file that we have added previously with the following line of code:


<?php get_template_part( 'parts/post', 'navigation' ); ?>

Here is the update code for single.php file:


<?php
/**
 * The template for displaying all single posts
 *
 * @link https://developer.wordpress.org/themes/basics/template-hierarchy/#single-post
 *
 * @package Dosth
 */
get_header();
?>
<div class="content-container">
    <?php while( have_posts() ): ?>
        <?php the_post(); ?>
        <?php if ( has_post_thumbnail() ) :
            $featured_image = wp_get_attachment_image_src( get_post_thumbnail_id( get_the_ID() ), 'full' ); ?>
            <div class="full-width-featured-image" style="background-image:url(<?php echo $featured_image[0]; ?>);">
                <h1><?php the_title(); ?></h1>
            </div>
        <?php endif; ?>
        <div class="container">
            <div class="row">
                <div class="article-info col-md-3">
                    <?php $categories = get_the_category(); ?>
                    <?php if ( ! empty( $categories ) ) : ?>
                        <div class="posted-in">
                            <h4><?php _e( 'Posted In', 'nd_dosth' ); ?></h4>
                            <?php the_category(); ?>
                        </div>
                    <?php endif; ?>
                    <div class="published-on">
                        <h4><?php _e( 'Published On', 'nd_dosth' ); ?></h4>
                        <?php the_date(); ?>
                    </div>
                    <div class="post-author">
                        <h4><?php _e( 'Author', 'nd_dosth' ); ?></h4>
                        <a class="author-archive" href="<?php echo esc_url( get_author_posts_url( get_the_author_meta( 'ID' ) ) ); ?>">
                            <?php the_author(); ?>
                        </a>
                        <?php echo get_avatar( get_the_author_meta('ID')  , 100 ); ?>
                    </div>
                </div>
                <div id="actual-article" class="col-md-8">
                    <?php the_content(); ?>
                    <?php get_template_part( 'parts/post', 'navigation' ); ?>
                    <?php comments_template(); ?>
                </div>
            </div>
        </div>
    <?php endwhile; ?>
</div>
<?php get_footer(); ?>

Here is the output of in the browser:

Let’s break it down

Don’t worry, nothing complex going on in the above code.

When WordPress starts processing the single.php file, after executing the_content() function, it comes across:


<?php get_template_part( 'parts/post', 'navigation' ); ?>

And starts processing the post-navigation.php template file located inside the nd-dosth/parts directory.

The post-navigation.php template file is responsible for outputting the next and previous posts section.


<?php
    //Getting Next Adjacent Post
    $next_post      = get_adjacent_post( false, '', false, 'category' );
    
    //Getting Previous Adjacent Post
    $previous_post  = get_adjacent_post();
?<

Inside this file, the first thing we are doing is getting the next adjacent post of the current post with the help of:

$next_post = get_adjacent_post( false, '', false, 'category' );

We are retrieving the next post irrespective of taxonomy based filter by setting the first parameter to false. 

And, by setting the third parameter to false, we are instructing get_adjacent_post() function to return the next post instead of the previous post.

Then, we are getting the previous post with the help of:


$previous_post  = get_adjacent_post();

We did not provide any parameters because this function returns the previous post by default.

<div class="next-previous-articles">
    <?php if ( ! empty( $previous_post ) ) : ?>
        <div class="previous-article">
            <h4><?php _e( 'Previous Article','nd_dosth' ); ?></h4>
            <?php nd_dosth_output_post_thumb_and_title( $previous_post->ID ); ?>  
        </div>
    <?php endif; ?>

    <?php if ( ! empty( $next_post ) ) : ?>
        <div class="next-article">
            <h4><?php _e( 'Next Article','nd_dosth' ); ?></h4>
            <?php nd_dosth_output_post_thumb_and_title( $next_post->ID ); ?>    
        </div>
    <?php endif; ?>
</div>

Next, If it is the first blog post of our site, the get_adjacent_post() function will not return any previous post, so, $previous_post variable will be empty.

So, We are checking for this situation and outputting the previous post based markup only if there is a previous post.

Finally, inside the IF condition, we are outputting the previous post’s thumbnail and title with the help of:

nd_dosth_output_post_thumb_and_title( $previous_post->ID );

This is a custom function we have created inside the functions.php file. 

This function accepts a $post_id as the parameter and the only responsibility of this function is to output a particular blog post’s title and thumbnail based on the $post_id provided. And the code inside this function is nothing new to you all.

/*
 * Outputs the post's thumbnail and title when ID of the post is provided
 */
function nd_dosth_output_post_thumb_and_title( $post_id ){ ?>
    <div class="post-info">
        <?php // Output Post's Thumbnail ?>
        <?php $page_thumb = wp_get_attachment_image_src( get_post_thumbnail_id( $post_id ), 'thumbnail' ); ?>
        <?php if( ! empty( $page_thumb[0] ) ) : ?>
            <a href="<?php echo get_the_permalink( $post_id ); ?>" class="post-thumb">
                <img src="<?php echo $page_thumb[0]; ?>" />
            </a>
        <?php endif; ?>
        <?php // Output Previous page Title ?>
        <a class="post-title" href="<?php echo get_the_permalink( $post_id ); ?>">
            <?php echo get_the_title( $post_id ); ?>
        </a>
    </div>    
<?php }

If we observe the code of this function, this function is using the ID of a blog post to output its title and thumb.

Since we are interested in outputting the previous post’s thumbnail and title, we have provided the ID of the previous post for this function, like this:

nd_dosth_output_post_thumb_and_title( $previous_post->ID );

Remember? in this lesson, I have said that get_adjacent_post() function returns a WP_Post object.

Because $previous_post variable now holds the WP_Post object of the previous post, we are accessing the ID like this:

$previous_post->ID

If you want to access the previous post’s title, all you have to do is access the 

$previous_post->post_title

Anyway, that’s pretty much how we are outputting the Previous Post’s thumbnail and title.

Next, we are doing the same for the Next post as well. Only this time, we are providing the ID of the next post, like this:

nd_dosth_output_post_thumb_and_title( $next_post->ID );

Easy enough?

The key takeaway here is if you define a function inside the functions.php file, you can call it anywhere inside your theme’s template files. 

Let’s style it

Go ahead and put the following CSS at the end of the style.css file:


#respond #reply-title{
    margin-top:0;
}
.single #actual-article{
    /* Issue fix */
    padding-left:15px;
    padding-right:15px;
}
/*-------------------------------------------------------------------------------
  18.Post Navigation Styling
-------------------------------------------------------------------------------*/
.next-previous-articles{
    overflow: hidden;
    border-top:1px solid #000;
    margin-top:40px;
}
.next-previous-articles > div{
    width:50%;
    float:left;
    padding-top:15px;
    padding-bottom:25px;
}
.previous-article, .next-article{
    display:block;
    font-size:20px;
}
.previous-article{
    color: #fdb813;
}
.next-article{
    color: #1a3794;
}
.previous-article{
    padding-right:15px;
    border-right:1px solid #ccc;
}
.next-article{
    padding-left:15px;
}
.next-previous-articles a{
    display:block;
}
.next-previous-articles .post-thumb{
    width:75px;
    float:left;
}
.next-previous-articles .post-title{
    font-size:16px;
    margin-left:95px;
    margin-top:15px;
    color:black;
}
@media only screen and (max-width:767px){
    .next-previous-articles > div{
        width:100%;
    }
    .previous-article{
        padding-left:15px;
        border-right:0;
    }
}

Here is the updated styles outline of the style.css file:

And here is the style output of the post navigation in the browser:

And that’s it. Although I have missed a few things here and there, this is pretty much how you build template files for the WordPress blog.

In other words, we are done with the blog!