hook_user is declared as follows:

function hook_user($op, &$edit, &$account, $category = NULL)

According to the documentation of hook_user, when $op is set to 'submit' and/or 'update' a user account is about to be modified. This implies that $account, the user object, can be changed within hook_user and these changes will be saved to the database (note that $account is passed as reference). However, this is not the case: Changes made to $account will not be saved to the database.

I have tried this with $op == 'submit', $op == 'update' and $op == 'insert'. In every case Drupal failed to save the changes made to $account (I attempted to change $account->roles).

This behaviour makes it impossible for modules to modify user information when a user is updated or created.

Support from Acquia helps fund testing for Drupal Acquia logo

Comments

Chill35’s picture

When you want your modifications to 'take' (be saved), you have to set the fields to NULL in $edit, as per the documentation. Have you tried doing that ?

For example, something like that :

$account->roles[] = 'contributer';
$edit->roles = NULL;
revnoah’s picture

Version: 5.1 » 6.13

I had a lot of trouble getting this work. Instead, I used the method below.

In this example, I'm modifying a profile field called 'public'.

function module_user($op, &$edit, &$account)
{
		switch($op)
		{
			case 'submit':
				
				$edit['profile_public'] = 0;
						
				break;
		}
	}
}
bradweikel’s picture

Version: 6.13 » 6.x-dev
Component: user system » documentation

The documentation for hook_user could use a little clarification, but the code is behaving correctly.

jhodgdon’s picture

Title: hook_user ignores changes to $account » hook_user documentation needs clarification on how to modify values

Changing title to reflect what needs to be clarified in the documentation

jhodgdon’s picture

Issue tags: +Novice

Probably could be done by a novice doc contributor

barbi’s picture

sub

cck’s picture

$edit and $account are passed to user_save() where $account is used to find the user and $edit has the user information that will be saved in the database. Use, for example, edit[email]="user@foo.com" to update the user's email address. $account->email="user@foo.com" will not be saved. Setting $edit[email] to NULL will clear its value. I tested the update operation in 6.19 and 6.28. Still the documentation can be a bit more clear. I cannot find core.php. If someone can tell me where it is, i can update it.

For the insert operation user_save uses a different path and it seems to be a bug based on the current documentation as both should work the same way. Since Drupal 7 does not use this, I don't know if it helps to fix it.

jhodgdon’s picture

Title: hook_user documentation needs clarification on how to modify values » hook_user/hook_user_presave documentation needs clarification on how to modify values
Version: 6.x-dev » 7.x-dev

Drupal 7 has hook_user_update and hook_user_insert; both of these run after the user object has been saved. Then there is hook_user_presave(), which appears to have the same documentation problem that is described here (no information saying "put the info on $edit not on $account).

Drupal 8 uses a user object and this problem is not present in the docs.

So let's fix the Drupal 7 hook docs first.

cck’s picture

Assigned: Unassigned » cck
FileSize
752 bytes

Update for Drupal 7.

cck’s picture

Status: Active » Needs review
jhodgdon’s picture

Status: Needs review » Needs work

Thanks! The wording looks good. There are a couple of trailing spaces in the patch though -- those need to be removed.

cck’s picture

Status: Needs work » Needs review
FileSize
750 bytes

Thanks for reviewing. They are removed.

jhodgdon’s picture

Status: Needs review » Reviewed & tested by the community

Thanks! That looks right to me.

David_Rothstein’s picture

Status: Reviewed & tested by the community » Fixed

Committed to 7.x - thanks! http://drupalcode.org/project/drupal.git/commit/fb0ecf1

I think technically it would be correct to say "will not necessarily be saved in the database" rather than "will not be saved"... For example, on programmatic user saves (or anything that does not pass a complete $edit array in), there will be properties not in $edit and therefore setting a property on $account should still result in it being saved.

However, this is confusing enough as it is, so I figured it's not so bad to be decisive rather than accurate here :) It should always be safe to use $edit (which will always take precedence over $account) and thus that one is preferred.

Status: Fixed » Closed (fixed)
Issue tags: -Novice

Automatically closed -- issue fixed for 2 weeks with no activity.