Last active
August 29, 2015 14:04
-
-
Save keesiemeijer/8c5ba761707a2ffaabbb to your computer and use it in GitHub Desktop.
Reversed WordPress Pagination
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?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; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
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/