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. dandy says:

    @Kaibone Thanks for your prompt reply. I really appreciate your help, but somehow it didnt worked. But it showed me a direction though.

    the register_setting() method creates a new entry in db. No value parameter is attached to this method.

    What i did was to loop through the $_POST array and use update_option in that loop. Like

    1. foreach($_POST as $field =&gt; $value) {
    2.     update_option($field,$value);
    3. }

    This worked. Thanks alot for your help.
    Regards.

  2. Francesco says:

    Nice article, but there is a thing I don't get it. In the wordpress codex reference, it does this example:

    register_setting( 'my_options_group', 'my_option_name', 'intval' );

    my_option_name looks a scalar here to me, hence the intval used to sanitize.

    In your article you use an array instead. Doesn't it make the pourpose of register_setting less powerfull? You're compacting a lot of settings inside an only one setting that wordpress is aware of.

  3. Hikari says:

    Francesco, an option entry can hold a unique option or an array, array is serialized automatically by WordPress.

    OZH's exemple is great, because it teaches us how to hold a bunch of options in a unique array and submit it as POST automatically.

    register_setting() is meant to allow WordPress to handle options saving from admin pages automatically. If we didn't do it as in his exemple, we'd need to add a function to convert different variables into a single array to be stored, which would make it much less automatic.

    When you have a bunch of options, always try to store them in array, instead of creating a bunch of wp_options entries and using a SQL query for each of them.

  4. Gerasimos says:

    How can we handle a select tag with the ability to select multiple items using the register_setting() ?

  5. prion says:

    even after reading the post and going through the sample options , i still cant retrieve the options. I am using the example to make my theme options using settigns api, how do i retrieve it? Somebody please help. :(

  6. darrinb says:

    does anyone know how to incorporate an error message using register_setting()? I have a callback function that checks to see if a value of an option already exists and if so, prevents the user from overriding it. I can prevent the override, but I can't display an error message. Additionally, WP shows the "settings saved" message.

    This is the code:

    1. // Sanitize and validate input
    2. function azs3_upload_pages_validate($input) {
    3.    
    4.     $upload_pages = '';
    5.     $upload_pages .= get_option('azs3_upload_pages');
    6.  
    7.     if ( isset($_POST['delete_upload_page']) &amp;&amp; '' != $_POST['delete_upload_page'] ) {
    8.         $upload_page = $_POST['delete_upload_page'];
    9.         if( '' != $upload_pages ) {
    10.             $upload_pages = explode (',', $upload_pages);
    11.             foreach ($upload_pages as $k =&gt; $v) {
    12.                 if ($v == $upload_page)
    13.                 unset($upload_pages[$k]);
    14.             }
    15.             $upload_pages = implode(',',$upload_pages);
    16.         }
    17.     } else {
    18.         if( '' != $upload_pages ) {
    19.             $assigned_pages = explode (',', $upload_pages);
    20.             if( in_array($input, $assigned_pages) ) {
    21.                 $errors = new WP_Error();
    22.                 $errors-&gt;add('pageexists', __('Page already exists.'));
    23.                 return $upload_pages;
    24.             } else {
    25.                 $upload_pages .= ','.$input;
    26.             }
    27.         } else {
    28.             $upload_pages = $input;
    29.         }
    30.     }
    31.     return $upload_pages;
    32. }
  7. Ozh says:

    darrinb » look at function add_settings_error()

  8. darrinb says:

    @Ozh: you are a life-saver. never would have found that!

  9. Unes says:

    Thank you for the very details!

  10. Eric says:

    You, sir, are awesome. Thanks.

  11. alex says:

    Any idea where I could find a list of all the available wordpress sanitize functions (like wp_filter_nohtml_kses)? Thanks!

  12. Ozh says:

    alex » I don't think there is such a list. Check the Codex maybe. Or wait for my book which has a lengthy chapter on security :)

  13. DrLightman says:

    @alex: wait for the Ozh book (recommended) or explore the WP source code yourself, it always works :)

  14. alex says:

    I see. Thanks for the replies – looking forward to your book, Ozh.

  15. steve says:

    Hi, thanks for the article.
    Not sure what you mean by saving your options in a "single db entry". Does this mean a single record in the table that wp uses for options?

    Also, how would you save multiple options. I want a user to be able to save multiple css properties for a popup div.

    Would you call
    register_setting( 'myplugin_option_group', 'height' );
    register_setting( 'myplugin_option_group', 'border-color' );

    etc..
    Thanks again
    Steve

  16. steve says:

    You can ignore that last comment.. i see how you're putting them in an array, and they end up in a single record.

  17. Caballero says:

    Hi!!
    I have 2 noob questions…

    Where are saved the options in DB? Which table name?

    And in your example, What is the options.php file? What is it for?

  18. Steve says:

    Caballero,
    Just in case ozh couldn't answer:

    1. table: wp_options

    2. options.php is already part of the WordPress core. So specifying that in action is what you need to do, to get WP to call itself and save your options

    -Steve

  19. Ozh says:

    Caballero » no offense but I don't think you're the intended audience of this article…

  20. Caballero says:

    Hahaha, no problem. I know I should learn some basics first

  21. Caballero says:

    I know you maybe don't want to answer but…
    I have managed to make all of this article work,
    I have checked that the options are stored in the DB.

    but if they are stored in a single DB entry, how can I use them?

    Is this correct?–>

    if ($input['option1'] == 1){
    add_action('wp_head', 'insert_css1');
    }
    else {
    add_action('wp_head', 'insert_css2');
    }

  22. Caballero says:

    I know you maybe don't want to answer but…
    I have managed to make all of this article work,
    I have checked that the options are stored in the DB.

    but if they are stored in a single DB entry, how can I use them?

    Is this correct?–>

    1. if ($input['option1'] == 1){
    2.    add_action('wp_head', 'insert_css1');
    3. }
    4. else {
    5.    add_action('wp_head', 'insert_css2');
    6. }
  23. Caballero says:

    Solved myself!! this was the solution:

    1. $options = get_option('dblog_sample');
    2. if ( $options['option1'] == "1" ){
    3.    add_action('wp_head', 'donostiblogs_css');
    4. }
    5. else {
    6.    add_action('wp_head', 'donostiblogs_css2');
    7. }

    thanks a lot for your post!!!
    (I will try not to bother you more) sorry

  24. Hikari says:

    Caballero, this tutorial teaches how to use a WordPress feature to automate settings handled by options pages.

    In this exemple, you store all settings in a unique option, that's stored in a row in wp-options table. It uses an array datatype, and each element of that array is a setting.

    I have a framework plugin that also handles markup and other stuff, and we have to do is build an array that's used to create the options page. We don't even have to know stuff teached in this tutorial, all we have to know is the existance of a couple of variables where stuff is stored. Take a look: Hikari Tools Framework.

  25. James says:

    Just one quick question, in your post you use settings_fields() with just one argument, in the codex there is no settings_fields() function, there is a settings_field() but it has more than one argument to it, so there must have been some changes to the arguments I'm guessing since this was written, any way I can get an example of how this works with the new arguments it needs, i'm not 100% sure what the arguments are based off the small codex entry.

  26. Ozh says:

    James » The Codex is nice for starters, but read the source to understand the hows and whats.

  27. JoS3 says:

    hi there , i´m a litle bit confused here guys , hope you all can help me , ok , here is the deal : i wonder if its necesary to do all the registry_settings when i actually pretend to have a particular form that will store its post info into some new tables my plugin uses … so i dont know if i actually need to use the registry_setting , add_option duo cuz in fact i dont need anything to be stored in the default wp database , only in my new table , dunno if u guys get my point … cheers

  28. wpnewbie says:

    how do i go about validating multi selected checkboxes ? which i have stored in an array from get_pages() wp function

  29. Jürgen says:

    Hello, great tutorial.
    Maybe you could mention function add_settings_error which can be used inside the sanitize callback function to give out error messages to the user.

  30. mike says:

    hey all, I have

    register_setting( 'product_colorsoptions_options', 'product_colors', 'product_colorsoptions_validate' );

    settings_fields('product_colorsoptions_options');
    $options = get_option('product_colors');

    register_setting and settings_fields are set with the same val, which I took to be the correct approach but Im getting the following error

    Error: options page not found.

    as a result of

    !isset( $whitelist_options[ $option_page ]

    in options.php

    any feedback greatly appreciated

  31. Greg Turner says:

    Thank you very much for this article. Quick question about something. The register_settings and add_settings_xx calls are all made in a function that is attached to the admin_init hook. The codex says this hook "Runs at the beginning of every admin page before the page is rendered." From this I conclude these calls are being made multiple times, whenever the admin page is rendered. Which does not make sense. Seems to me, these calls only need to be made once, perhaps in the register_activation_hook function. What am I missing? Thanks again.

  32. Jürgen says:

    Hello,
    thanks for your advice on this topic.
    But there is still on question left:
    How to I report the user about invalid input values?
    It's ok to use the sanitize function, but this will not give feedback on errors.
    Or did I miss something?

  33. Nabha says:

    Jurgen, you want to use add_settings_error() for that. (Just discovered it in Professional WordPress Plugin Development, in Chapter 7, in the section on the settings API.)

    This page has a little documentation on it:
    http://hitchhackerguide.com/2011/02/11/add_settings_error/

  34. Juergen says:

    Hello, Nabha,
    thanks for the hint.

  35. Tim says:

    This helped me a ton, since I got nowhere with the code from the wordpress.org documentation. Not sure what's up with that, but thank you!

  36. GB says:

    Thx – clear article.

    I am using
    <?php wp_nonce_field('update-options');
    and a hidden field with the name "page_options" – the 2.7 way for backwards compatibility.

    And escaping my input values.

    Any thoughts on a better way to do this and still keep 2.x compatibility?

  37. steve says:

    Ozh, I was wondering if you'd ever encounter this situation.
    Simply, that in your admin settings page validation function, somehow there is a carriage return (slash and an N) tagged to the end of every value.

    So when I test for an is_int, it never returns true.. because there's actually a 2carriagereturn, not 2.

    I did a error_log(print_r($input,true)) to see what was going on.

  38. steve says:

    sorry you can ignore that.. the \n's come from using error_log (if I just echo the individual array elements, there's no carriage)..

    is_int still doesn't work, but is_numeric returns the correct answer so I'll use that.

  39. Smrth says:

    how would you validate if given is number between 1 and 600?

  40. Yasen Vasilev says:

    Cool! But I think I'm doing something wrong. What if I don't use wp_options, but my own table? What code should I use to get the possibility to write in that table from the settings page? I tried the global wpdb and SQL query in the settings page, but it crashes?

  41. Anmol says:

    Thanks a lot man for the wonderful post.

    Used the tutorial and implemented custom skins for my client with radio buttons.

    Also created a profile which will be displayed on the home page.

    Keep up the good work.

  42. Denny Cherry says:

    Thank you so much for posting this. You have no idea how close I was to punching my monitor until I found this. I'm a first time PHP/WordPress plugin author and this really cleared it up for me.

  43. Spoygg says:

    Just to say a big thank you :) This is by far the most simplest way to add options to plugin. Lately I had a need to add options to my plugin that I use throughout my sites and I was dreading that task… And than I found this great little article, simplicity FTW! Thaaaaaanks :)

  44. Eoin H says:

    Quick question,

    If I want to put an 'upload logo' file field in, how would I do this, or mor to the point, is there a function I need to add handle file uploads?

    Cheers

  45. ItKnol says:

    Dear Ozh,

    Thanks a lot for this tutorial. Very helpful and well presented.

    I would just like to add that, IMO, echoing values for the input fields should include a check like:

    if(isset($option[sometext])):echo $option[sometext];endif;

    In order to avoid Undefined Index notices on first run of the settings page.

    Kind regards,
    ItKnol

  46. Flynn says:

    Simple is good.

    This, IMHO, is by far the best WP "Options Framework" on the internet.

    add_settings_field(), add_settings_section(), do_settings_sections() and do_settings_fields() do very little other than limiting the layout of the options page. I love how you simply ignored them.

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 ?