The ‘user_has_cap’ hook seems to take two page loads to trigger

This question relates to another question I asked recently (http://wordpress.stackexchange.com/questions/29009/how-to-assign-specific-users-the-capability-to-edit-specific-pages-posts-cus/), the answer to which got me most of the way there to what I was trying to do. However, rather than keep updating that question I thought it better to post a new one as I really consider it more of a new issue now.

I am basically restricting Read access to a custom post type (projects) on a per-user basis, I’m using the user_has_cap hook and I check whether the User trying to Read a page has the post type’s ID in an array of IDs that are assigned to the User, depending on whether the array has the current post ID in it then Read capabilities are added / removed accordingly. This is done with the following code:

Read More
function allow_user_to_read_cpt_filter($allcaps, $cap, $args) {
    global $current_user; // Get user id
    get_currentuserinfo(); //...
    $userid = $current_user->ID; //...
    $wos_uspr_checked_read_ids = explode(',',esc_attr(get_the_author_meta('wos_uspr_read_data', $userid)));
    /* The above is a comma separated list of IDS, e.g. 724,736,784 */
    global $wpdb;
    $post = get_post($args[2]);
    if (!in_array($post->ID, $wos_uspr_checked_read_ids)) {
        $user = wp_get_current_user();
        $user->remove_cap('read_project');
        $user->remove_cap('read_projects');
        $user->remove_cap('read_others_projects');
        $user->remove_cap('read_published_projects');       
    } else {
        $user = wp_get_current_user();
        $user->add_cap('read_project');
        $user->add_cap('read_projects');
        $user->add_cap('read_others_projects');
        $user->add_cap('read_published_projects');
    }

    return $allcaps;
}

add_filter('user_has_cap', 'allow_user_to_read_cpt_filter', 100, 3);

(Yes, I have used different code than the answer given to my previous question, I don’t think this is contributing to the problem here though as I have used the other method of assigning capabilities, I just prefer using the above method.)

Anyway, the problem I am encountering with this is that it is taking two loads of the page before my post types content is being hidden. The code I am using on my page looks like this:

if (current_user_can('read_projects')) {
    echo '<p>Yes, you can read this.</p>';
} else if (!current_user_can('read_projects')) {
    echo '<p>No, you cannot read this.</p>';
}

My guess was that the hook was not being triggered quickly enough when the page is loaded in order to show or hide the content on the first load, but I’m struggling to find an answer to when user_has_cap is triggered.

Related posts

Leave a Reply

1 comment

  1. I finally managed to get the required behaviour, I ended up using updated code from the example I showed in my question – and actually closer to the code suggested in the question I referenced in my question text! Here is the code that worked in the end:

    function allow_user_to_edit_cpt_filter($allcaps, $cap, $args) {
        global $current_user; // Get user id
        get_currentuserinfo(); //...
        $userid = $current_user->ID; //...
        $a_user = new WP_User($userid); // Get user details
        if ($a_user->roles[0] != 'administrator')  { // Don't apply if administrator
            $wos_uspr_checked_edit_ids = explode(',',esc_attr(get_the_author_meta('wos_uspr_edit_data', $userid)));
            global $wpdb;
            $post = get_post($args[2]);
                // UPDATED CODE BLOCK BEGINS
            if (!in_array($post->ID, $wos_uspr_checked_edit_ids)) {
                if (($args[0] == "edit_project") || ($args[0] == "edit_others_projects") || ($args[0] == "edit_published_projects")) {
                    foreach((array) $cap as $capasuppr) {
                       if (array_key_exists($capasuppr, $allcaps)) {
                          $allcaps[$capasuppr] = 0;
                       }
                    }
                }
            }
                // UPDATED CODE BLOCK ENDS
        }
        return $allcaps;
    }
    add_filter('user_has_cap', 'allow_user_to_edit_cpt_filter', 100, 3);
    

    Using this code instead of what I’ve quoted in my question seems to trigger correctly on first page load, and my content is restricted from view the first time. I’m sure I’d tried this format before and had no success but it is now working as desired.