How to make scheduled post preview visible to anyone?

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?

Related posts

Leave a Reply

2 comments

  1. 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=foryoureyesonly200 OK