Created my first custom theme from scratch and I’m trying to do a listing of all posts with the same tag.
In tag.php
I display all posts with that specific tag via a WP_Query
and I’m trying to implement the pagination for that listing (using paginate_links()
). Page links seem to be outputted correctly. Also the first page looks good.
What I don’t understand is that when I go on to the next tag page (or to any of the page links outputted from my tag.php
template e.g. http://127.0.0.1/wp_site/tag/test_tag/page/2/
) the content from index.php
is being displayed.
What am I actually missing for displaying the subsequent tag pages correctly?
tag.php
template CODE:
<?php get_header(); ?>
<div class="">
<div id="primary" class="content-area">
<main id="main" class="site-main" role="main">
<?php if (have_posts()) : ?>
<article id="post-<?php the_ID(); ?>" <?php post_class(); ?>>
<header class="entry-header">
<h1 class="entry-title">Other entries related to '<?php single_tag_title(); ?>'</h1>
</header><!-- .entry-header -->
<div class="entry-content"></div><!-- .entry-content -->
</article><!-- #post-## -->
<div>
<?php while (have_posts()) : the_post(); ?>
<?php
$tagId = get_queried_object()->term_id;
$postType = get_post_type();
?>
<?php endwhile; ?>
<?php
$htmlOutput="";
/* the 'terms' ID is the testimonial category parent id */
$paged = ( get_query_var( 'paged' ) ) ? get_query_var( 'paged' ) : 1;
$args = [
'post_type' => 'testimonials-widget',
'tag_id' => $tagId,
'posts_per_page' => 3,
'paged' => $paged,
'tax_query' => [
[
'taxonomy' => 'category',
'field' => 'term_id',
'terms' => '8',
]
],
];
$post_query = new WP_Query($args);
$contentHtml="";
if($post_query->have_posts() ) {
$posts = $post_query->posts;
foreach($posts as $post) {
// generate html output
}
}
wp_reset_postdata();
echo $contentHtml;
?>
</div>
<div class="mainContentWrapperCls">
<?php
echo paginate_links( array(
'base' => str_replace( 999999999, '%#%', esc_url( get_pagenum_link( 999999999 ) ) ),
'total' => $post_query->max_num_pages,
'current' => max( 1, get_query_var( 'paged' ) ),
'format' => '?paged=%#%',
'show_all' => false,
'type' => 'plain',
'end_size' => 2,
'mid_size' => 1,
'prev_next' => true,
'prev_text' => sprintf( '<i></i> %1$s', __( '<< Previous page', 'text-domain' ) ),
'next_text' => sprintf( '%1$s <i></i>', __( 'Next page >>', 'text-domain' ) ),
'add_args' => false,
'add_fragment' => '',
) );
?>
</div>
<?php else : ?>
<h1>No posts were found.</h1>
<?php endif; ?>
</main><!-- #main -->
</div><!-- #primary -->
</div><!-- .wrap -->
<?php get_footer(); ?>
Note: I created a new query with
WP_Query
intag.php
. The reason why I did this is because I didn’t know how to generate the type of pagination I needed (<Prev 1 2 3 Next>
style) viapaginate_links()
, with the main query.
Theme functions.php
CODE:
<?php
function myCustomThemeScriptEnqueue() {
// Theme stylesheet, js
wp_enqueue_style('myCustomTheme-style', get_stylesheet_uri(), array(), '1.0.0', 'all');
}
function myCustomThemeThemeSetup() {
add_theme_support('menus');
add_post_type_support( 'page', 'excerpt' );
}
function nllTagFilter($query) {
if ($query->is_main_query()) {
if ($query->is_tag) {
$post_types = get_post_types();
$query->set('post_type', $post_types);
}
}
}
add_action('pre_get_posts','nllTagFilter');
add_action('wp_enqueue_scripts', 'myCustomThemeScriptEnqueue');
add_action('init', 'myCustomThemeThemeSetup');
add_theme_support( 'post-thumbnails' );
set_post_thumbnail_size( 150, 150 );
?>
This is my theme’s file-structure so far:
2 Answers
Overall CODE issues:
Your CODE is so wrong in so many ways that I shouldn’t even attempt to address them here. I suggest you study Official WordPress Theme Handbook properly before doing these sort of customizations.
For the sake of the context, I’m ignoring other issues within your CODE and touching only the issues below:
1. Why index.php
template is being loaded?
First of all, you are getting wrong pagination from your erroneous CODE (check the explanation below). So apart from the first tag page, all the other tag pages are nonexistent (i.e. you need to add more posts to the tag to get more tag pages).
Secondly, According to WordPress Template loading rules, 404.php
template should be loaded for those non-existing tag pages (as you probably know, in HTTP, 404 is the Page Not Found Error CODE). However, since you don’t have a 404.php
template in your theme, index.php
template is being loaded, as it is the ultimate fallback template in a WordPress theme.
Now, if you create a 404.php
template, then you’ll see that it’ll be loaded instead of index.php
for those non-existing tag pages.
Study WordPress Template Hierarchy properly for a better understanding of how different templates are loaded for different content.
2. Fixing the wrong pagination:
As I said above, you’re getting nonexistent tag page numbers within your pagination. To remove those nonexistent page numbers from the pagination, you need to delete the
'total' => $post_query->max_num_pages
line from the paginate_links
function call in tag.php
template file.
The reason is:
-
$post_query
is your custom query, not the main query that should determine the number of pages the tag archive has. You even usedwp_reset_postdata()
beforepaginate_links
function call, so no reason to use that variable here. -
The
total
parameter of thepaginate_links
function by default gets the value of the main WP_Query’smax_num_pages
property. So deleting it will automatically provide the correct value for the pagination from the main WP_Query object.
3. Pagination without new WP_Query
:
In the comments you said:
The reason why I did this is because I didn’t know how to generate the type of pagination I needed (
<Prev 1 2 3 Next>
style) viapaginate_links()
, with the main query.
Well, you don’t need a completely new WP_Query
just for a different pagination style. In fact, the paginate_links()
function don’t need the main WP_Query
object at all!
So all you need for your desired pagination style is:
echo paginate_links( array(
'end_size' => 2,
'mid_size' => 1,
'prev_text' => __( '<< Previous page', 'text-domain' ),
'next_text' => __( 'Next page >>', 'text-domain' )
) );
All the other values are being collected by default (including the main WP_Query
object)! So you can remove your new WP_Query
object in the tag.php
template entirely. Check the paginate_links
documentation.
Having said that, there can be only one more thing you may want (judging from your comments):
4. Control the number of posts per tag page:
You don’t need a new WP_Query
for this either. This can be easily achieved from the following CODE in functions.php
:
function tag_post_per_page_filter( $query ) {
if ( $query->is_main_query() ) {
if ( $query->is_tag ) {
$query->set( 'posts_per_page', 3 );
}
}
}
add_action('pre_get_posts','tag_post_per_page_filter');
Basically it sets the posts_per_page
to 3
in the main WP_Query
object for the tag pages. That’s all.