WP_User->add_role producing unexpected results

I recently had to script the adding of a number of roles to a selection of the users in my database. In order to do so I put together a script like this:

error_reporting(E_ALL);
require("../../wp-load.php");

$source_file="role_source";

if(($source_handle = fopen($source_file, "r")) !== false) {
    while(($row = fgetcsv($source_handle)) !== false) {

        if(count($row) > 2) {

            if(($user = get_user_by('id', $row[1])) !== false) {
                for($i = 2; $i < count($row); $i++) {
                    if(!$user->has_cap($row[$i])) {
                        $user->add_role($row[$i]);
                    }
                }   
            } 
        }
    }

    fclose($source_handle);
}

This runs against source data that looks like this:

user@domain.com,2,role-slug-1,role-slug-2

And serves to add each of the listed roles that the user doesn’t already have to their set. Thing is, it doesn’t quite work. If I look in the wp_usermeta table, at the wp_capabilities row I can see the roles listed correctly, and all subsequent calls to WP_User->has_cap(<role name>) return true, but they’re the only things that act as if that user has that role. Calling current_user_can() returns false, and any of the plugins that let you manage users and grant them multiple roles deny that this user has those capabilities. Am I missing something here? From the documentation it looks like calling WP_User->add_role() should be all I need to do.

2 Answers
2

This would be best as a comment, but no reputation 🙂

In the codex they say

“If you are defining a custom role, and adding capabilities to the role using add_role(), be aware that modifying the capabilities array and re-executing add_role() will not necessarily update the role with the new capabilities list. The add_role() function short-circuits if the role already exists in the database.
The workaround in this case is to precede your add_role() call with a remove_role() call that targets the role you are adding.”

i suspect you could be inside this short-circuit

I say this cause it seems (just from your pasted code, it could be different) that your script could be running more than once (differently as it would do with plugin activation hook). But this is a guess. In this case, just hooking once (and making first remove_role() and then add_role() ) could do the trick

Leave a Comment