Or at least that's how it seems.

I have a page to which I pass several arguments to query post_meta for a custom field and I always get an extra "Next" link no matter the number of posts. If querying the same post type without passing any variables to 'meta_query' (setting $female to null) in my WP_query, pagination works as expected.

I have looked at every link I can find about custom post type pagination (and there are a lot of them), have installed page-navi, and have scoured the codex, have disabled and reendabled my plugins. I'm feeling somewhat foolish so please be nice as I'm embarrassed I can't get this to work. Here's my stripped down code and any ideas would be appreciated.

The urls:

http://dev.huntingtonmedical.com/doctors/page/7/ http://dev.huntingtonmedical.com/doctors/page/5/?gender=female (the next link will take you to a blank page)


    $gender = $_GET['gender'];
    if ( $gender != 'female' ) unset( $gender );

    global $paged;

    $paged = ( get_query_var('paged') ) ? get_query_var( 'paged' ) : 1;

    $args = array(
        'post_type' => 'doctors',
        'meta_key' => 'last_name',
        'orderby' => 'meta_value',
        'order' => 'ASC',
        'paged' => $paged,
        'meta_query' => array(
                'key' => 'gender',
                'value' => $gender,
                'compare' => 'IN'

    $query = new WP_Query( $args );

    while( $query->have_posts() ) { 
        echo '<br>';


    posts_nav_link(' | ',' Previous Page ',' Next Page ');
  • you're creating a new query in the template, but using the pagination from the main query, which runs before the template is loaded. have a look at pre_get_posts in codex and on this site.
    – Milo
    Dec 31, 2013 at 0:43
  • I have been stumped by Wordpress exactly two times now and I still am. It makes no sense that this should work this way and seems like it should be considered a bug, but I will go back and continue trying to understand and fix this. Thanks for the comment and links though, for sure. Quickly though, is wrapping the query in a function and then calling that function with the pre_get_posts action the simple answer?
    – Evan Rose
    Dec 31, 2013 at 15:41
  • it makes sense once you understand what's going on behind the scenes. this answer may help shed some light on things. also have a look at the Action Reference to see the process WordPress goes thru for each request. Note where posts_selection is (the main query) and where template_redirect is (loading the template). pre_get_posts lets you modify the query before it happens - you don't perform your own query, you just set query vars.
    – Milo
    Dec 31, 2013 at 15:54
  • So another hour has gone by and I'm feeling more foolish than before. I cannot find an example that makes sense. For instance, where does $qry come from in the answer on which you commented here? That is probably my missing link. Also, if I change the $args array into this $qry-> on this page link
    – Evan Rose
    Dec 31, 2013 at 17:05
  • Also, I tried your answer here link and don't understand where the variables in your functions are coming from and nor do I know what "// do special stuff" might be. And man, I have spent like 8 hours trying to figure this out and am incredulous that I can't find an answer I can wrap my head around!
    – Evan Rose
    Dec 31, 2013 at 17:09

1 Answer 1


/doctors/ is a post type archive, so we can check if that query is being run in the pre_get_posts action via the conditional tag is_post_type_archive( 'doctors' ) and modify those queries accordingly.

WordPress passes the query object to the function by reference ( $query in this example ), so we can modify the query vars via the set method of the query object. This code would go in your theme's functions.php file:

function wpa_doctor_gender( $query ) {
    // if this is the main query on the doctors post type archive
    if ( $query->is_post_type_archive( 'doctors' )
        && $query->is_main_query() ) {

        // set query vars for all doctors queries
        $query->set( 'meta_key', 'last_name' );
        $query->set( 'orderby', 'meta_value' );
        $query->set( 'order', 'ASC' );

        // set meta_query if gender is female
        if ( isset( $_GET['gender'] )
            && 'female' == $_GET['gender'] ){
                $meta_query = array(
                        'key' => 'gender',
                        'value' => $_GET['gender'],
                        'compare' => 'IN'
                $query->set( 'meta_query', $meta_query );
add_action( 'pre_get_posts', 'wpa_doctor_gender' );

Now in the template, we can get rid of all the custom query code and loop, and just run the vanilla loop to output posts:

while( have_posts() ) { 
    // etc..
  • First pass, this appears to be working! Sometimes when dealing with the guts, it's not clear what's been made available and what I need to do from scratch.
    – Evan Rose
    Dec 31, 2013 at 19:08
  • This page in Codex is a good starting point to learn more about the query internals.
    – Milo
    Dec 31, 2013 at 19:11
  • First pass, this appears to be working! Sometimes when dealing with the guts, it's not clear what's been made available and what I need to do from scratch. Also forgot you could pass $_GET parameters to functions! Thank you so much for your help and happy new year. (And believe me - I've read that page - I've read everything - just slow ;)
    – Evan Rose
    Dec 31, 2013 at 19:32

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.