The essence of plugins is giving to WordPress users more control over their blog, that is, most of the time, more options. Typically, a plugin adds a page under the Settings menu, where you can modify the options (see this article on register_setting() for best practices).
But if you think about multi user blogs, it can make sense to implement per user options instead of "global" settings. And guess what? It's dead easy.
First, a few theory, then a complete example. Scroll down if you're the kind of guy who likes code, not explanations :)
Modify the "Profile" page
What we are going to do is play with the action hooks provided by file wp-admin/user-edit.php to add some fields to the profile page, then save them.
To add content (ie fields, checkboxes, texareas…) to the profile page, you can use any of the 3 actions:
- personal_options: append content to the "Personal Options" block
- profile_personal_options: add content after the "Personal Options" block (like add a whole new custom block)
- show_user_profile: add content right before the "Update Profile" button
For instance, to add content within the "Personal Options" block, you simply need to do something like:
- add_action('personal_options', 'ozh_personal_options');
- function ozh_personal_options() {
- echo "<p>Content added by action 'personal_options'</p>";
- }
These action hooks will pass one parameter to your function (that is ozh_personal_options() in the above example) containing a WP_user object.
Save custom per user data
Simply adding fields and pressing "Update Profile" won't do, you need to tell WordPress what you want to save. Hook into action personal_options_update and sanitize, I mean, SANITIZE, the POSTed data. This action will pass the user ID as a parameter to your custom function. Example:
- add_action('personal_options_update', 'ozh_save_user_setting');
- function ozh_save_user_setting( $user_id ) {
- $option = ( $_post['somecheckbox'] == 'yes' ? 'yes' : 'no' ); // sanitize: accept only 'yes' or 'no'
- update_usermeta( $user_id, 'some_user_options', $option );
- }
Complete example of a plugin with per user setting
Let's make a dummy plugin that will allow registered users of a blog to be nagged by a silly javascript alert box on every admin page they'll visit.
- <?php
- /*
- Plugin Name: Example plugin - Per User Settings
- Plugin URI: http://planetozh.com/blog/
- Description: Add a silly per user setting to your <a href="profile.php">Profile</a> page
- Author: Ozh
- Author URI: http://planetozh.com/
- */
- // Add a custom field to the form in "Profile"
- function ozh_user_setting_alert_box($user) {
- ?>
- <tr>
- <th scope="row">Add Alert Box</th>
- <td><label for="ozh_add_nag">
- <input name="ozh_add_nag" type="checkbox" id="ozh_add_nag" value="1" <?php checked('1', $user->ozh_add_nag); ?> /> Add a silly and annoying alert box on each admin page
- </label></td>
- </tr>
- <?php
- }
- // Handle data that's posted and sanitize before saving it
- function ozh_save_user_setting_alert_box( $user_id ) {
- $ozh_add_nag = ( !empty($_POST['ozh_add_nag']) ? 1 : 0 );
- update_usermeta( $user_id, 'ozh_add_nag', $ozh_add_nag );
- }
- // Now, the per user behavior itself: add the silly alert box if applicable
- function ozh_get_user_setting_alert_box() {
- if( get_user_option('ozh_add_nag') ) {
- ?>
- <script type="text/javascript">
- alert("Annoying, isn't it?");
- </script>
- <?php
- }
- }
- // Hook everything
- add_action('personal_options', 'ozh_user_setting_alert_box');
- add_action('personal_options_update', 'ozh_save_user_setting_alert_box');
- add_action('admin_head', 'ozh_get_user_setting_alert_box');
- ?>
For your convenience, the above plugin example and a few more inline comments is available here (rename as .php)
Best practices
A few things you'll want to do:
- Visual integration: use the same markup and CSS classes than the latest WordPress as of date to add rows and fields. Your plugin must add content to the profile page as if it was a built-in option. I hate it when plugin options look like weird plugin option. It must look like WordPress.
- Data sanitization: don't save blindly and assume everything posted will be stupid or malicious. If you're expecting an integer, use intval(). If you're expecting one value from a set, explicitely test for each value. If you're expecting free text including HTML, use esc_html(). And so on. Sanitize everything.
- Data concatenation: if you're going to add several options, please, put them in one array and save only this one entry.
- Wise implementation: sometimes it just makes sense to have a standalone plugin option page with global settings instead of per user settings. The typical WordPress blog is a single user blog.
Shorter URL
Want to share or tweet this post? Please use this short URL: http://ozh.in/rq
Thanks for this great article..
There's a fourth place on the Profile screen where you can add fields.
By filtering 'user_contactmethods' you can quickly add a text input field to the Contact Info section. You can also use the filter to remove or rename the existing fields if so inclined.
Here's some example code:
function my_user_contactmethods($methods){
$methods['phone'] = 'Phone Number';
return $methods;
}
add_filter('user_contactmethods','my_user_contactmethods');
The above code will add a 'Phone Number' text input to the Contact Info section.
Note that you still have to include the code to manually update the user meta when the form is submitted, as in Ozh' examples.
I am using you wordpress admin menu plugin and was wondering if it is possible to ad an option to sort the menu items!
Thanks. Love the plugin!
Jerry
I cant seem to get it to work on multiple authors in 3.0
Hi!
I want to write a simple plugin for my WordPress blog but I didn't find any documentation for what I need.
I want to have a settings/options page to save each user's website URL (by user ID) on a separate admin menu page, not on the Profile page.
I want to give each Logged In user the possibility to save and see the settings page with their individual options saved.
Can you post on your website an example, please?
I would appreciate if you send me a link to an example or tutorial regarding my problem.
Thanks!
Thanks for showing your code. I actually use something similar to what you showed to prevent registered users from seeing a part of the dashboard that should be limited to admins!
Wow I just noticed the nifty flag plugin you have beside each commenter's name. Can you please forward me the name of that? I think it would be a wonderful addition to my site! Thanks!
John ยป My own plugin IP to Nation
Thanks Ozh, I shall definitely check it out. It will be so handy for my site!
I always wondered how these things are really done. Thanks for showing! Now I am sure I will never be able modify any code to adjust it to my needs. I shall always ask for expert help. Thanks once more!
This is awesome. Is there a way to default it checked, so when the plugin is on, all users are defaulted to it checked and "on", but then they can go to their profile to turn it off?
Thanks! :)
Hi Ozh,
I know this is a pretty old post. Hope you will still read it though.
Could you point me in the right direction of writing a plugin for users instead of admin?
Thanks a bunch!