In: , , ,
On: 2009 / 05 / 05
Shorter URL for this post: http://ozh.in/lp

In the upcoming WordPress 2.8 there's an interesting function set meant to help authors manage their plugin custom options. In a nutshell: whitelist your options, define how you want them to be validated, and just lean back and rely on the API to handle everything for you.

Your new best friend is function register_setting(), and I'm going to recapitulate how it's supposed to be used.

The (very) old (deprecated) way (that sucks)

If you began coding plugin a long time ago, you may have sticked to the habit of doing everything yourself, re-inventing and re-coding the wheel everytime.

Does something like checking for $_POST on your plugin admin page ring a bell? Time to evolve to a hassle free way of coding stuff.

The (new) register_setting() way (that pwnz)

The concept is the following: do the little tasks, let WordPress manage the dirty job.

– on init, tell WordPress that you're going to use some new options
– optional but cool, tell WordPress what function you'd like to be used for data validation (the user is supposed to enter text on your plugin admin page? Make sure it's only text, then)
– optional but cool, store all your options in one DB entry (yeah, those who've been reading this blog for a while know that it's my favorite pet peeve)
– don't handle POST data, let WordPress do it
– don't update/create the DB entry in the options, let WordPress do it
– don't bother with all the security, nonces, anti XSS stuff you have to throw in, let WordPress do it

Code, dissected

First, tell WordPress that you're going to use new options

  1. add_action('admin_init', 'ozh_sampleoptions_init' );
  2. function ozh_sampleoptions_init(){
  3.     register_setting( 'ozh_sampleoptions_options', 'ozh_sample' );
  4. }

This function says: I'm going to need a new set of options, named 'ozh_sampleoptions_options', it will be stored in the DB entry 'ozh_sample'. There can a third parameter, a callback function to sanitize data: we'll see this later.

Then, we need to draw the plugin option page itself. Nothing really new here, except just one new thing. The function that echoes the admin form would be something like:

  1. // Draw the menu page itself
  2. function ozh_sampleoptions_do_page() {
  3.     ?>
  4.     <div class="wrap">
  5.         <h2>Ozh's Sample Options</h2>
  6.         <form method="post" action="options.php">
  7.             <?php settings_fields('ozh_sampleoptions_options'); ?>
  8.             <?php $options = get_option('ozh_sample'); ?>
  9.             <table class="form-table">
  10.                 <tr valign="top"><th scope="row">A Checkbox</th>
  11.                     <td><input name="ozh_sample[option1]" type="checkbox" value="1" <?php checked('1', $options['option1']); ?> /></td>
  12.                 </tr>
  13.                 <tr valign="top"><th scope="row">Some text</th>
  14.                     <td><input type="text" name="ozh_sample[sometext]" value="<?php echo $options['sometext']; ?>" /></td>
  15.                 </tr>
  16.             </table>
  17.             <p class="submit">
  18.             <input type="submit" class="button-primary" value="<?php _e('Save Changes') ?>" />
  19.             </p>
  20.         </form>
  21.     </div>
  22.     <?php  
  23. }
  24. [/php]
  25.  
  26. Notice the <tt>settings_fields()</tt> call. This tells WordPress to add all the hidden fields our form needs (nonce, referrer check...), and that we're going to use our option set previously defined as 'ozh_sampleoptions_options'.
  27.  
  28. And that's all, basically. You don't need to check if user submits the form, to check whether the options need to be updated or not, to handle things passed to $_POST. WordPress takes care of it.
  29.  
  30.  
  31. <h2>Data sanitization</h2>
  32.  
  33. Function <tt>register_setting()</tt> accepts 3 parameters: the option group name, the option name to save and sanitize, and a callback function that does the sanitization.
  34.  
  35. If you want the user to submit integers, and only integers (say, they age), you would for instance use:
  36. [php]
  37. register_setting( 'my_options', 'your_age', 'intval' );

If you're allowing safe text with a limited set of HTML tags:

  1. register_setting( 'my_options', 'your_bio', 'wp_filter_nohtml_kses' );

Now, in the previous example, since we want to store everything in a single DB entry, we'll define our own validation function:

  1. function ozh_sampleoptions_init(){
  2.     register_setting( 'ozh_sampleoptions_options', 'ozh_sample', 'ozh_sampleoptions_validate' );
  3. }
  4.  
  5. // Sanitize and validate input. Accepts an array, return a sanitized array.
  6. function ozh_sampleoptions_validate($input) {
  7.     // Our first value is either 0 or 1
  8.     $input['option1'] = ( $input['option1'] == 1 ? 1 : 0 );
  9.    
  10.     // Say our second option must be safe text with no HTML tags
  11.     $input['sometext'] =  wp_filter_nohtml_kses($input['sometext']);
  12.    
  13.     return $input;
  14. }

All wrapped up

For your convenience, you'll find all the code of this article in the following plugin: ozh-sampleoptions-plugin.php (rename as .php)

Happy coding!

Shorter URL

Want to share or tweet this post? Please use this short URL: http://ozh.in/lp

