Pagination causes error 404 when used with front-page.php

EDIT

From your comments, front-page.php is only used when a page is set as a static front page. Normal home pages, ie, when Front page displays is set to Your latest posts, index.php is used.

All archive pages and the front page uses paged and not page, so you would need to set get_query_var( 'page' ) to get_query_var( 'paged' ).

Any ways, you should not be using a custom query on your home page, you should be using pre_get_posts to alter the main query to your needs

add_action( 'pre_get_posts', function ( $q )
{
    if (    $q->is_home()
         && $q->is_main_query()
    ) {
        $q->set( 'category_name',  'featured' );
        $q->set( 'posts_per_page', 4          );
    }
});

Your pagination links should then be

next_posts_link( 'Next' );
previous_posts_link( 'Previous' );

Your loop in index.php should look like this

if ( have_posts() ) {
    while ( have_posts() ) {
        the_post();

           // Your markup and template tags

    }
}

If you really need to use front-page.php as a normal home page and not a static front page, then you need to do the following

  • Change your loop to what I have suggested above with the pagination links

  • Use pre_get_posts as suggested as above to change the main query according to your need

  • Use the home_template filter to use front-page.php as your homepage template

You can try the following

add_filter( 'home_template', function ( $template )
{
    $locate_template = locate_template( 'front-page.php' );

    if ( !$locate_template )
        return $template;

    return $locate_template;
});

ORIGINAL ANSWER

The functions next_posts_link() and previous_posts_link() don’t work on static front pages out of the box. The issue is, pagination uses get_query_var( 'paged' ) which is saved in the $paged global. Because static front pages uses get_query_var( 'page' ) and not get_query_var( 'paged' ), your links will never paginate past page 1.

We can trick next_posts_link() and previous_posts_link() to think they are used on an archive page by setting the $paged global to get_query_var( 'page' ).

You can try the following

$paged                   = get_query_var( 'page', 1 ); 
$args                    = [];
$args['post_type']       = 'post';
$args['post_status']     = 'publish';
$args['category_name']   = 'featured';
$args['posts_per_page']  = 4;
$args['paged']           = $paged;

$the_query = new WP_Query($args);

if ($the_query->have_posts()) {

    while ($the_query->have_posts()) {

        $the_query->the_post() ;
        the_title();

    } // End of: while ($the_query->have_posts())

    next_posts_link('Next', $the_query->max_num_pages );
    previous_posts_link('Previous');

    wp_reset_postdata(); // VERY VERY IMPORTANT

} // End of: if ($the_query->have_posts())

EDIT

You can also make use of the following on your static front page

$query = new PreGetPostsForPages(
    251,       // Page ID we will target, your static front page ID
    'content', //Template part which will be used to display posts, name should be without .php extension 
    false,     // Should get_template_part support post formats
    true,      // Should the page object be excluded from the loop
    [          // Array of valid arguments that will be passed to WP_Query/pre_get_posts
        'post_type'      => 'post', 
        'category_name'  => 'featured',
        'posts_per_page' => 4
    ] 
);
$query->init(); 

where the PreGetPostsForPages class is supported by my answer here

add_action( 'pregetgostsforgages_after_loop_pagination', function ()
{
    $paged = get_query_var( 'page', 1 );
    next_posts_link( 'Next' );
    previous_posts_link( 'Previous' );
});

Leave a Comment

tech