Question

I am trying to list all private pages that user has access to read. To explain in more details, below is the initial setup:

Each user has a specific role created and assigned only ability to read private pages. Then these roles are selected for specific pages to limit access to that page.

Example:

  • "user 1" role name = "user_1_role", capabilities = "Read Private Pages"
  • "user 2" role name = "user_2_role", capabilities = "Read Private Pages"
  • "Page 1", visibility set to Private, limit access to "user_1_role"
  • "Page 2", visibility set to Private, limit access to "user_1_role" and "user_2_role"

Goal:

  • When "user 1" is logged in, I would like to list all pages that this user is able to read. In this example that would be "Page 1" only.
  • For "user 2" the listing would be "Page 1" and "Page 2" as this user is able to read both pages.

I tried following code but this is listing all existing private pages and not only those with limited access to currently logged in user:

    $pages = get_pages(
        array('post_status' => array( 'private' ),
    ));
    foreach ( $pages as $page ) {
      if (current_user_can( 'read_private_pages', $page->ID )) {
          echo $page->post_title . "<br/>";
      }
    }

Any help would be much appreciated.

EDIT: I did not mention in original post that there can be unlimited number of pages and also user roles and users. So ideally the solution should work for any number of posts, users and roles.

I tried also following code similar to the above but with the same result:

    $user = wp_get_current_user();
    $pages = get_pages(
        array('post_status' => array( 'private' ),
    ));
    foreach ( $pages as $page ) {
      if ($user->has_cap( 'read_private_pages', $page->ID )) {
          echo $page->post_title . "<br/>";
      }
    }

When I try to change the capability to e.g. current_user_can( 'read_pages', $page->ID ), it is correctly not showing any pages in the list as there is no user with read_pages permissions, just with read_private_pages. So the current_user_can() somehow works, I just think the second parameter with $page->ID is for some reason not taken into account.

EDIT 2: I also forgot to mention that I am using a 3rd party plugin to create roles and restrict pages, known as MembersPress, so the answer/code must be able to work in conjunction with the aforementioned plugin.

Was it helpful?

Solution

I have made the following code for you to copy and paste in to your functions.php file.

I'm sure there is a simpler solution, however this is the working solution I came up with.

The first part of the section adds the new roles.

function anakeme_custom_roles() {

    add_role(
        'level_1',
        'Level 1',
        [
            'read_private_pages' => true,
            'read_level_1' => true,
        ]
    );

    add_role(
        'level_2',
        'Level 2',
        [
            'read_private_pages' => true,
            'read_level_2' => true,
        ]
    );

}
add_action( 'init', 'anakeme_custom_roles' );

The second part of the code creates the foreach loop and adds conditions depending on the users capabilities and page level.

function anakeme_shortcode_level() {

    $pages = get_pages(
        array(
            'post_status' => array( 'private' ),
        )
    );

    foreach ( $pages as $page ) {

        $page_level = get_post_meta( $page->ID, 'visibility_level', true );
        $read_1 = current_user_can( 'read_level_1', $page->ID );
        $read_2 = current_user_can( 'read_level_2', $page->ID );

        if ( $read_1 && $page_level == 1 ) {

            echo $page->post_title . "<br/>";

        } else if( $read_2 && $page_level >= 1 ) {

            echo $page->post_title . "<br/>";

        }

    }

}
add_shortcode( 'list_pages_level', 'anakeme_shortcode_level' );

Now for this to work, you must create a custom field in the pages you want to remain exclusive for certain roles/levels. The roles I created in my example use a numbering system.

So for Level 1 users to access level 1 pages, I simply added the custom field visibility_level and the value 1. Same goes for Level 2 users, just swapping the value 1 for 2.

Once that numbering system was established, I used a condition to check if the number was equal to 1 or more, then displayed the results accordingly.

To implement this anywhere in your site, use the shortcode list_pages_level.

If you would like further help in understanding the above code, or help expanding on the code, please reply with your questions(s)

EDIT

The above code will work without using third party plugins, however as the OP requires a code to work in conjunction with a plugin known as 'MembersPress', the below code should satisfy the OP's requirements of displaying pages that the currently logged in user has access to.

function anakeme_shortcode_level() {
    
    global $current_user;

    /**
      *
      * Get 'private' pages as array.
      *
      */
    $pages = get_pages(
        array(
            'post_status' => 'private',
        )
    );
    
    /**
      *
      * Loop through all pages.
      *
      */
    foreach ( $pages as $page ) {
        
        /**
          *
          * Get current users role.
          *
          */
        $user_roles = $current_user->roles;
        $user_role = array_shift( $user_roles );
        
        /**
          *
          * Check the current user can read private pages.
          *
          */
        $private = current_user_can( 'read_private_pages', $page->ID );
        
        /**
          *
          * Get the roles that have access to the associated page.
          *
          */
        $restricted = get_post_meta( $page->ID, '_members_access_role' );
        
        /**
          *
          * Find and echo only pages where the user has access to private pages and the `users role` is equal to the `role` restriction on the page set by MembersPress.
          *
          */
        if( ( $private ) && ( $user_role == in_array( $user_role, $restricted ) ) ) {
                
            echo $page->post_title . "<br/>";
            
        }

    }

}
add_shortcode( 'list_pages_level', 'anakeme_shortcode_level' );

Please note that the code provided above is NOT normally provided by StackOverflow members as it is relating to a 3rd party plugin (MembersPress). Please be sure to contact the plugin's customer support in the future for any coding requests.

Please be sure to mark the answer as correct if this is what you required and to also upvote the answer as a kind-of thank you :)

Licensed under: CC-BY-SA with attribution
Not affiliated with wordpress.stackexchange
scroll top