pre_get_posts Remove posts based on meta value with ‘post__not_in’

I am attempting to alter the query of pages where the post meta value of _members_access_role does not meet that of the currently logged-in user. Here is what I have so far:

// Get all posts with the access level of 'Member'
function members_get_member_posts() {
    $post_ids = array();
    $args=array(
        'post_type' => array('post','tribe_events','document'),
        'meta_key' => '_members_access_role',
        'meta_value' => 'member',
        'post_status' => array('publish','private')
    );
    $protected_posts = get_posts($args);
    if($protected_posts) {
        foreach($protected_posts as $p) {
            $post_ids[] = $p->ID;
        }
    }
    // return an array of paid post IDs
    return $post_ids;
}

// Hide all posts from users who are not logged-in or are not administrators or members
function members_hide_member_posts($query) {
    $current_user = wp_get_current_user();
    if(empty($current_user) || ($current_user->roles[0] != 'member' && $current_user->roles[0] != 'administrator') && (false == $query->query_vars['suppress_filters'])) {
        $protected_posts = members_get_member_posts();
        if($protected_posts)
            $query->set('post__not_in', $protected_posts);
    }
    return $query;
}
add_filter('pre_get_posts', 'members_hide_member_posts');

If I do a quick print_r(members_get_member_posts()) I am seeing the array of post IDs correctly – but on the front-end, posts are still showing up when they should not be (since I am feeding in that returned function value to posts__not_in).

Read More

For example, if a public user visits the site, they can still see the Member (role) posts. Was also having a bit of trouble bringing in global $current_user object — as it would not check if $current_user->ID was empty or not without the page producing a fatal error about memory limits (even after I set the php.ini file to 256M for the hell of it), so a possible memory leak? Thanks!

Update
While not documented, I did double-check that you can use an array() value for post_type in get_posts as of 3.3 (I believe). Also tried without it and returns just posts as it should – so the data is returning, just not “filtering out” that data.

Related posts

Leave a Reply

1 comment

  1. Try this version:

    // Get all posts with the access level of 'Member'
    function members_get_member_posts() {
    
        $post_ids = wp_cache_get( 'wpse61487_members_posts' );
        if ( false === $post_ids ) {
    
            $post_ids = array();
            $args=array(
                'post_type' => 'any',
                'meta_key' => '_members_access_role',
                'meta_value' => 'member',
                'post_status' => array('publish','private')
            );
    
            $protected_posts = get_posts($args);
            if($protected_posts) {
                $post_ids = wp_list_pluck( $protected_posts, 'ID' );
            }
    
            wp_cache_set( 'wpse61487_members_posts', $post_ids );
         }
    
         // return an array of paid post IDs
         return $post_ids;
    }
    
    // Hide all posts from users who are not logged-in or are not administrators or members
    function members_hide_member_posts($query) {
    
        if( !$query->is_main_query() )
            return;
    
        $current_user = wp_get_current_user();
        if(empty($current_user) || ($current_user->roles[0] != 'member' && $current_user->roles[0] != 'administrator') && (false === $query->query_vars['suppress_filters'])) {
            $protected_posts = members_get_member_posts();
            if( !empty( $protected_posts ) )
                $query->set('post__not_in', $protected_posts);
        }
    }
    add_action('pre_get_posts', 'members_hide_member_posts');