Take the 2-minute tour ×
WordPress Development Stack Exchange is a question and answer site for WordPress developers and administrators. It's 100% free, no registration required.

How do I 301 redirect private pages, rather than 404 them? If a post is private, WordPress filters it out in the SQL query, so there are no $post variables to work with.

I'd like for this code to work, but doesn't:

add_action('wp','redirect_stuffs', 0);
function redirect_stuffs(){
global $post;
    if ( $post->post_status == "private" && !is_admin() ):
        wp_redirect("http://dangayle.com/",301);
        exit();
    endif;
}

I don't know where that is set earlier than wp, other than the fact that I know it's a user role issue. If I could set a non-logged in user to have that capability, it would probably fix the issue:

$publicReader -> add_cap('read_private_posts');

The problem with add_cap is that only logged-in users have capabilities.

share|improve this question
add comment

3 Answers

up vote 3 down vote accepted

Sorry guys, I found my answer:

add_action('wp','redirect_stuffs', 0);
function redirect_stuffs(){
global $wpdb; 
    if ($wpdb->last_result[0]->post_status == "private" && !is_admin() ):
        wp_redirect( home_url(), 301 );
        exit();
    endif;
}

Posts/Pages are removed from the sitemaps, but the page still shows up on the site so that it can get 301'd.

share|improve this answer
add comment

Firstly, I would have to agree with @fencepost's answer. However, I couldn't resist posting a solution, so here we are!

function __intercept_private_page( $posts, &$wp_query )
{
    // remove filter now, so that on subsequent post querying we don't get involved!
    remove_filter( 'the_posts', '__intercept_private_page', 5, 2 );

    if ( !( $wp_query->is_page && empty($posts) ) )
        return $posts; // bail, not page with no results

    // if you want to explicitly check it *is* private, use the code block below:   
    /*
        if ( !empty( $wp_query->query['page_id'] ) )
            $page = get_page( $wp_query->query['page_id'] );
        else
            $page = get_page_by_path( $wp_query->query['pagename'] );

        if ( $page && $page->post_status == 'private' ) {
            // redirect
        }
    */

    // otherwise assume that if the request was for a page, and no page was found, it was private
    wp_redirect( home_url(), 301 );
    exit;
}
is_admin() || add_filter( 'the_posts', '__intercept_private_page', 5, 2 );

Update: Revised code to use the_posts filter instead of posts_results (which fires before WordPress checks permissions, and so $posts hasn't been 'emptied' yet).

share|improve this answer
    
I'll check this out. Thanks! –  Dan Gayle Mar 14 '11 at 15:58
    
This still 404s. –  Dan Gayle Mar 14 '11 at 21:44
    
Revised answer. –  TheDeadMedic Mar 14 '11 at 22:35
add comment

It seems to me that you shouldn't return either 404 or 301 - you should return either 401 (Unauthorized / authentication required, though you won't accept any authentication offered) or 403 (Rejected, aka I know what you're asking for and you can't have it).

There's an abandoned plugin Private Page Forbidden that might be worth looking at for guidance, though at a casual glance it seems to want to convert 404 into 403 which seems like a bad idea. Unfortunately while there's been a variety of discussion of options (see https://core.trac.wordpress.org/ticket/10551 and related) the milestone for fixes has gradually moved to "Future Release."

share|improve this answer
    
I just now understood what you meant. In general, I might agree with you. After all, the return numbers exist for a reason. Unfortunately, in this case, I don't have a choice but to 301, which is a directive which comes from above. –  Dan Gayle Mar 14 '11 at 15:59
add comment

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.