最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

Restrict Access to Posts based on Custom User and Post Meta Data

programmeradmin0浏览0评论

I have a custom Post Type called Club Pages, and a custom role called "Club Leader". Club Leaders currently can only read, modify, and delete all Club Pages posts. However, there are many different clubs that have their own sets of pages in this post type, and I need to make sure that Club Leaders can only read, edit, and delete the pages in WP Admin that are associated with their specific club.

Currently, each Club Pages post has a custom meta data field called club_name. I'm not using hierarchical post types to represent each club because there will be about 100 of them -- all of which need to use the same template and menu, which seems like a super cluttered and unmanageable admin area for super admins. I'm not opposed to using child post types if I need to, though.

So, my plan was to add a custom User Meta field, also called club_name, to represent which club Club Leaders are associated with, and somehow filter the Post Listing in the WP Admin to only show posts that have the same club_name as that user. So I'm thinking the logic for this filter would be something like:

If User->Role == 'Club Leader'
 get `user->club_name`
For each Post
 If `post->club_name` == `user->club_name`
  return `post_item`
 Else 
  return nothing

I expect each Club Leader to only be associated with one club each, but bonus points your solution allows me to give a single Club Leader access to multiple clubs' pages, in case that changes in the future.

Also, I know I only provided pseudo-code, but I'm looking for the full PHP code solution.

I have a custom Post Type called Club Pages, and a custom role called "Club Leader". Club Leaders currently can only read, modify, and delete all Club Pages posts. However, there are many different clubs that have their own sets of pages in this post type, and I need to make sure that Club Leaders can only read, edit, and delete the pages in WP Admin that are associated with their specific club.

Currently, each Club Pages post has a custom meta data field called club_name. I'm not using hierarchical post types to represent each club because there will be about 100 of them -- all of which need to use the same template and menu, which seems like a super cluttered and unmanageable admin area for super admins. I'm not opposed to using child post types if I need to, though.

So, my plan was to add a custom User Meta field, also called club_name, to represent which club Club Leaders are associated with, and somehow filter the Post Listing in the WP Admin to only show posts that have the same club_name as that user. So I'm thinking the logic for this filter would be something like:

If User->Role == 'Club Leader'
 get `user->club_name`
For each Post
 If `post->club_name` == `user->club_name`
  return `post_item`
 Else 
  return nothing

I expect each Club Leader to only be associated with one club each, but bonus points your solution allows me to give a single Club Leader access to multiple clubs' pages, in case that changes in the future.

Also, I know I only provided pseudo-code, but I'm looking for the full PHP code solution.

Share Improve this question asked May 21, 2020 at 18:06 CarriCarri 133 bronze badges 6
  • How many clubs will there be? – Tony Djukic Commented May 21, 2020 at 20:03
  • About 100.. maybe 90ish – Carri Commented May 21, 2020 at 20:29
  • That's quite a few, so my initial idea would be too long of a list of checkboxes. So you'd probably need a Select2 dropdown/AJAX search. Are you familiar with how the works? I built something similar where users were assigned a 'location' and then before displaying content I would run a location match check. But that was just 5 locations. Same method would work but a huge list of 'clubs' wouldn't be very use friendly. – Tony Djukic Commented May 21, 2020 at 20:32
  • Not specifically familiar, but conceptually, yes. Assigning a club to a user isn't the hard part, though. What I am not understanding is if I should be programmatically filtering posts in the WP-Admin area based on user/post meta data, or if I should just rely on the "capability" functionality that already exists in WP -- and I don't know what the syntax would look like for such a script in either case. – Carri Commented May 21, 2020 at 20:42
  • You'd definitely want to do a programmatic check as you load the posts into the post-list view. So check the users for the assigned club, then load the list. I'll post the method I used as an answer. – Tony Djukic Commented May 21, 2020 at 20:53
 |  Show 1 more comment

1 Answer 1

Reset to default 0

In a similar use case scenario, I had a client with 5 locations which could be assigned to the user. This will need to be changed for you because it's based on location being assigned to both a user and a post, whereas you're just going to assigning entire posts to users rather than matching post meta.

function filter_by_user_club( $query ) {
  if( is_admin() ) {
    $user_id        = get_current_user_id();
    $user_location  = get_user_meta( $user_id, 'myplugin_user_location', true );
    $currentscreen  = get_current_screen();
    if ( $currentscreen->post_type == 'custom_post_type' ) {
        if( !empty( $user_location ) ) {
            $location_meta_query = array(
                'key'   => 'cpt_location',
                'value' => $user_location,
                'compare'   => 'IN'
            );
            $query->set('meta_query', array( $location_meta_query ) );
        }
    }
  }
add_action( 'pre_get_posts', 'filter_by_user_club', 9998 );

I'm guessing that this sort of modification would need to be applied for your method, if I'm understanding your structure correctly...

You would need to change the meta_query to instead query an array of IDs using post_in, like so:

    function filter_by_user_club( $query ) {
      if( is_admin() ) {
        $user_id        = get_current_user_id();
        $user_clubs     = get_user_meta( $user_id, 'myplugin_user_clubs', true );
        $currentscreen  = get_current_screen();
        if ( $currentscreen->post_type == 'club_post_type' ) {
            if( !empty( $user_clubs ) ) {
                //if you've saved the user club IDs as an array (recommended)
                $query->set('post_in', $user_clubs );
                //if you've saved the user club IDs as a string use this...
                //$query->set('post_in', array( $user_clubs ) );
            }
        }
      }
    add_action( 'pre_get_posts', 'filter_by_user_club', 9998 );

Obviously a lot still to do to get the club IDs associated with the user, etc. but this will filter the club post type list based on the user.

We're using $query->set() and essentially adding an argument into that screen's default get_posts() query. While the query here, by default, will grab all of the posts (paginated based on how many you set per screen), we're now telling it to only show posts_in the array we provided when we checked which clubs a user has associated with them.

发布评论

评论列表(0)

  1. 暂无评论