0

After pretty much getting everything working with query_posts, I noticed my pagination wasn't running. I was told pre_get_posts should be the solution.

My problems:

  1. I don't know how to pass all my criteria (query_posts(array('post_type' => 'trips', 'types' => $types, 'paged' => $paged,)in to pre_get_posts
  2. I can't get it working on (just) the template I want, which is used on a page (is_page doesn't work)

    Any help would be appreciated.

This is what's inside functions.php

function bwpm_pre_get_posts($query){
    if(!$query->get('posts_page_page'))
    $query->set('posts_per_page',1);
    }
    add_action('pre_get_posts','bwpm_pre_get_posts');

This is what's in the template that is used on the page.

<?php
/*
Template Name: Generic Trips Template
*/
?>
<?php get_header(); ?>

        <?php get_template_part( "beforeloop", "page" ) ?>
                                    <?php $types = $post->post_name; ?>


<?php if (have_posts()) : ?>
    <?php 
        $paged = (get_query_var('paged')) ? get_query_var('paged') : 1;
        query_posts(array( 
            'post_type' => 'trips', 
            'types' => $types, 
            'paged' => $paged,
        ) );
    ?>
<?php while (have_posts()) : the_post(); ?>
    <article id="post-<?php the_ID(); ?>" class="post"></article>

<?php endwhile; ?>

<div style="text-align:center;">
<?php posts_nav_link(' &#183; ', 'previous page', 'next page'); ?>
</div>

<?php endif; wp_reset_query(); ?>
        <?php get_template_part( "afterloop", "page" ) ?> 

<?php get_footer(); ?>

Update: 11/06/2012 After updating the code to @chipbennet example, the problem still isn't solved as I don't get properly working pagination. The previous link will never appear, and the next link will show the same content on every page. Full page code can be found on http://pastebin.com/NiuSEWia.

7
  • 1
    I'm using this on a page, so I've tried is_page, but that ain't working. I've also tried to get more criteria in to the pre_get_posts, but can't find a good example and that ain't working either. If anyone has a good example... .
    – WouterB
    Commented Jun 9, 2012 at 18:38
  • Can you explain what you're actually trying to accomplish? I get that you're trying to manipulate the pagination, but: why? What's the intended outcome? Knowing that will help answer the question. Commented Jun 9, 2012 at 20:33
  • @ChipBennett I was using query_posts, but didn't get pagination working. Now I'm trying to basically get everything working the way it was when I WAS using query_posts, and also get pagination working. Unfortunately, I don't know how to pass all my criteria in to pre_get_posts, nor do I seem to manage to get it working on the template I want it.
    – WouterB
    Commented Jun 9, 2012 at 20:57
  • You're describing an implementation method, without explaining what you're trying to implement. Why do you need to manipulate pagination? What, ultimately, are you trying to accomplish? Commented Jun 9, 2012 at 21:24
  • I don't need to manipulate pagination. I'm trying to have my custom template, which is used on a page to function the way a normal posts page would work. The only reason I'm not using the normal way is because I need to a) add some criteria (post type, types), and b) I want to call it only on a certain page.
    – WouterB
    Commented Jun 10, 2012 at 9:37

3 Answers 3

5
+25

It appears that you want to create a custom page template to display a custom post type? If so, you don't really need to mess with pre_get_posts at all.

First, create your custom page template. I assume you've already done this.

Second, you need to create a custom query, using WP_Query():

global $post;
$types = $post->post_name;

$trips_query_args = array( 
    'post_type' => 'trips', 
    'types' => $types, 
);

$trips_query = new WP_Query( $trips_query_args );

