What I am looking to do:
Setup WP_Query
pagination in a single-custom-post-type.php template file
What I have done
1) Created a post type called "authors". Each post within that post type is an individual author.
2) Standard edit post screen pages contain a dropdown which lists all posts (authors) from the authors custom post type.
3) Created a single-authors.php template which query's all posts with the author metadata from the dropdown, so the result is a list of posts that have the same author assigned to them (kind of like an archive):
<?php
// set the "paged" parameter (use 'page' if the query is on a static front page)
global $paged;
/*We need this here to add and maintain Pagination if Template is assigned to Front Page*/
if ( get_query_var( 'paged' ) ) {
$paged = get_query_var('paged');
} elseif ( get_query_var( 'page' ) ) {
$paged = get_query_var( 'page' );
} else {
$paged = 1;
}
$args = array(
'posts_per_page' => 10,
'meta_key' => 'author_select',
'meta_value' => $author_id,
'paged' => $paged,
);
$temp = $wp_query;
$wp_query = NULL;
$wp_query = new WP_Query($args);
?>
<?php if( $wp_query->have_posts() ) : ?>
<?php while ( $wp_query->have_posts() ) : $wp_query->the_post(); ?>
<?php // Successfully outputs the results of the above query, so I've omitted the code from this example. ?>
<?php endwhile; ?>
<div class="single_navigation">
<?php if( get_adjacent_post( false, '', true ) ) { ?>
<span class="prev"><?php previous_post_link( '< %link' ) ?></span>
<?php } ?>
<?php if( get_adjacent_post( false, '', false ) ) { ?>
<span class="next"><?php next_post_link( '%link >' ) ?></span>
<?php } ?>
</div><!--/single navigation-->
<?php endif; ?>
<?php
$wp_query = null;
$wp_query = $temp;
wp_reset_query();
?>
What I am stuck on
The pagination links do not appear. I have done some research and have found that they use the $wp_query
variable, however when I changed my query variable to $wp_query
, the links appeared, but when clicked did nothing.
Any idea where I am going wrong?
Edit:
To answer some of your questions, my query successfully outputs the posts that I am querying, $author_id already has a value that I did not include in this code snippet. Similarly, I left out the actual content output within the while loop because that part is not the issue. The issue is that I need to paginate the content that already exists on this single post.
The purpose of this functionality was to allow posts to have custom authors (outside of the built in Users system) and this template's purpose is to output all of the posts for a given author (which is already working).
What I am looking to do:
Setup WP_Query
pagination in a single-custom-post-type.php template file
What I have done
1) Created a post type called "authors". Each post within that post type is an individual author.
2) Standard edit post screen pages contain a dropdown which lists all posts (authors) from the authors custom post type.
3) Created a single-authors.php template which query's all posts with the author metadata from the dropdown, so the result is a list of posts that have the same author assigned to them (kind of like an archive):
<?php
// set the "paged" parameter (use 'page' if the query is on a static front page)
global $paged;
/*We need this here to add and maintain Pagination if Template is assigned to Front Page*/
if ( get_query_var( 'paged' ) ) {
$paged = get_query_var('paged');
} elseif ( get_query_var( 'page' ) ) {
$paged = get_query_var( 'page' );
} else {
$paged = 1;
}
$args = array(
'posts_per_page' => 10,
'meta_key' => 'author_select',
'meta_value' => $author_id,
'paged' => $paged,
);
$temp = $wp_query;
$wp_query = NULL;
$wp_query = new WP_Query($args);
?>
<?php if( $wp_query->have_posts() ) : ?>
<?php while ( $wp_query->have_posts() ) : $wp_query->the_post(); ?>
<?php // Successfully outputs the results of the above query, so I've omitted the code from this example. ?>
<?php endwhile; ?>
<div class="single_navigation">
<?php if( get_adjacent_post( false, '', true ) ) { ?>
<span class="prev"><?php previous_post_link( '< %link' ) ?></span>
<?php } ?>
<?php if( get_adjacent_post( false, '', false ) ) { ?>
<span class="next"><?php next_post_link( '%link >' ) ?></span>
<?php } ?>
</div><!--/single navigation-->
<?php endif; ?>
<?php
$wp_query = null;
$wp_query = $temp;
wp_reset_query();
?>
What I am stuck on
The pagination links do not appear. I have done some research and have found that they use the $wp_query
variable, however when I changed my query variable to $wp_query
, the links appeared, but when clicked did nothing.
Any idea where I am going wrong?
Edit:
To answer some of your questions, my query successfully outputs the posts that I am querying, $author_id already has a value that I did not include in this code snippet. Similarly, I left out the actual content output within the while loop because that part is not the issue. The issue is that I need to paginate the content that already exists on this single post.
The purpose of this functionality was to allow posts to have custom authors (outside of the built in Users system) and this template's purpose is to output all of the posts for a given author (which is already working).
Share Improve this question edited May 8, 2014 at 19:26 Shane asked May 8, 2014 at 16:38 ShaneShane 3391 gold badge3 silver badges10 bronze badges 6 | Show 1 more comment3 Answers
Reset to default 25You have 2 problems.
First problem
The line
$paged = ( get_query_var( 'paged' ) ) ? get_query_var( 'paged' ) : 1;
will fail, because on singular post view, when the URL contains '/page/XX/'
, the variable WordPress sets is 'page'
and not 'paged'
.
You may think to use 'page'
instead of 'paged'
, but that will not work either, because once the 'page'
variable is intended to be used for multi-page singular post (page separation using <!--nextpage-->
) and once the post is not multi-page, WordPress will redirect the request to the URL without '/page/XX/'
.
This is what happens when you name your query variable $wp_query
.
The solution is to prevent that redirection by removing the function responsible for it, which is 'redirect_canonical'
hooked into 'template_redirect'
:
So, in your functions.php
add:
add_action( 'template_redirect', function() {
if ( is_singular( 'authors' ) ) {
global $wp_query;
$page = ( int ) $wp_query->get( 'page' );
if ( $page > 1 ) {
// convert 'page' to 'paged'
$wp_query->set( 'page', 1 );
$wp_query->set( 'paged', $page );
}
// prevent redirect
remove_action( 'template_redirect', 'redirect_canonical' );
}
}, 0 ); // on priority 0 to remove 'redirect_canonical' added with priority 10
Now WordPress will not redirect anymore and will set correctly the 'paged'
query var.
Second problem
next_posts_link()
and previous_posts_link()
both check if ( ! is_single() )
to display pagination.
Now, is_single()
is true in your case, because you are in a single post of 'author' type, so those functions can't work as you expect.
You have 3 possibilities:
- Use
query_posts
to override the main query (really not recommended) - Use a custom page template instead of a custom post type, because
is_single()
is false for pages, and your code will work there. - Write your own pagination function and use that
That's the code for solution number #3:
function my_pagination_link( $label = NULL, $dir = 'next', WP_Query $query = NULL ) {
if ( is_null( $query ) ) {
$query = $GLOBALS['wp_query'];
}
$max_page = ( int ) $query->max_num_pages;
// only one page for the query, do nothing
if ( $max_page <= 1 ) {
return;
}
$paged = ( int ) $query->get( 'paged' );
if ( empty( $paged ) ) {
$paged = 1;
}
$target_page = $dir === 'next' ? $paged + 1 : $paged - 1;
// if 1st page requiring previous or last page requiring next, do nothing
if ( $target_page < 1 || $target_page > $max_page ) {
return;
}
if ( null === $label ) {
$label = __( 'Next Page »' );
}
$label = preg_replace( '/&([^#])(?![a-z]{1,8};)/i', '&$1', $label );
printf( '<a href="%s">%s</a>', get_pagenum_link( $target_page ), esc_html( $label ) );
}
and use it like so in the single-authors.php
:
my_pagination_link( 'Older Entries', 'next', $author_query );
my_pagination_link( 'Newer Entries', 'prev', $author_query );
Based on another similar WPSE question "Pagination is not working wp_query custom fields values", I would suggest adding global $paged;
to the beginning of your template file:
global $paged;
$paged = ( get_query_var( 'paged' ) ) ? get_query_var( 'paged' ) : 1;
gmazzap provides a detailed answer, but I found several portions were not necessary for my implementation, which is very similar to yours. The vital portion was to rearrange my template and use a page template, rather than a custom post type.
In my query args, I did the following:
$paged = (get_query_var('paged')) ? get_query_var('paged') : 1;
$get_posts_args = array(
'numberposts' => -1,
'posts_per_page' => 5,
'paged' => $paged,
'page' => $paged,
'post_type' => array('dvposts','post'),
'post_status' => 'publish',);
Passing $paged
to both the paged
and page
keys allowed both the links to point to the correct url and the results to actually move through the pages.
Then anywhere after you initialize your query, you use paginate_links with with at least these args:
$big = 999999999; // need an unlikely integer
echo paginate_links( array(
'base' => str_replace( $big, '%#%', esc_url( get_pagenum_link( $big ) ) ),
'format' => '?paged=%#%',
'current' => max( 1, get_query_var('paged') ),
'total' => $qwer->max_num_pages,
) );
This example is actually at the bottom of the WP codex page.
I wanted the page numbers to show, but if you don't, you can use previous_post_link
and nest_post_link
all the same.
I can't say I fully understand it, but it seems like there might be issues with 'current' => max( 1, get_query_var('paged') )
. That may not be the same as $paged
that was initialized earlier. I changed it to 'current' => max( 1, $paged ),
and it worked the same, as expected.
the_title()
– Pieter Goosen Commented May 8, 2014 at 16:47'meta_value' => $author_id
being filled from the dropdown mentioned? And when selecting each author via the dropdown, are the first ten posts showing correctly? – Stephen S. Commented May 8, 2014 at 16:52$author_query->have_posts()
returnstrue
and that the$author_query
actually contains any posts? – kaiser Commented May 8, 2014 at 17:06