Click here to go back to the previous section: The Panel
Please note that this documentation relates to Vanilla 1
A user preference in Vanilla is a user-defined customization of the interface. Users turn their preferences on and off from their account tab on the Forum Preferences form. The form contains a number of different headings and checkboxes underneath. As you come up with new features for Vanilla, you may want to offer users the ability to turn these preferences on or off. This is where you add that preference and it is super-duper easy.
A while back I wrote a “Quick Keys” extension that allows users to jump to different parts of the application by pressing ALT+[Key]. I didn’t want this option to have to be turned on for all users, so I created a new user preference to handle the switching on and off of this feature.
I won’t go into the details of how the QuickKey extension works, but I will explain how the QuickKey preference was applied. Take a look at extensions/QuickKeys/default.php on line 69:
// Add the QuickKeys setting to the forum preferences form if ($Context->SelfUrl == 'account.php' && $Context->Session->UserID > 0) { $PostBackAction = ForceIncomingString('PostBackAction', ''); if ($PostBackAction == 'Functionality') { function PreferencesForm_AddQuickKeysPreference(&$PreferencesForm) { $PreferencesForm->AddPreference('MenuOptions', 'UseQuickKeys', 'UseQuickKeys', 1); } $Context->AddToDelegate('PreferencesForm', 'Constructor', 'PreferencesForm_AddQuickKeysPreference'); } }
First I check to make sure that I’m looking at the correct page (account.php). Next I make sure that the user has a valid session because preferences only apply to signed-in, active users. Then I make sure that I’m looking at the “Forum Preferences” form (which has a PostBackAction of “Functionality”).
Once I know I’m looking at the right place in the application, I want to create a new checkbox option and add it to the preferences form. I do this through the use of Delegation. I’ve added a delegate call to the PreferencesForm control in the control’s constructor (a method that is called when the class is instantiated into an object. What I do next is write a function and attach it to this delegate.
As you can see, I gave my new function a pretty unique name. This is highly recommended so that as new functions are attached to delegates, there aren’t any name clashes. I named my function PreferencesForm_AddQuickKeysPreference The part before the underscore is the name of the control that contains the delegate I’m attaching to (PreferencesForm), and the part after the underscore is a unique name to describe the purpose of my function (AddQuickKeysPreference).
Any function called through delegation has one parameter passed in, and that parameter is the control from which the delegate is called, in this case the PreferencesForm. Now I have access to all of the properties and methods of the PreferencesForm control, so I just call the AddPreference method of the PreferencesForm control. That method is defined as follows:
AddPreference($SectionLanguageCode, $PreferenceLanguageCode, $PreferenceName, $RefreshPageAfterSetting = '0', $IsUserProperty = '0');
SectionLanguageCode is the code for the heading on the form under which I want my new preference to be placed. In this example, I wanted the quick keys preference to appear under a heading called ‘Menu Options’. (Note: This was a new heading and a new dictionary code, so I also needed to define this definition at the top of my extension file). PreferenceLanguageCode is the dictionary code for my new preference. I called mine UseQuickKeys and I added this dictionary definition to the top of my extension file also. PreferenceName is the name of my new preference as it will be stored in the user’s account with a true or false value associated with it. RefreshPageAfterSetting if set to 1 will make the form save itself and refresh afterwards if the user changes this preference. In this example I definitely wanted the quickkeys to be activated right away, so I made the form save and refresh here by setting this value to 1. Finally, IsUserProperty is a parameter used by the core Vanilla libraries to indicate that this preference is represented in the database by a column on the user table. In this case I was adding a brand new preference that is not a column on the user table, so I accepted the default of ‘0’ (false).
So now my function was written, but I still needed to attach it to the “Constructor” delegate of the PreferencesForm control. I did that with the following line:
$Context->AddToDelegate('PreferencesForm', 'Constructor', 'PreferencesForm_AddQuickKeysPreference');
Here I am calling the AddToDelegate method of the context object. I specify first the name of the control that I am attaching a delegate to: PreferencesForm. Next I specify the actual delegate I want to attach to within that control: Constructor. Finally I specify the name of my new function: PreferencesForm_AddQuickKeysPreference.
With that, I’ve added my new preference:
Now, when I click this checkbox for the first time it will add a new “UseQuickKeys” preference to my account and mark it as true or “on”. If I uncheck it, the UseQuickKeys preference will remain in my account, but it will be turned off.
While the concept of delegation might be a little difficult to grasp, you can certainly see and appreciate how easy it was to write this code and add a new preference to Vanilla.
The first step in creating a user preference is to come up with a distinct name for your preference so that it does not conflict with existing preferences. A surefire way to ensure that you do not encounter a conflict is to use your extension’s name as a prefix (ExtensionName_PreferenceName).
The second step in writing a user preference is deciding how you want to go about adding your preference. You can add to the forum preferences form as outlined above, or you can create your own control that defines the preference. You should be aware of the fact that the UserManager class (located at library/People/People.Class.UserManager.php) has a SwitchUserPreference method that allows you to define a new preference or alter an existing one:
$UserManager->SwitchUserPreference($PreferenceName, $Switch);
$PreferenceName is the preference name you want to define or manipulate, and $Switch is the new boolean (1 or 0) value to assign to the preference. This is the actual method called by the AJAX PanelSwitch function.
The SwitchUserPreference method always assigns the preference to the user account that calls the method. In other words, when clicking on one of these preferences, you can’t set another user’s preferences - you can only set your own.
This is really only for technically oriented people, but it might help you grasp preferences as a whole if you understand how they are saved to the database.
Whenever a user preference is defined using the UserManager’s SwitchUserPreference method, an associative array of PreferenceName & PreferenceValue pairs is built based on the user object’s Preferences array. If there is a new value being saved, it is added to the array, and if it is an existing value being updated, the array is updated. Then the array is serialized and saved into a single “Preferences” field in the user table for that user.
Every time a page loads in Vanilla, that single field is loaded into the session object and unserialized back out to the user object. Then when you call the User object’s “Preference” method, it looks for that key in the user’s Preferences array and returns the value if found or the default value if not found.
It’s a simple concept, and runs very quickly as opposed to a new table to hold user preferences. It also makes it so that extension authors can very easily add as many user preferences as they want to any installation of Vanilla.
Click here to read the next section on developing new extensions: Languages in Extensions