WordPress Development Stack Exchange is a question and answer site for WordPress developers and administrators. Join them; it only takes a minute:

Sign up
Here's how it works:
  1. Anybody can ask a question
  2. Anybody can answer
  3. The best answers are voted up and rise to the top

I essentially want password protected/private pages/posts in WP to work as they currently do, but completely disregard the functionality for certain IP addresses.

I've looked into filters/actions and don't see anything that seems promising, again I would prefer to do this without creating a specific category or anything outside of the current functionality of this in wordpress.


share|improve this question
up vote 0 down vote accepted

Bypass Password Protected Posts

You are, unfortunately right about the lack of filters, and hacking the core is inevitable. One solutions that seems to work revolves around the sanitize_post_field() function which fires off a number of interesting filters if its $context argument is not set to raw.

The template function that is responsible for deciding whether to show the password field or the content is http://core.trac.wordpress.org/browser/tags/3.2.1/wp-includes/post-template.php#L556

Notice how nice it would be to void the post_password? Let's dig in...

See how the post is acquired through the get_post() function: http://core.trac.wordpress.org/browser/tags/3.2.1/wp-includes/post.php#L370

The function contains no filters or actions to hook into, but sanitize_post_field() contains some filters that can be hooked into, and post_password goes through that function.

Please refer to the function http://core.trac.wordpress.org/browser/tags/3.2.1/wp-includes/post.php#L1676

Notice, however, that if $context == 'raw'; the function returns, and none of the filters are fired off. So a little core hack is required that will make the flow of the code reach those filters.

// wp-includes/post.php, line 557
-- $post = get_post($post);
++ $post = get_post($post, null, 'display');

Will force the $context to be anything but raw. This will permit to do something along the following lines:

function wpse31407_bypass_password( $value, $post_id, $context ) {
    $allowed_ips = array( '', '', ... );
    if (in_array( $_SERVER['REMOTE_ADDR'], $allowed_ips )) return '';
    else return $value;
add_filter( 'post_password', 'wpse31407_bypass_password', null, 3 );

This will effectively remove the password, so the test http://core.trac.wordpress.org/browser/tags/3.2.1/wp-includes/post-template.php#L556 if ( empty($post->post_password) ) is evaluated to true allowing you to bypass the password. There should be no implications by getting the post with a display context, as it is used only for the retrieval of the post_password.

You can as well create your own filter in the core around the post_password_required() function mentioned above, not to overcomplicate things, maybe. Up to you.

Bypass Private Posts

Now, as for private posts, refer to this bit or query.php http://core.trac.wordpress.org/browser/tags/3.2.1/wp-includes/query.php#L2649 as this is where the found post get stripped off of private entries.

And you'd be tempted to hook into the http://core.trac.wordpress.org/browser/tags/3.2.1/wp-includes/query.php#L2625 posts_results filter and go in and alter the post_status for each post from private to public... however, as you may have seen the get_post_status() function works on its own copy of a post that it gets from get_post()... ...which again has no filters but sanitize_post_field() does, which again requires a $context of anything but raw. So again:

// wp-includes/post.php, line 563
-- $post = get_post($post);
++ $post = get_post($post, null, 'display');

And hook into a filter to trick the function into thinking that the post is published by doing this:

function wpse31407_bypass_private( $value, $post_id, $context ) {
    $allowed_ips = array( '', '', ... );
    if (in_array( $_SERVER['REMOTE_ADDR'], $allowed_ips )) return 'publish';
    else return $value;
add_filter( 'post_status', 'wpse31407_bypass_private', null, 3 );

Or wrap your own filter around the get_post_status() function.


Once you understand which parts of the core are responsible for blocking the posts you can attempt to modify them however you require, so I hope my long answer helps to an extent, and someone follows up with more tips and perhaps better solutions. Great question, got me digging and thinking.

share|improve this answer
Thanks for the great feedback, out of curiosity, since post_status isn't a documented filter, does page status exist as well? I couldn't find either in the codebase via grep to be honest, but it worked! – user652650 Oct 19 '11 at 16:45
Glad to have been of help. A page is a post, with a post_type of page. You won't find these via grep, as they are in the form of 'post_'.$field, etc. – soulseekah Oct 20 '11 at 6:32

You don't need to change core, just add action to pre_get_posts and do your check:

add_action( 'pre_get_posts', 'filter_anime_tax' );
function filter_anime_tax( $query ) {
    $ip = getUserIP();
    $ip_data = geoip_record_by_name( $ip );
    if( $ip_data['country_code'] != 'anything you want' ) { 
        $query->set( 'post_status', array( 'publish', 'private' ) );

You can show or hide private posts to specific countries or IPs.

share|improve this answer

Your Answer


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.