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.

有帮助吗?

解决方案

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.

许可以下: CC-BY-SA归因
scroll top