Userprops are defined in bin/upgrading/proplists.dat. They're a quick way to store preferences, settings, and information about the user, such as the values of choices they've made in the past. If you're looking for a quick way to store any data about the user, without having to create a whole new database table, your first thought should be "userprop".
(There are other things in proplists.dat along the same lines -- talkprops, which apply to comment objects, and logprops, which apply to entries -- but for the purpose of this walkthrough, we'll assume that you're dealing with userprops.)
When to use userprops
- Are you trying to store a yes/no for the user, like whether or not they have a specific feature on or off? If so, you should make a new userprop.
- Are you trying to store a trinary or multiple-value option, like the option for what email address to show on the profile for paid users? (none, system email address, user-specified email address, local (@dreamwidth.org) email address, system + local, user + local) If so, you should make a new userprop.
- Are you trying to store a small amount of text as a preference, like the customized crosspost footer text or the username of the person who invited the user? If so, you should make a new userprop.
- Are you trying to store multiple things that all depend on each other, or things that have the possibility to get really long, or things that there can be a lot of (like tags or memories or vgifts received/sent)? If so, a userprop won't help you -- that's getting into "new database table" territory.
On your development environment, give your working user the priv canview:userprops or canview:* and go to /admin/propedit.bml. That lets you see all of the userprops defined on your dev environment, and manipulate them as necessary. It's a good idea to keep this page handy, because while you develop, you'll want to refer to it as you go.
To create a new userprop, add it into bin/upgrading/proplists.dat. It's okay to copy an existing userprop definition and just change what you want to change.
The lines you want to change are 'des' and 'prettyname'. Prettyname should be a short, explanatory, human-understandable title for the userprop, and 'des' should be a description of what it does and what the possible values are (and what they mean). Documenting the possible values and what they do here will save you and others a hell of a lot of time code-diving later, so be sure you do it!
"Datatype" is something else you can change if you want to. The two you'll most usually use are 'char' (characters) and 'num' (for numbers), although there's also 'bool' for boolean (on/off). It's usually a better idea to go with 'char' as a type for greatest flexibility -- if you set something up as boolean and later on discover that you need another option, it's annoying to re-do them, while if you set it up as 'char' you can treat it as boolean in the code and still have the ability to expand later.
If you're storing something that's more than just a few options, you can also use 'blobchar' as a type -- that will allow you more than 255 characters.
Once you have your new userprop created, save the file and tell the database to reload the file:
$LJHOME/bin/upgrading/update-db.pl -r -p --innodb
Then go to /admin/propedit and verify that your new userprop exists.
Working with userprops
To manipulate your userprops in-code, there are a bunch of functions you can call. Most of them are defined in cgi-bin/LJ/User.pm, in section 7 (Userprops, Caps, and Displaying Content to Others).
The most useful functions and how they should be called:
$u->prop( userprop ); # returns the current value of the userprop 'userprop' for user object $u $u->set_prop( userprop, $value ); # sets the userprop 'userprop' to value '$value' for user object $u $u->clear_prop( userprop ); # clears the value of the userprop 'userprop' (sets it to undef) for user object $u
Best practice tips
- Remember that when you create a new userprop, everyone who already has created an account on the site won't have the userprop set. Your code should take that into account and assume smart defaults for what to do when the userprop isn't defined, which will also make the choice for what to do for new accounts. (See some of the various functions in section 7 of cgi-bin/LJ/User.pm, which provides some examples of how to set defaults and assume the proper behavior for userprops.)
- If you're accepting user input to set the userprop -- for instance, if you're not setting it based on the user's choice of a drop-down box or a checkbox in a HTML form, but as part of a text input form -- be sure to run it through one of the user-input sanitizing and escaping functions in cgi-bin/ljtextutil.pl.
- You're probably going to want to set, clear, and manipulate your userprops through a Settings package, so they can appear on one of the tabs of manage/settings/.
- If you want your userprop to be settable through the admin console "set" command, you need to create a section for it in cgi-bin/LJ/Hooks/Setters.pm. Unless you add it here, it won't be settable or manipulatable via the admin console.
- When you're working with userprop values in-code, it's a good idea to make sure that you provide an alternative for what to do if the userprop has a value that shouldn't be possible, just in case.
- If you want newly-created users to have a specific setting for the userprop, instead of just assuming what to do in-code, you can add it to the %USERPROP_INIT section of etc/config.pl. You should only do this after talking with Denise and/or Mark about it, though, and be sure to note that you did this in the comment you make when you upload your patch to the bug you're fixing, because Mark doesn't allow patches to overwrite the config files on Dreamwidth itself and will have to manually add the line after the code push where your patch goes live.