1

Inside my index.php, I have a new WP_Query() for a custom post type that I have named "todo".

I am trying to implement pagination for this query, so it only displays three posts, then requires to go to the next page to view more.

However, with this code after the while loop:

<li><?php next_posts_link( 'NEXT', $todos->max_num_pages) ?></li>

The actual link itself is bringing me to localhost/page/2.

When it should be bringing me to localhost/todo/page/2, as when I enter this URL manually, it does show me the three next posts, instead of the other URL which brings me to a 404.

I am very new to Wordpress and may be missing some key details for this question, as well as some fundamental knowledge of how things work, but if anyone know's what I am doing wrong I would appreciate any help..

Below is the entire code:

if ( get_query_var( 'paged' ) ) { $paged = get_query_var( 'paged' ); }
elseif ( get_query_var( 'page' ) ) { $paged = get_query_var( 'page' ); }
else { $paged = 1; }

$args = array(
  'posts_per_page' => 3,
  'post_type'   => 'todo',
  'post_status' => 'publish',
  'page' => $paged
 );
 
$todos = new WP_Query( $args );
?>

    <main id="primary" class="site-main">
        <section class="glass">
            <div class="todolist">
            <?php
            if( $todos->have_posts() ) :
                while($todos->have_posts()) :
                $todos->the_post();
            ?>
                <div class="todo">
                    <img src="<?php echo get_template_directory_uri() . '/event_note-24px'?>" alt="">
                    <div class="details">
                        <h2><?php echo get_the_title();?></h2>
                        <div class="time">
                            <img src="<?php echo get_template_directory_uri() . '/query_builder-24px'?>" alt="">
                            <?php echo get_the_content();?>
                        </div>
                    </div>
                    <div class="todoaction">
                        <img src="<?php echo get_template_directory_uri() . '/done-24px'?>" alt="">
                        <img src="<?php echo get_template_directory_uri() . '/clear-24px'?>" alt="">
                    </div>
                </div>
                <?php endwhile;?>
            </div>
            <li><?php previous_posts_link( ' PREV', $todos->max_num_pages) ?></li> 
            <li><?php next_posts_link( 'NEXT', $todos->max_num_pages) ?></li>
            <?php endif; ?>
        </section>

Thank you.

1 Answer 1

0

That is actually the expected output of next_posts_link(), i.e. it always uses the current page URL. And the same also applies to previous_posts_link().

So if you're on the homepage (localhost/), then the URL of page 2 would be localhost/page/2, and if you're on (your custom post type archive page at) localhost/todo, then the URL of page 2 would be localhost/todo/page/2.

And if you want to alter the main WordPress query on the homepage, then you should use the pre_get_posts hook instead of making a secondary/custom WP_Query call (new WP_Query()) in your index.php template.

So for example, to display 3 todo posts on the homepage,

  1. Add this to your theme's functions.php file:

    add_action( 'pre_get_posts', 'my_pre_get_posts' );
    function my_pre_get_posts( $query ) {
        // If we're on the homepage, query 3 "todo" posts instead of the default ones.
        if ( is_home() ) {
            $query->set( 'post_type', 'todo' ); // query posts of the "todo" type only
            $query->set( 'posts_per_page', 3 ); // and display three posts per page
        }
    }
    
  2. Then in your index.php template, just remove those $todos and $args, and use the default loop to display the posts returned via the main query:

    <?php
    // No need for the $todos and $args.
    ?>
    
        <main id="primary" class="site-main">
            <section class="glass">
                <?php if ( have_posts() ) : ?>
                    <div class="todolist">
                        <?php while ( have_posts() ) : the_post(); ?>
                            <div class="todo">
                                ... your code.
                            </div>
                        <?php endwhile; ?>
                    </div>
    
                    ... your pagination here.
                <?php endif; // end have_posts() ?>
            </section>
    

That way, even if next_posts_link() and previous_posts_link() do not add the todo/ to the pagination links, you wouldn't get the error 404 when going to localhost/page/2 unless of course if there's no page 2 for the main query.

And if you wonder what that "main" (WordPress) query is, then check the Codex, specifically the part which says, "Save the posts in the $wp_query object to be used in the WordPress Loop.".

Also, your pagination code will show an empty bullet when there's no next/previous posts link, so to fix that, you'd want to use get_previous_posts_link() instead of previous_posts_link() and get_next_posts_link() instead of next_posts_link(). Example:

<?php // this would replace the "... your pagination here." part above.

$links = '';

if ( $link = get_previous_posts_link( 'Previous Posts' ) ) {
    $links .= "<li>$link</li>";
}

if ( $link = get_next_posts_link( 'Next Posts' ) ) {
    $links .= "<li>$link</li>";
}

if ( $links ) {
    echo "<ul>$links</ul>";
}
?>

Additionally, in your $args array, you should've used paged (note the "d") and not page, i.e. 'paged' => $paged. But I'm just saying that so you know the correct arg is paged. :)

1

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.