Metastuff

This entry "Handling Plugins Options in WordPress 2.8 with register_setting()" was posted on 05/05/2009 at 12:50 pm and is tagged with , , ,
Watch this discussion : Comments RSS 2.0.

96 Blablas

  1. scribu says:

    Neat tutorial.

    One important correction though:

    This can be done now, in WordPress 2.7 :D

  2. Ozh says:

    scribu » indeed, except that it's not mandatory in 2.7 if I'm correct. In 2.8 you *have* to white list your options.

  3. scribu says:

    Not true. I've tested some of my plugins on WP 2.8 that use the "deprecated" way and they still work.

  4. scribu says:

    …but you *do* have to whitelist options if you want to use options.php to update them.

  5. Ozh says:

    scribu » That's what I meant, yeah. Old way still works (hopefully damn it, don't want to rework all my old plugins) but whitelisting is mandatory to use options.php and let WP do the job

  6. Jermaine says:

    Thanks for this tutorial! Was playing around with custom options this evening and this helped to clear a few things up. The custom function for sanitizing is a great idea! :D

  7. Stephen R says:

    WordPress is my hobby — at work I have to work with Drupal. Every time I see something like this it reinforces just how primitive DP is compared to WP. A shame WP is so strongly locked into the "blog" format or I could have convinced my company to use WP instead….

    Oh yeah… . good tutorial. :)

  8. Tweak says:

    Great tutorial
    Thanks

  9. […] 9. Handling Plugin Options in WordPress 2.8 – PlanetOzh […]

  10. […] With WordPress 2.8 comes the register_setting() function, which just might make things a bit easier. […]

  11. […] to a switch to the probably-recommended method of doing settings pages this version requires WordPress 2.8 or […]

  12. Ade says:

    Thanks for the article!

    Just one question – how does one set default options/settings? Using add_options(), ie the old way? Or am I missing something obvious? :-)

  13. Ade says:

    After some investigating I managed to find the answer – yes, add options defaults using add_option().

    Something else I discovered is that if you want to register more than one set of serialized options (ie have more than one wp_options db entry), use the same options group name in each call to register_settings. Then in the admin page form only one call to settings_fields() is required, ie like this:
    In the plugin's admin init function:

    1. register_settings( 'all_my_options', 'my_options_1, 'my_options_1_validate');
    2. register_settings( 'all_my_options', 'my_options_2, 'my_options_2_validate');

    And in the admin form:

    1. settings_fields('all_my_options');

    Hope this is useful to someone.

  14. […] 5.Handling Plugins Options in WordPress 2.8 with register_setting() […]

  15. Ajay says:

    Wouldn't the plugin need to contain the old code to maintain backward compatibility?

  16. Ozh says:

    Ajay » If backward comp is your thing, sure. I dropped this a long time ago. It's way too cumbersome to maintain old code, and doesn't not encourage people to upgrade their blog.

  17. Ajay says:

    I agree totally!
    I wish all the users did.

    What I can do is update my plugins with the new code, and state that those interested in "not upgrading" to the new WP, can use the old version of the plugin, with no support from my part.

    Just one doubt in the code:

    What is the purpose of the $options variable? Or, is this something that is required, since you don't use it specifically elsewhere

  18. Ajay says:

    Ok, the code didn't come.

    It's the two lines

    1. &lt;?php settings_fields('ozh_sampleoptions_options'); ?&gt;
    2. &lt;?php $options = get_option('ozh_sample'); ?&gt;
  19. Viper007Bond says:

    Ajay,

    That's so that his form can be filled in with the existing values.

  20. Ajay says:

    Hi Viper,

    I got that. However, $options doesn't seem to have been used anywhere else?

    Or am I mistaken about this?

  21. Nice example. Much more helpful than the limited docs for this on wordpress.org.

  22. Is _nonce no longer needed with this new method?

  23. Ozh says:

    Philip M. Hofer (Frumph) » As I write in this guide, this method inserts everything you need including nonces

  24. Swear I didn't see that the first time I read it =) Thanks Ozh this will definately come in handy and really well described.

  25. […] 5.Handling Plugins Options in WordPress 2.8 with register_setting() […]

  26. Nico says:

    Hi !
    I'm beginning in developping WordPress plugins and in programming PHP too by the way. I wish I could have found your blog earlier ! Full of clear articles and made of good philosophy about developping WP plugins. Compared to WordPress populartiy, there's not much on the web.
    I have a maybe stupid question about this register_setting function, how do you handle error messages for users in your example ? If you need to return messages like "enter an Int" or "enter a valid email" or whatever validation you need ?
    Thanks for your answer

  27. Ozh says:

    Nico » The best way, from the user's point of view, is to have real time validation using javascript (like, you enter an integer where a string is expected and the field turns red and says "ho noes". There are several client side JS libraries that validate forms). The easiest way, from the coder's POV, is to simply echo a message in the function that validates every time something doesn't pass the test.

  28. Nico says:

    Merci pour la réponse :)

  29. Ade says:

    Regarding user feedback messages (eg a form field fails a validation test in the register_settings callback function), Ozh said:

    The easiest way, from the coder's POV, is to simply echo a message in the function that validates every time something doesn't pass the test.

    I found this doesn't work. There is a redirect before the settings page is sent back to the browser after running the callback, which means echo messages won't be seen. I found a clunky way around this (involving saving an error code as a plugin option, and then hooking into admin_notices and extracting the error code from the plugin's options). Seems overly complicated, so I'll probably look for a javascript solution instead.

  30. WebDev says:

    Thanks in advance :) I'm collecting useful WordPress plugin development techniques to my upcoming Twitter plugin. I've found lots of cool information in your blog!
    Thank you!

  31. Brenton says:

    I'm all for consolidating multiple plugin-related settings into one (wp_options) database entry using the method suggested above, except for detail. None of the filter functions or sanitize functions appear to work because the name of the option is no longer just "option1" (to use your example above) but is now "ozh_sample[option1]". How can you register this new name with a filter? Previously you would use:
    add_filter('sanitize_option_option1', myFunction, 10, 2);
    but the new approach would require:
    add_filter('sanitize_option_ozh_sample[option1]', myFunction, 10, 2);
    which doesn't appear to work.

    Any ideas?

  32. Brenton says:

    I got it. Sorry for the question. Somehow, by writing out my question (and then reading my own post) I saw the answer. Hooking into the option filters under this new scheme (to use the example above) would simply be:

    add_filter('sanitize_option_ozh_sample', myFunction, 10, 2);

    myFunction() would then need to pick its way through the supplied array looking for 'option1' and then filter its value appropriately.

  33. Lopo Lencastre de Almeida says:

    I did it and with WP2.8.5 it says that it can't find options.php

  34. Ozh says:

    Lopo Lencastre de Almeida » So you did it wrong.

  35. Tony Dew says:

    Ozh: Thanks for yet another great tutorial. Very helpful!

    Ade: Yes, as a matter of fact, your tip on multiple sets of options was very helpful. Just what I needed, actually!

  36. Hikari says:

    Very interesting, I still didn't know about it!

    And I have a question, how about unstalling function? What is the best way of removing from database anything we created with

    1. register_setting()

    ?

    And what plugin do you use for this Posting code filter? :P

  37. Ozh says:

    Hikari » use delete_option() as usual. For code posting I use "ig syntax hiliter".

  38. Richard says:

    Hi Ozh, as always, wonderful tutorial. I'm having a slight problem using this method for 'select' form elements. I have the text and checkbox working just great, but when it comes to using a select and the selected() function, I just can't seem to get it to work – i.e. the value I select in the form just isn't saved.

    Would you be able to add to your example above by showing us how to use other form elements such as select and radio?

    Thank you very much in advance for any reply!

  39. Sergei Plaxienko says:

    It looks like code after "the admin form would be something like:" seems to have tags on lines 3 and 22.

    Or is it suppose to be like that?

  40. Sergei Plaxienko says:

    … I mean "wrong tags".

  41. Sergei Plaxienko says:

    Sorry, my fault. I've got the idea with php tags.

  42. Kaibone says:

    Maybe this is a silly question:

    I have successfully been saving the data that I need – this tutorial helped where the WordPress Codex was lacking. Thank you!

    Now, how can I retrieve this data for use within the rest of my plugin??

    Feeling noobish…
    -Kaibone

  43. Ozh says:

    Kaibone » just look at the example plugin provided…

  44. nn says:

    was usefull, thanks!

  45. Hi,

    Just a note to thank you for such a useful article. I am fairly new to wordpress development and was struggling to work out how to do settings for my app. Your example and explanation has saved me a lot of time.

    Andy

  46. Keith says:

    Hi,

    Great tutorial. I have everything working but one peice. (maybe out of scope for this article) But any help is appreciated.

    If your using the register_settings api and have only 1 database entry how would you set default options that would be set when the theme is activated. One of my options is to select a theme style. When first activating the theme no style is selected.

  47. This is a great article. You've explained things very well. Are you able to use this method to set different options/settings per page/post? If not or if so, how would that be done.

    Thanks for your help.

  48. dandy says:

    how can i use register_setting with ajax.

    like i've created a setting group

    register_setting('setting_1′,'simple_logo');

    how can i update it? is there any update_setting option?

    thanks.

  49. Kaibone says:

    @dandy: You could try using some variables:

    1. $setting = empty($_POST['setting']) ? 'setting_1' : $_POST['setting'];
    2. $logo = empty($_POST['logo']) ? 'simple_logo' : $_POST['logo'];
    3. register_setting($setting,$logo);

    Then when you run the ajax call, send 'setting' and 'logo' values through a POST method and the register_setting will use the 'updated' variables.

    Hope it helps! (untested)

Leave a Reply

XHTML: You can use these tags: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>
Gravatars: Curious about the little images next to each commenter's name ? Go to Gravatar and sign for a free account
Spam: Various spam plugins may be activated. I'll put pins in a Voodoo doll if you spam me.

Read more ?