2

I've got a page called Blog. In the Settings -> Reading I've set my Blog page as Posts page. In the menu when I click on the Blog link the posts are loaded correctly and pagination works, so far so good. All the info is coming from the home.php template.

I'm using my own pagination code that generates the pages looking at max_num_pages and paged params. In short it generates correct amount of pages with the correct links.

However, when I test a non-existent blog page. For example there are 5 pages exist and I type blog/page/6 it doesn't get redirected to 404, instead it seems to fall back to the else statement of the main if(have_posts()).

I've tested the category paginated pages that use the same pagination code, they work correctly: non existing category pages of type category/<category_name>/page/2 are redirected to 404 template.

I can't think of anything why the main blog 'paged pages' that don't exist won't redirect to 404.

I would hugely appreciate any tips and help.

Many thanks, Dasha

3 Answers 3

1

This is the default Wordpress behaviour for pagination when using a custom query (where you feed in the paged value yourself) or in the index.php as it doesn't realize there isn't content to display on the XXXth page until it has already loaded the template, and then tries to run the WP_Query.

You can try adding logic that determines if $paged is set and no results are found, then throw the 404, which would look something like this:

header("HTTP/1.0 404 Not Found");
$wp_query->set_404();
require TEMPLATEPATH.'/404.php';
exit;
11
  • Wow, I'm impressed that it's a default WP behavior. Surely this is one of the top scenarios for a blog with a page being set up as "Posts Page". Gonna try your solution now. Thanks!
    – dashaluna
    Commented Mar 20, 2012 at 11:20
  • Also, I was wondering if the following statements do the same thing: $wp_query->is_404 = true; and $GLOBALS['wp_query']->is_404 = true; and $wp_query->set_404(); Does it make difference which one to use? Similarly, are these the same as well: status_header(404); and header("HTTP/1.0 404 Not Found"); and whether it makes difference to use them? Thanks!
    – dashaluna
    Commented Mar 20, 2012 at 11:34
  • This is not the default behavior. Try ma.tt/category/meta/page/20 :D
    – fuxia
    Commented Mar 20, 2012 at 12:08
  • @toscho, yes it somehow doesn't feel like a default behaviour.. It would be nice to know why that's happening. Hm, I'm not sure what I'm looking at at that link? :S
    – dashaluna
    Commented Mar 20, 2012 at 12:19
  • The link leads to a category page without posts. It's a 404 … because that is the default behavior.
    – fuxia
    Commented Mar 20, 2012 at 12:24
4

This is what I usually use on my functions.php in every wordpress site (I know, I should code it as a plugin...)

/**
 * @author daniele raimondi W3B snc
 * @version 0.4
 * @abstract This workaround fixes a problem with page pagination, where you can request
 * n paginated part of a (non-paginated)page from 2 to 2147483647 (max 32 signed int value)
 * and you will never get a 404 error. WP returns instead the page itself  if it's a not-paginated page, 
 * or the first page if you request n-paginated pages, from n+1 on.
 */

function fix_missing_404_on_paginated_page() {
    global $wp_query,$page,$paged;

    if (!isset($page)) $page = get_query_var('page');
    if (!isset($paged)) $paged = get_query_var('paged');
    if (is_page() || is_single()) {
        $realpagescount = count( explode( '<!--nextpage-->', $wp_query->post->post_content ) );

        if ( (isset($page) && isset($realpagescount) && $page >= $realpagescount) || (is_paged() && isset($paged) && $paged >=0 ) ){
        //wp_redirect( home_url() );
            nocache_headers();
            status_header( '404' );
            $wp_query->is_404=true;
            $wp_query->is_single=false;
            $wp_query->is_singular=false;
            $wp_query->post_count=0;
            $wp_query->page=0;
            $wp_query->query['page']='';
            $wp_query->query['posts']=array();
            $wp_query->query['post']=array();
            $wp_query->posts=array();
            $wp_query->post=array();
            $wp_query->queried_object=array();
            $wp_query->queried_object_id=0;
            locate_template('404.php', true);
            exit;
        }
    }
}
add_action('template_redirect', 'fix_missing_404_on_paginated_page');
0
2

I had something similar recently on pages and posts in a multisite installation. Unfortunately I haven’t figured out why WordPress didn’t call the 404 template sometimes, but I build a workaround:

In the functions.php I created a small helper function:

/**
 * Helper for cases where the 404 template is not loaded correctly.
 *
 * @return bool
 */
function t5_force_404()
{
    if ( have_posts() )
    {
        return FALSE;
    }

    header( 'HTTP/1.0 404 Not Found' );
    locate_template( '404.php', TRUE, TRUE );
    $GLOBALS['wp_query']->is_404 = TRUE;
    return TRUE;
}

And on top of the single.php and page.php I called it like this:

if ( t5_force_404() ) {
    return; // stop any further processing
}

// everything is fine, go on.
get_header();

So … this will solve the issue, but I still don’t know why it happens.

1
  • This is a great approach to have a helper function like that, thanks!
    – dashaluna
    Commented Mar 20, 2012 at 11: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.