0

I've seen several (and have tried at least 15+ methods here on StackExchange) ways of how to do the custom post type loop, none work in my case.

I have tried methods using paged and without, using custom navigation and with resetting the permalinks.

I can get the posts to show, the issue I'm experiencing is with the navigation loading the same content despite the link changing to page-2.

Here is my current method without the use of paged

        <?php
        $args = array('post_type' => array('posts', 'affiliate-products'));

        query_posts($args);

        if (have_posts()) : while (have_posts()) : the_post();
                get_template_part('template-parts/content', 'product');
            endwhile;
            the_posts_navigation();
        else :
            ?>
            <p><?php esc_html_e('Sorry, no posts matched your criteria.'); ?></p>
        <?php endif; ?>

Could anyone please suggest a way of doing this with working pagination for front-page.php? Thanks in advance! <3

EDIT:

Current non-working code, based on the suggestions regarding the 'pre_get_posts' function:

Homepage loop

        <?php

    if (have_posts()) : while (have_posts()) : the_post();
            get_template_part('template-parts/content', 'product');
        endwhile;
        the_posts_navigation();
    else :
        ?>
        <p><?php esc_html_e('Sorry, no posts matched your criteria.'); ?></p>
    <?php endif; ?>

functions.php

add_action( 'pre_get_posts', function( \WP_Query $query) {
  if ( is_home() && $query->is_main_query() ) {
    $query->set('post_type', 'affiliate-products');
    $query->set( 'posts_per_page', 3 );
  }
} );

any ideas? :)

2
  • 1
    Is this replacing the main post loop? Or is this an additional post loop? Keep in mind that query_posts has a significant number of disadvantages, it doesn't change the posts that WP gives you, instead it throws away the posts and performs a second query. There are far better ways to modify which posts WP fetches than this to include custom post types on a page. By using query_posts you've doubled the number of queries, and have to re-implement all the functionality from scratch, e.g. pagination, it's the worst case scenario by default
    – Tom J Nowell
    Commented Dec 16, 2018 at 20:48
  • Please see edit above! Commented Dec 16, 2018 at 23:20

1 Answer 1

1

The root problem here is the call to query_posts:

    $args = array('post_type' => array('posts', 'affiliate-products'));

    query_posts($args);

At no point do you tell it which page to fetch, so it always fetches the first page, aka the default.

You could add this, but fundamentally, the entire approach is incorrect, and has many other problems you might not be aware of. For example, you don't call wp_reset_query, so any loops or code that run after your post loop will be broken. query_posts usage is a massive red flag, avoid it at all costs.

Sadly, a lot of legacy code still exists, and a lot of very old tutorials that mistakenly teach this to new people.

The Real Way To Change What Posts Get Shown

If you want to change which posts appear on a page, you're supposed to use the pre_get_posts filter so that it fetches what you want the first time.

Otherwise, you're throwing away the main query after the fact, then making a second query, making the page as much as 2x slower. Then, because you created your own query, none of the built in functionality is present, so you have to rebuild that too.

Instead, in your functions.php hook into pre_get_posts like this:

add_action( 'pre_get_posts', function( \WP_Query $query) {
    //
} );

Now you can use $query->set and $query->get to change the arguments before it goes to the database. You can use all the conditionals too such as $query->is_home() or $query->is_main_query().

For example, this filter will set the search page to only show 5 posts:

add_action( 'pre_get_posts', function( \WP_Query $query) {
    if ( $query->is_main_query() && $query->is_search() ) {
        $query->set( 'posts_per_page', 5 );
    }
} );

Now the search listings show 5 posts per page, pagination still works, it's just as fast, no performance penalty, and other features still work too.

Some notes:

  • pre_get_posts is a filter that modifies a standard main post loop. Use it with a normal loop, template modification is not necessary, if you're modifying templates to implement this then something has gone wrong
  • Never ever under any circumstances use query_posts. There is no valid use case that isn't covered by better/easier options. Erase this from your mind and if you come across it treat it with deep suspicion, it's a major red flag
  • If you need to change the posts the main loop fetches, use the pre_get_posts filter
  • If you need to do a second query, use WP_Query, but never use it to change or replace the main query. This is more for things like sidebar post lists, etc
  • Remember to cleanup after yourself, when using WP_Query you should call wp_reset_postdata afterwards or you'll break things
  • Don't smush all your loop statements together on one line, it makes things harder to read and confuses editors and tools

For reference, this is what a standard post loop looks like:

if ( have_posts() ) {
    while ( have_posts() ) {
        the_post();
        // display the post
    }
} else {
    // nothing was found
}

If you need to put a query_posts call before it, then something has gone horribly wrong. Use pre_get_posts instead.

I strongly recommend you look through the slides of this talk, they cover how to use queries, best practices, and common mistakes

8
  • Thank you for such a detailed answer, this is fantastic and I'm learning! I'm not so great with PHP, using: <?php pre_get_posts(); if (have_posts()) : while (have_posts()) : the_post(); ?> Doesnt seem to work, even though the pre_get_posts is now in the functions.php as you advised Commented Dec 16, 2018 at 21:50
  • Could you please give an example of usage, for myself and anyone in the future willing to learn from this! :) Commented Dec 16, 2018 at 21:52
  • Please see edit above! Commented Dec 16, 2018 at 23:20
  • @AlexHighHigh pre_get_posts is not a function, it's an action/hook. I already put a complete full example of using pre_get_posts in my answer. Your questions edit even includes what you need, but you've added other things in it that I never mentioned in my answer, such as the pre_get_posts('') function call, there's no such function, not sure why it was added
    – Tom J Nowell
    Commented Dec 17, 2018 at 0:25
  • I'm not experienced in PHP, could you please provide a working example for this setup? Commented Dec 17, 2018 at 0:57

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.