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.

When I write a post and schedule it for later publishing, WordPress will allow me to preview the post as if it was already published but I need to be logged in as administrator (or anyone who is authorized to preview the post).

Is there a way, possibly a query string parameter, to make the post previewable by anyone, i.e. also by anonymous users? Something like my-post?previewsecret=645732116468?

share|improve this question

2 Answers 2

up vote 4 down vote accepted

Draft previews

Take a quick look at this chunk of core code in query.php which

[Checks] post status to determine if post should be displayed.

http://core.trac.wordpress.org/browser/tags/3.3.1/wp-includes/query.php#L2658

if ( ! is_user_logged_in() ) {
  // User must be logged in to view unpublished posts.
  $this->posts = array();
}

...is what makes it somewhat non-straightforward to bypass for non logged in users. You could override the result of that function by going deeper and then taking care of roles. But that's too much overhead and can contribute to exposed security.

If you look a little further up http://core.trac.wordpress.org/browser/tags/3.3.1/wp-includes/query.php#L2632 on line 2632 you'll find that the post is actually fetched from the database and can be further filtered using the posts_results hook that comes a couple of lines lower.

Store the value of the post, and inject it towards the end after all the checks that void the posts array. http://core.trac.wordpress.org/browser/tags/3.3.1/wp-includes/query.php#L2740 where the_posts hook is eagerly awaiting.

So something rough would look like:

add_filter( 'posts_results', 'wpse46014_peek_into_private', null, 2 );
function wpse46014_peek_into_private( $posts, &$query ) {

    if ( sizeof( $posts ) != 1 ) return $posts; /* not interested */

    $status = get_post_status( $posts[0] );
    $post_status_obj = get_post_status_object( $status );

    if ( $post_status_obj->public ) return $posts; /* it's public */

    if ( !isset( $_GET['key'] ) || $_GET['key'] != 'foryoureyesonly' )
        return $posts; /* not for your eyes */

    $query->_my_private_stash = $posts; /* stash away */

    add_filter( 'the_posts', 'wpse46014_inject_private', null, 2 );
}

function wpse46014_inject_private( $posts, &$query ) {
    /* do only once */
    remove_filter( 'the_posts', 'wpse46014_inject_private', null, 2 );
    return $query->_my_private_stash;
}

Append your post preview link with the secret key ?p=4601&key=foryoureyesonly and the post is displayed for anyone. The code has some dirty going-ons, like the stash, you can use globals instead (not recommended), or wrap it up into an object (yes!) and further extend the functionality with custom passwords for each post, etc.

Scheduled previews

Scheduled previews work in a very similar way. The posts_results are populated with 'future' status posts in absolutely the same fashion and the same hooks can be leveraged. The code will work without change for scheduled posts.

/2012/07/12/one-two-three/ - 404 NOT FOUND

/2012/07/12/one-two-three/?key=foryoureyesonly - 200 OK

share|improve this answer
    
Amazing answer, thanks. –  Borek Mar 19 '12 at 19:00

Soulseekah's answer is incredible, and the exact thing I was looking for. In searching for this, I also came across a plugin (that might be based off this post for all I know).

Public Post Preview

share|improve this answer

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.