(Note: what is the 'types' parameter? As far as I know, it's not a core query parameter. Are you using it somehow?)

Third, we need to let WordPress know that it needs to base pagination on our custom query rather than on the default query:

global $wp_query;
// Put default query object in a temp variable
$tmp_query = $wp_query;
// Now wipe it out completely
$wp_query = null;
// Re-populate the global with our custom query
$wp_query = $trips_query;

At this point, we've moved the default query into a temporary variable, and re-populated the $wp_query global with our custom query.

Fourth, we need to output our custom query loop:

if ( $trips_query->have_posts() ) : while ( $trips_query->have_posts() ) : $trips_query->the_post();

    // Normal loop output goes here
    // You can use loop template tags normally
    // such as the_title() and the_content()

endwhile; endif;

Just put your loop output into the above. I've omitted it for brevity.

Fifth, we just need to reset things:

// Restore original query object
$wp_query = $tmp_query;
// Be kind; rewind
wp_reset_postdata();

This should be all you need to output a custom query loop, with proper pagination.

Edit

The use of taxonomy {slug} => {term} as a query taxonomy parameter was deprecated in WordPress 3.1, in favor of 'tax_query'. You should replace this:

'types' => $types

...with this:

'tax_query' => array(
    array(
        'taxonomy' => 'types',
        'field'    => 'slug',
        'term'     => $types
    ) 
)

This would make your $types_query_args array look like this:

$trips_query_args = array( 
    'post_type' => 'trips', 
    'tax_query' => array(
        array(
            'taxonomy' => 'types',
            'field'    => 'slug',
            'term'     => $types
        ) 
    )
);

Edit

@ChipBennett interesting development. I added 'paged' => N to the $trips_query_args array, where N stands for a number. When adding 1 the page actually shows exactly the perfect results for page 1. When adding 2 it shows the perfect results for page 2. However when using the navigation links OR even manipulating the URL, it no longer works. Any ideas?

So, let's try forcing the query pagination, using the following:

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

You would update your $trips_query_args array accordingly:

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

$trips_query_args = array( 
    'post_type' => 'trips', 
    'tax_query' => array(
        array(
            'taxonomy' => 'types',
            'field'    => 'slug',
            'term'     => $types
        ) 
    ),
    'paged'    => $paged;
);

Does that result in correct pagination?

23
  • +1: good explanation. @WouterB WordPress generates a page by: parsing the url as a query (applying pre_get_posts, retrieving the content from DB and then choosing a template. I.e. content is determined before templates. If you want to determine the content once the template has been retrieve you need to use this method. Commented Jun 10, 2012 at 14:51
  • That said - WP (can) support post type archives - so you might want to make use of that, tweaking it with pre_get_posts - possibly with the use of custom query variables Commented Jun 10, 2012 at 14:53
  • I suspect that the OP intends to use some page meta data to build the custom query, but I'm not certain. Commented Jun 10, 2012 at 17:57
  • @ChipBennett "types" is indeed a custom taxonomy. The page template is used on multiple categories. It calls only the posts that have the correct category.
    – WouterB
    Commented Jun 11, 2012 at 8:49
  • @ChipBennett Using your example I now have exactly the same results on page 2 as I have on page 1. Hope you can take another look. I've added the pages complete code on pastebin. pastebin.com/NiuSEWia
    – WouterB
    Commented Jun 11, 2012 at 10:11
3

WordPress figures pagination details based on the main query, and before the template is parsed. Which is probably why somebody recommended that you leverage pre_get_posts.

I don't know what the "beforeloop" and "afterloop" template parts in your code are for, but it looks like you're trying to let the main (page) query stand for the page header, then switch to a custom query, then switch back to the main query with wp_reset_query(). This approach won't work if you expect pagination to function properly, and is not a recommended approach to multiple queries in general. If you want two queries on a page, one of them should be a custom query using WP_Query or something similar.

You can either:

  • Determine if there's a natural WP equivalent of the page you're trying to create (for example, it look slike you're trying to create a post type archive, or a custom taxonomy term archive), and use this natural template instead. Check the Template Hierarchy.

  • Change the entire main query using pre_get_posts, and get anything else you need (the stuff currently in the beforeloop and afterloop) using a custom query. You can set all query params in pre_get_posts the same way you've set the posts_per_page param. For example:

    $query->set('posts_per_page',1); $query->set('post_type','trips');

Etc. You shouldn't need to manipulate the paged var if you're paginating based on the main query like this.

2
  • 1
    using what you describe results in a 404 page. function bwpm_pre_get_posts($query){ if(!$query->get('posts_page_page')) $query->set('posts_per_page',1); $query->set('post_type','trips'); } add_action('pre_get_posts','bwpm_pre_get_posts');
    – WouterB
    Commented Jun 10, 2012 at 13:24
  • @WouterB Sorry for the misunderstanding--I didn't mean to suggest that setting those two vars is all that's needed to get the result you want--I'm not exactly sure what that is. But that example is definitely how you set query params using pre_get_posts (in answer to your question #1). How to set query params and how to get exactly the result you're after are two different questions :) I still think your best bet is to figure out if there's a native query/template combo that fits your needs. As I said, it looks like a basic post type archive for a custom post type. Is that what you want?
    – MathSmath
    Commented Jun 10, 2012 at 20:39
0

I solved this issue using pre_get_post. I found one implementation that works for me:

if ( ! function_exists( 'ucc_add_cpts_to_pre_get_posts' ) ) {
    function ucc_add_cpts_to_pre_get_posts( $query ) {
        if ( $query->is_main_query() && ! is_post_type_archive() && ! is_singular() && ! is_404() ) {
            $my_post_type = get_query_var( 'post_type' );
            if ( empty( $my_post_type ) ) {
                $query->set('post_type', 'your_custom_type');
                $query->set('posts_per_page', 'your_posts_per_page');
            }
        }
    }
}
add_action( 'pre_get_posts', 'ucc_add_cpts_to_pre_get_posts' );

http://uncommoncontent.com/2012/01/28/add-custom-post-types-to-the-loop You must remove query_posts from your template.

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.