Skip to content

Instantly share code, notes, and snippets.

@keesiemeijer
Last active August 29, 2015 14:04
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save keesiemeijer/8c5ba761707a2ffaabbb to your computer and use it in GitHub Desktop.
Save keesiemeijer/8c5ba761707a2ffaabbb to your computer and use it in GitHub Desktop.
Reversed WordPress Pagination
<?php
/**
* Reversed Pagination for WordPress - proof of concept
*
* WARNING! Not suitable for use on a live website!
*
* Proof of concept for reversed pagination as discussed here
* http://nerd.vasilis.nl/problem-paginated-archive-pages-blogs/
* and here (Dutch)
* http://wasstra.at/035/
*
* As of now it lacks the lower and upper limits as discussed in the article.
* This makes it possible you can only have one post in the first (non paginated) page.
* With some small adjustments It should be possible to recalculate the posts with the limits.
*
* I've made this to see if I could coax WordPress in retrieving the correct posts for paginated pages.
*
* Still to do (and probably a whole lot more):
* Core pagination functions need be adjusted for the new ordering (or create your own).
* Make it work if the default permalink structure is used.
* Feeds?
* Static front page posts page?
* More defensive coding.
* Lots more testing.
*
* Example of what posts are shown with 10 posts per page.
*
* example.com/ - 1 to ? newest posts - date DESC
* example.com/page/2 - 10 older posts - date DESC
* example.com/page/1 - 10 oldest posts - date DESC
*/
add_filter( 'redirect_canonical', 'first_paged_canonical', 10, 2 );
/**
* allows pagination to start at 1 (url/page/1)
*/
function first_paged_canonical( $redirect_url, $requested_url ) {
global $wp_rewrite;
// Abort if not using pretty permalinks, is a feed, is a single post or page
if ( ! $wp_rewrite->using_permalinks() || is_feed() || is_singular() ) {
return $redirect_url;
}
// If paged === 1, apppend pagination back to $redirect_url.
if ( get_query_var( 'paged' ) === 1 ) {
$redirect_url .= user_trailingslashit( "page/1", 'paged' );
}
return $redirect_url;
}
add_action( 'pre_get_posts', 'my_post_queries' );
/**
* resets orderby and order for the main query
*/
function my_post_queries( $query ) {
// not an admin page and is the main query
if ( !is_admin() && $query->is_main_query() && ! ( is_feed() || is_singular() ) ) {
// get total posts and set new limits for the query
add_filter( 'posts_clauses', 'my_post_clauses', 99, 2 );
// let's order by the 'date'
$query->set( 'orderby', 'date' );
$paged = my_get_paged_query_var();
if ( $paged > 0 ) {
$query->set( 'order', 'ASC' );
// reverses the post order back to DESC for the posts on paginated pages
add_filter( 'the_posts', 'my_reverse_the_posts', 99, 2 );
} else {
// first non paginated page
$query->set( 'order', 'DESC' );
}
}
}
/**
* sets new limits for the 'limits' clause
*/
function my_post_clauses( $pieces , $_this ) {
global $wpdb;
extract( $pieces );
// What page are we on? (starting from 0)
$paged = my_get_paged_query_var();
if ( ! empty( $groupby ) ) {
$groupby = 'GROUP BY ' . $groupby;
}
if ( !empty( $orderby ) ) {
$orderby = 'ORDER BY ' . $orderby;
}
// Extra query needed to get the total posts found.
$query = "SELECT $wpdb->posts.ID FROM $wpdb->posts $join WHERE 1=1 $where $groupby $orderby";
$total = count( $wpdb->get_results( $query ) );
$posts_per_page = $_this->get( 'posts_per_page' );
if ( $total ) {
$max_num_pages = ceil( $total / $posts_per_page );
// Bail for last page posts.
// Posts are also displayed on the first not paginated page because order by date is now ASC.
if ( $paged == $max_num_pages ) {
$_this->set_404();
return $pieces;
}
if ( $paged > 0 ) {
// set limits on paginated pages starting from 1 (order by date is ASC)
$pieces['limits'] = 'LIMIT ' . ( ( $posts_per_page * $paged ) - $posts_per_page ) . ',' . $posts_per_page;
} else {
// calculate posts on the first (not paginated) page
$posts = $total - ( ( $max_num_pages - 1 ) * $posts_per_page );
// set limits if there is pagination to be done (order by date is DESC)
$pieces['limits'] = ( $max_num_pages > 1 ) ? "LIMIT 0, $posts" : '';
}
}
return $pieces;
}
/**
* reverses the posts if $paged > 0
*
* pagination starts at 1 instead of the default 2
*/
function my_reverse_the_posts( $posts, $_this ) {
return array_reverse( $posts );
}
/**
* $paged query_var will be set to 0 for first (not paginated) page
*
* pagination starts at 1 instead of the default 2
*/
function my_get_paged_query_var() {
$paged = get_query_var( 'paged' );
if ( !$paged ) {
$paged = 0;
}
return $paged;
}
@keesiemeijer
Copy link
Author

Proof of concept for reversed WordPress archives pagination as discussed here:
http://nerd.vasilis.nl/problem-paginated-archive-pages-blogs/
And here (Dutch):
http://wasstra.at/035/

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment