Programmatically adding and removing roles to users in Drupal

⚠️ Warning
This post is more than 10 years old. I do not delete posts, because even old information is still useful, but please know that some material on this page may be outdated or incorrect. Thanks!
Jul 1, 2011

[UPDATE: Here is a much simpler method for editing a user's roles.]

I thought there might be some sort of API function that allows me to add a user role to a user object by the role id (rid), but after looking at user_save() and some other information around the Drupal universe (like this thread), it looks like it's not as easy as I'd hoped. Definitely not like node_save(), where you just modify the node object, save it, and you're done!

I wrote this helper function that you could stick in your own custom module (tested with Drupal 7), which lets you add roles as simply as:

  custom_add_role_to_user($user->uid, 'role name here');

Here's the function:

/**
 * Add a role to a user.
 *
 * @param $user
 *   User object or user ID.
 * @param $role_name
 *   String value of role to be added.
 *
 * @see http_://drupal.org/node/28379#comment-4277052
 * @see http_://api.drupal.org/api/drupal/modules--user--user.module/function/user_save
 */
function custom_add_role_to_user($user, $role_name) {
  // For convenience, we'll allow user ids as well as full user objects.
  if (is_numeric($user)) {
    $user = user_load($user);
  }
  // If the user doesn't already have the role, add the role to that user.
  $key = array_search($role_name, $user->roles);
  if ($key == FALSE) {
    // Get the rid from the roles table.
    $roles = user_roles(TRUE);
    $rid = array_search($role_name, $roles);
    if ($rid != FALSE) {
      $new_role[$rid] = $role_name;
      $all_roles = $user->roles + $new_role; // Add new role to existing roles.
      user_save($user, array('roles' => $all_roles));
    }
  }
}

Hopefully, for Drupal 8, the user_save() function will be cleaned up (see the @todo), and this won't be such a chore.

[Edit: I've also written a handy function to remove user roles, which was made more robust in the way it removes roles using the $edit array of user_save() instead of modifying the user object's existing roles array, by g-hennux (see comments below). It's pasted below.]

/**
 * Remove a role from a user.
 *
 * @param $user
 *   User object or user ID.
 * @param $role_name
 *   String value of role to be removed.
 */
function custom_remove_role_from_user($user, $role_name) {
  // For convenience, we'll allow user ids as well as full user objects.
  if (is_numeric($user)) {
    $user = user_load($user);
  }
  // Only remove the role if the user already has it.
  $key = array_search($role_name, $user->roles);
  if ($key == TRUE) {
    // Get the rid from the roles table.
    $roles = user_roles(TRUE);
    $rid = array_search($role_name, $roles);
    if ($rid != FALSE) {
      // Make a copy of the roles array, without the deleted one.
      $new_roles = array();
      foreach($user->roles as $id => $name) {
        if ($id != $rid) {
          $new_roles[$id] = $name;
        }
      }
      user_save($user, array('roles' => $new_roles));
    }
  }
}