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.
Comment | File | Size | Author |
---|---|---|---|
#12 | user-hook_user_presave_doc-124689-11.patch | 750 bytes | cck |
#9 | user-hook_user_presave_doc-124689-8.patch | 752 bytes | cck |
Comments
Comment #1
Chill35 CreditAttribution: Chill35 commentedWhen 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 :
Comment #2
revnoah CreditAttribution: revnoah commentedI 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'.
Comment #3
bradweikel CreditAttribution: bradweikel commentedThe documentation for hook_user could use a little clarification, but the code is behaving correctly.
Comment #4
jhodgdonChanging title to reflect what needs to be clarified in the documentation
Comment #5
jhodgdonProbably could be done by a novice doc contributor
Comment #6
barbi CreditAttribution: barbi commentedsub
Comment #7
cck CreditAttribution: cck commented$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.
Comment #8
jhodgdonDrupal 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.
Comment #9
cck CreditAttribution: cck commentedUpdate for Drupal 7.
Comment #10
cck CreditAttribution: cck commentedComment #11
jhodgdonThanks! The wording looks good. There are a couple of trailing spaces in the patch though -- those need to be removed.
Comment #12
cck CreditAttribution: cck commentedThanks for reviewing. They are removed.
Comment #13
jhodgdonThanks! That looks right to me.
Comment #14
David_Rothstein CreditAttribution: David_Rothstein commentedCommitted 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.