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.

  • How many clubs will there be? – Tony Djukic May 21 at 20:03
  • About 100.. maybe 90ish – Carri May 21 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 May 21 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 May 21 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 May 21 at 20:53
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.

| improve this answer | |
  • What action would I have to hook into in order to use this properly? Also, can you explain how $query->set('post_in', $user_clubs ); works to perform the filter? I ask because it doesn't seem like that line alone would work in all cases, but I may be missing something. – Carri May 21 at 21:45
  • I forgot to add the action, sorry. There's a lot more in the function I wrote that doesn't apply to your use-case so I only extracted the one segment you needed. I have updated my answer. What we're doing is adding query arguments to the get_posts query, so we hook into the pre_get_posts' action. We then also check to make sure we're in the is_admin()` section and we also then make sure we're only doing this for that one custom post type. – Tony Djukic May 22 at 15:14
  • Thank you so much -- This is really close to what I want, but its my fault for not being clear. The posts I'm trying to filter will share a meta key and value with the user. So, I need to use something like $query->set('meta_query', $args); instead. – Carri May 25 at 23:10

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.