Hiding posts from non logged in users

Fiddling with user roles would probably be the most robust solution, however a quick and dirty approach would be to set post meta-data to mark posts that should be hidden, then add a meta-query to post queries by using a pre_get_posts hook in order to restrict results to non-hidden posts for non-logged-in users.

The following will limit all posts queried for logged-out visitors to those which either do not have associated hide_from_guests meta-data, or have that metadata set to 'false':

function wpse225120_hide_posts_from_guests( $query ) {
  // If the user's logged in, exit the function now.
  if( is_user_logged_in() )
    return;

  // Get the current metadata query so we can alter it instead of overwriting it
  $meta_query = $query->get( 'meta_query' );

  // Create a meta-query filtering out hidden posts
  $hidden_meta_query = array(
    'relation' => 'OR',
    array(
      'key'     => 'hide_from_guests',
      'value'   => 'false'
    ),
    array(
      'key'     => 'hide_from_guests',
      'compare' => 'NOT_EXISTS'
    ) 
  );

  // If there's not already a meta-query, supply the one for hidden posts and exit
  if( ! is_array( $meta_query ) || empty( $meta_query ) ) {
    $query->set( 'meta_query', $hidden_meta_query );
    return;
  }

  // If there is an existing meta-query, modify it to support our new hidden posts
  // meta-query as a top-level 'AND' condition, if need be
  if( isset( $meta_query[ 'relation' ] ) && 'OR' === $meta_query[ 'relation' ] )
    $meta_query = array(
      'relation'  => 'AND',
      $meta_query
    );
  }

  // Add the hidden posts meta-query and overwrite $query's old meta-query
  $meta_query[] = $hidden_meta_query;
  $query->set( 'meta_query', $meta_query );
}
add_action( 'pre_get_posts', 'wpse225120_hide_posts_from_guests' );

Note that globally altering every query like this is generally considered to be a bad practice. If at all possible, use is_main_query() and other conditional tags to limit query modifications to just the relevant queries in order to prevent unexpected behaviors and performance impact.

The 'hide_from_guests' post meta-data can be set on individual posts by using the custom fields interface, post metadata functions, or implementing a custom metabox and attaching it to relevant post types, among other ways.

Leave a Comment