Content:
You’ll often see websites display related blog posts underneath the post content.
There’s no built-in functionality to do this, but you can add this functionality to your theme using a custom query. This query will reside in the theme functions.php
file – this file acts as the heart of the theme, defining the functionality it provides.
This guide will show you how to fetch your posts, and display them on your site.
Creating the Custom Function
Start by creating a new function in functions.php
. The query code will reside in this function. It’s advised to give it a name relating to your theme, to ensure there’s no conflict with any built-in or plugin related functions.
function qb_related_posts() {}
Creating the Query
WordPress provides a function to create a custom query. This will allow you to pull out specific content, based on the parameters provided. This function is called WP_Query()
, and can be called as follows
$related_query = new WP_Query();
It supports a variety of parameters, which can be passed as an array. There are a few parameters that we’ll need to use, to get the posts we want. If you want to look at the full range of parameters, you can find more information over on the WordPress developer reference site.
The following example will get all posts in the same category as the post we’re currently viewing.
$related_args = array(
'post_type' => 'post',
'posts_per_page' => -1,
'post_status' => 'publish',
'post__not_in' => array(get_the_ID()),
'orderby' => 'rand',
'category__in' => wp_get_post_categories(get_the_ID())
);
The parameters should be pretty self-explanatory, but let’s go through them to be sure.
post_type
: The type of post to be returned, eitherpost
orpage
.posts_per_page
: If you’re using pagination, set this to a proper value. If you want all posts without pagination, set to -1.post_status
: Status of the posts to retrieve.post__not_in
: ID number(s) of posts you want to exclude. In this example, we exclude the ID of the current post, as we don’t want the post we’re on showing as a related post. Note the double underscore in the property name.orderby
: Order of the returned results.rand
will randomise the order.category_in
: ID of the category to fetch posts from. We usewp_get_post_categories()
to return an array of category ID’s attached to the current post.
If your posts are found in multiple categories, you might want to find posts which are in the same set of categories as the current post. To do this, you can replace category_in
with category__and
.
'category__and' => wp_get_post_categories(get_the_ID())
category__and
will work fine with posts that only have one category assigned.
Fetching Posts from the Query
In order to grab the post data from the result, you’ll need to
First, check whether there are any results from the query, using have_posts()
.
if (!$related->have_posts()) {
return false;
}
Returning false in the case where there are no results will make it easier to handle later on.
Next, create an array to hold the post data to return.
$post_array = array();
Now we can loop through the posts that the query has returned. Calling the_post()
inside the while loop will load the post data into the global $post
variable.
while ($related->have_posts()) {
$related->the_post();
// Do things with the post data
}
It’s then possible to get data from the post in the same way you would, for example, in single.php
to display a single post.
Create an array to store data for this post – you’ll need to decide what data you’ll need, depending on what you want to display in your related posts section.
while ($related->have_posts()) {
$related->the_post();
$post = array(
'title' => get_the_title(),
'slug' => get_page_link()
);
$post_list[] = $post;
}
In this example, we’re fetching the post title, and the page link. The single post is then added to the post_list
.
Resetting the Original Post Data
There’s one more thing that needs to be added to ensure the code will function as intended.
When you use the_post()
to loop through the WP_Query()
result, the global $post
value is replaced with the post in the loop. This is why functions such as get_the_title()
can be called without referencing a post – they use the $post
global by default.
However, this means that any additional code run on the page, following this ‘related post’ code, will run on the last post in our query. This is because this post will be the one that’s now stored as the $post
global.
In order to restore the original $post
value, add a call to wp_reset_postdata()
. Put this just before the return statement.
wp_reset_postdata();
return $post_list;
The full code for this section is shown below.
$post_list = array();
while ($related->have_posts()) {
$related->the_post();
$post = array(
'title' => get_the_title(),
'slug' => get_page_link()
);
$post_list = $post;
}
wp_reset_postdata();
return $post_list;
Limiting the Number of Returned Posts
Unfortunately, WP_Query() doesn’t have a built-in way of returning a specific number of posts. Fortunately, it’s possible to filter the posts manually to get the number you want.
Before the while loop where we go through the post result, we can create a variable to keep track of the number of posts we’ve processed.
$count = 0;
Next, add a check to see if we’ve reached the post limit. There’s also the case to handle where the post limit is -1, which we set as the default.
while ($related->have_posts() && ($limit === -1 || $count < $limit)) {
// Processing code
At the bottom of the while loop, increment the counter.
$count++;
Full functions.php Code
If you’re looking for the full code added to functions.php, you can find it below.
function qb_related_posts(int $limit = -1) {
$related_args = array(
'post_type' => 'post',
'posts_per_page' => -1,
'post_status' => 'publish',
'post__not_in' => array(get_the_ID()),
'orderby' => 'rand',
'category__in' => wp_get_post_categories(get_the_ID())
);
$related = new WP_Query($related_args);
if (!$related->have_posts()) {
return false;
}
$post_list = array();
$count = 0;
while ($related->have_posts() && ($limit === -1 || $count < $limit)) {
$related->the_post();
$post = array(
'title' => get_the_title(),
'slug' => get_page_link(),
);
$post_list[] = $post;
$count++;
}
wp_reset_postdata();
return $post_list;
}
Displaying Posts on the Front End
The backend function is complete, but you still need to call the function in one of your front end templates to show the posts.
The data from the related posts function is an array, so you can loop through it to extract and show the data.
Below is an example of how to do this:
if ($qb_related_posts = qb_related_posts(3)): ?>
<aside>
<h3>Related Posts:</h3>
<section id="related">
<?php foreach ($qb_related_posts as $qb_post): ?>
<a href="<?= $qb_post['slug'] ?>">
<p><?= $qb_post['title'] ?></p>
</a>
<?php endforeach; ?>
</section>
</aside>
<?php endif; ?>
This code will get data for 3 related posts, and output their titles as links to the post.