Displaying post order number in archives
Let’s say you have taken over a website for a podcast. Each time a episode of this podcast is produced, a WordPress post is published that provides information about that episode. There are over 500 episodes to date.
You’ve been tasked with displaying the podcast episode number in the podcast archives, and you’d rather not manually add custom meta for each of the 500+ episodes.
We’ll show you how to:
- Get the total count of published posts in a certain post type.
- Count backwards as you iterate through the WordPress loop.
- Adjust the episode number accordingly through paged archives.
- BONUS: Make it work with Jetpack Infinite Scroll too.
This is the exact same effect I use on the Themetry website to give visitors a visual idea of what number tutorial they’re on in the index.
Let’s begin!
Getting started
To follow along, you’ll need the following:
- A WordPress site, preferably a locally hosted one
- A custom post type with the slug of ‘podcast’ with has_archive set to true
- A bunch of posts and podcasts saved in various post statuses (mostly ‘publish’)
- The Jetpack plugin for Infinite Scroll, Development Mode can be turned on
A deep-dive into wp_count_posts
Say hello to the wp_count_posts function.
With it, we can glean all sorts of information about the total number of posts of a certain post type.
Get total count of all posts, regardless of post status
$post_count = wp_count_posts();
echo "<p>Total number of posts (all post statuses): $post_count</p>";
This won’t be of use to us, because we want to count the ‘podcast’ post type. This just gives us the count of the ‘post’ post type.
Also, we only want to count published posts. A site with drafts would screw up the count because drafts are not (typically) publicly displayed.
Another way of counting all posts, regardless of post status
$post_count_alternative = wp_count_posts( 'post' );
echo "<p>Total number of posts: $post_count</p>";
Same result as above. We’re just specifying the post type this time around.
Since ‘post’ is the default, we don’t need to specify it in this case. But we’ll need to remember how to specify post types when we get to podcasts.
Get total count of all posts, published only
$post_count_published = wp_count_posts()->publish;
echo "<p>Total number of posts (just published): $post_count_published</p>";
Appending ->publish
to wp_count_posts()
ensures we’re only counting published posts.
Just for kicks, you could change the ->publish
to ->draft
, ->pending
, or ->trash
.
But the counts of drafts, pending, and trashed posts will be useless for our purposes.
Get total count of all podcasts, published only
Let’s combine what we learned above to get what we’re really after: a total count of published podcasts.
$podcast_count = wp_count_posts( 'podcast' )->publish;
echo "<p>Total number of podcasts (just published): $podcast_count_published</p>";
We’ll use this $podcast_count
value from here on out.
Count backwards through the loop
Now that we know how to count the number of published podcasts, we’ll use that in our podcast-related template files.
In the podcast archive template
Open up your archive-podcast.php
file.
Before the while loop starts, we’ll place our initial published podcast count value.
// Get total count of published podcasts
$podcast_count = wp_count_posts( 'podcast' )->publish;
// Start loop
while ( have_posts() ) : the_post();
// Use include( locate_template() ) so we can pass variable values to template part
include ( locate_template( 'template-parts/content-podcast.php' ) );
// Decrease counter
$podcast_count--;
// End loop
endwhile;
Within our while loop, we’ll include the template-parts/content-podcast.php
template.
It is critical that we use include ( locate_template() )
instead of get_template_part()
, as the latter doesn’t allow variables (like $podcast_count
) to be passed through it.
After the template is included, we’ll decrease the $podcast_count
value by one.
In the podcast content template part
Open up your template-parts/content-podcast.php
template.
We’ll output the count in a data attribute.
<article class="hentry" data-count="<?php echo $podcast_count; ?>">
<?php the_title( '<h2 class="entry-title"><a href="' . esc_url( get_permalink() ) . '" rel="bookmark">', '</a></h2>' ); ?>
</article><!-- .hentry -->
We’ll then use CSS to grab the number and display it.
.podcast-list .hentry:after {
content: "Episode #: " attr(data-count);
}
Although the template part is pretty small, we’re still separating it into its own file so we can re-use it for our Jetpack Infinite Scroll render function later on.
Getting it to work with pagination
At this point, our programmatic podcast episode numbering is working great.
That is, until you navigate beyond the first page of the podcast archive (i.e. example.localhost/page/2/
)
You’ll notice the count on the second page displays as if it were still on the first. And why would it? We have not made our counting function aware of what page we’re on.
Let’s revisit our archive-podcast.php
file.
Get the page number
First, let’s find out what page number we’re on by pasting this before the loop:
// Get page number
$paged = ( get_query_var( 'paged' ) ) ? get_query_var( 'paged' ) : 1;
On the second page, the value of $paged will be 2. On the third page, the value of $paged will be 3. And so on.
Get the posts per page
Next, let’s fine out how many posts there are per page.
// Get posts per page option
$posts_per_page = get_option( 'posts_per_page' );
For this, we’re just grabbing the option set in Settings → Reading
.
Adjusting the podcast episode number on pagination
To recap, we now have three variables defined before the while loop starts:
- Published podcast count
- Current page number
- Posts per page
Let’s say we have 100 podcasts, 10 posts per page, and we’re on the 2nd page. That means, the 2nd page of podcasts should start with episode #90.
Before peeking ahead, think back to algebra class. How can we use these values to adjust the podcast episode number on the second page?
Adjusted podcast count = Published podcast count - ( ( Current page number - 1 ) * Posts per page )
And now let’s plug in our sample values:
90 = 100 - ( ( 2 - 1) * 10 )
With PHP, we can write our “plain English” equation the same way.
Final variables and equation
For convenience, here are our variables and equation grouped together. To make things easier to read, we’ve handled the “current page number – 1” part earlier.
// Get total count of podcasts
$podcast_count = wp_count_posts( 'podcast' )->publish;
// Get page number minus 1
$paged = ( get_query_var( 'paged' ) ) ? get_query_var( 'paged' ) : 1;
$paged = $paged - 1;
// Get posts per page option
$posts_per_page = get_option( 'posts_per_page' );
// Adjusted podcast count
$podcast_count = $podcast_count - ( $paged * $posts_per_page );
At this point, we have a functioning podcast episode number displaying correctly on the first page, and subsequent pages.
But what if we want to use Infinite Scroll? That will require a little extra work.
Making it work with Jetpack Infinite Scroll
To make it work, we’ll need to declare theme support (necessary for any Infinite Scroll integration) and define a render function (this is where the counting magic will happen).
Add theme support
In our blank inc/jetpack.php file, add the following to declare Infinite Scroll support.
function themetry_jetpack_setup() {
// Add theme support for Infinite Scroll.
add_theme_support( 'infinite-scroll', array(
'container' => 'entries-list',
'render' => 'themetry_infinite_scroll_render',
'footer' => 'page',
'wrapper' => false,
) );
}
add_action( 'after_setup_theme', 'themetry_jetpack_setup' );
The container value matches up with the container ID in archive-podcast.php
and index.php
. Since we want Infinite Scroll to work on both normal posts and podcasts, we want to keep this pretty standard.
We’ll save the podcast-specific stuff for the render function, which we have called but yet to define. We will do so now.
Add render function
Since we want to make sure Infinite Scroll works with non-podcast posts as well, we’ll use a conditional function to isolate the podcast-specific code.
function themetry_infinite_scroll_render( $args ) {
// Get total count of posts
$podcast_count = wp_count_posts( 'podcast' )->publish;
// Get posts per page option
$posts_per_page = get_option( 'posts_per_page' );
// Get page number
$paged = ( get_query_var( 'paged' ) ) ? get_query_var( 'paged' ) : 1;
// New post count = total post count - ( page number * posts per page )
$podcast_count = $podcast_count - ( $paged * $posts_per_page );
while ( have_posts() ) {
the_post();
if ( is_post_type_archive( 'podcast' ) {
// Must use locate_template so we can pass $podcast_count value
include ( locate_template( 'template-parts/content-podcast.php' ) );
// Decrease counter
$podcast_count--;
} else {
get_template_part( 'template-parts/content' );
}
}
}
Note that the themetry_infinite_scroll_render
function name matches with what we set as our ‘render’ key value in our theme support declaration above.
Notable difference between the paged archive code
The Infinite Scroll render function is very similar to the code used on podcast-archive.php
, with one notable difference: we don’t subtract 1 from the page number.
For some reason, $paged
in our Infinite Scroll render function gives us the page we were on before we loaded new posts. Subtracting 1 on top of that would give us inaccurate counts.
Not a replacement for steps completed thus far
It’s also worth noting that an Infinite Scroll render function is not a replacement for any of the steps we’ve completed thus far.
The “Count backwards through the loop” step is still used to do the initial counting when a user lands on the podcast archive page (i.e. https://example.com/podcast/).
The “Getting it to work with pagination” step is still used because it’s possible for users to land on paged archive URLs (i.e. https://example.com/podcast/page/2/
) even with Infinite Scroll enabled.
Wrapping up
While we used a custom post type as an example, you could modify the code to work with taxonomies as well. If you’re unsure how exactly, ask in the forum and I’ll help.
But be wary of applying this technique on a broad scale across your site.
If you tried to apply it to your entire blog, and then individual categories, post order numbers would be different depending on the view, and that would be confusing.