Excluding private/protected posts via IP

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.

Read More

Thanks!

Related posts

Leave a Reply

2 comments

  1. 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( '127.0.0.1', '255.255.255.255', ... );
        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( '127.0.0.1', '255.255.255.255', ... );
        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.

    Conclusion

    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.

  2. 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.