Pagination might be one of the most seen ui-patterns on the web. The concept of showing just a limited amount of articles, posts or whatever and making the reader click through the rest, comes in quite a few variations. Googles search results are coming to mind or more advanced infinite scroll solutions. Naturally, WordPress implements this concept and I have to admit that, for some time, I found it quite difficult to use, especially with custom queries.

As so often, the difficulties weren’t caused by the API-implementation or documentation, but myself not reading it. So, after realizing that, there was nothing left than working it out and here is the solution I use in my starter-theme. It contains a file named pagination.php, with the following content.

<?php 
     
     global $paginated_query;
     global $wp_query;

     if ( !$paginated_query ):
     	$paginated_query = $wp_query;
     endif;

     if ( $paginated_query->max_num_pages > 1 ) : ?>
          <div class="pagination">
              if ( !$current_page = get_query_var('paged') ) :
                  $current_page = 1;
              endif;

              echo paginate_links(array(
                  'base' => get_pagenum_link(1) . '%_%',
                  'current' => $current_page,
                  'total' => $total    
              )); ?>
          </div><?php
     endif;

?>

The great thing is, that the paginate_links function does all the page-logic for you, if you just provide it with a current page number and the total numbers of pages. So if you want to paginate your main loop, all you have to do, is to include this file. Since we don’t define a $paginated_query, the parameters will be taken from the global $wp_query.

<?php if ( have_posts() ) : while ( have_posts() ) : the_post(); ?>
...
<?php endwhile; endif; ?>
<?php get_template_part("pagination); ?>

But it’s quite easy, even with a custom query. Here you have to define the $paginated_query variable, before including pagination.php and giving the paged param to the WP_Query-object, so the requested page can be queried.

<?php 
    $custom_query = new WP_Query( array(
        'post_type' => 'page',
        'posts_per_page' => 3,
        'paged' => ( !$current_page = get_query_var('paged') ) ? 1 : $current_page
    ) );
?>
<?php if ( $custom_query->have_posts() ) : while ( $custom_query->have_posts() ) : $custom_query->the_post(); ?>
...
<?php endwhile; endif; ?>
<?php 
    $paginated_query = $custom_query;
    get_template_part("pagination); 
?>

That’s how I do it, but I’m always interested in other solutions.

Please comment if you have a better or alternative solution!

function check_custom_query_param( $query ) {
    if ( isset($query->query_vars['custom_param']) && $query->query_vars['custom_param']) {
        $query->custom_param = true;
    }
}
add_action( 'pre_get_posts', 'check_custom_query_param' );


function change_where_query( $where, &$wp_query ) {
    global $wpdb;	
    if ( property_exists ( $wp_query , 'custom_query' ) && $wp_query->custom_query ) {
    	// change the where query
    }
    return $where;
}
add_filter('posts_where', 'change_where_query', 10, 2);

The snippets story

Some weeks ago I wanted to pass a custom parameter to the WP_Query object to change the where-query if the param was true. The problem was, that to extend WP_Query with a parameter, you have to circumvent the filtering of the query options. I solved this by hooking into the pre_get_posts action. There the custom parameter is still available and we can easily add it to the filtered query object.

$menu = wp_get_nav_menu_items($menu_id,array(
   'posts_per_page' => -1,
   'meta_key' => '_menu_item_object_id',
   'meta_value' => $post->ID // the currently displayed post
));
var_dump($menu[0]->ID);

Current wp_nav_menu item: The snippets story

I needed to retrieve the current wp_nav_menu item connected to the currently requested page/post in WordPress. I found some solutions going through the hole menu-tree, comparing each items object-id with the current post-id. But, since menu items are post-types, you are able to use all the WP-Query-params with wp_get_nav_menu_items, even a meta-query. The code above selects all menu_items which are connected to the current post, from the menu you specify via $menu_id.

The only drawback is that two menu-items, linked to the same post, would both be returned without you knowing which was actually clicked. However thats the same with all the other solutions I found.