Take the 2-minute tour ×
WordPress Development Stack Exchange is a question and answer site for WordPress developers and administrators. It's 100% free, no registration required.

I'm using Settings API and I can't get checkboxes to work, if they're set to "false" they're not even being $_POST and that's the point.

Stephen Harris & Chip Bennett explained it, but I believe their way is not simple enough (especially for me, not PHP-guy at all). Do I REALLY need a few custom PHP functions and custom-named submit buttons for every form just to get this simple thing working?

My settings look much like:

register_setting('XX_theme_settings', 'XX_theme_settings', 'setting_validate' );

add_settings_section('theme_options', 'Theme Options', 'theme_options_generate', 'page1' ); 
add_settings_field( 'XX_Option1', 'Option 1', 'checkbox', 'page1', 'theme_options', 'XX_Option1', $args = array('id' => 'checkbox1', 'type' => 'checkbox') );
add_settings_field( 'XX_Option2', 'Option 2', 'checkbox', 'page1', 'theme_options', 'XX_Option2', $args = array('id' => 'checkbox2', 'type' => 'checkbox') ); 

Then I generate checkboxes with this callback function:

function checkbox($args) {
    $options = get_option('XX_theme_settings');
    echo '<input type="checkbox" name="'. $args['id'] .'" value="true"'; if($options[$args['id']]==true) { echo 'checked="checked'; }; echo '/>';
    echo $args['type'];  
}

Now, everything I need is a good validate callback:

function setting_validate($input) {
   // Firstly it should find all fields of type == "checkbox" 
   // (I'm not sure why should I check which field was just being sent, 
   // is updating all the checkboxes from different sections a big no-no?
   // it is much easier indeed.
   // Now set the ones missing to false/0 and the rest to true/1.
   // Then merge everything like below:

   $options = get_option('XX_theme_settings');
   $merged = array_merge($options, $input);  
   return $merged;  
}

So the question is: how to list all Settings Api checkboxes and then set the right ones to true?

I guess it'd look something like that:

$options = array(
        array(
            'id' => 'checkbox1',
            'type' => 'checkbox',
            'page' => 'page1',
         ),
        array(
            'id' => 'checkbox2',
            'type' => 'checkbox',
            'page' => 'page1',
         ),
);

function setting_validate($input) {
   foreach($options as $option) {
     if($option['type'] == "checkbox") { 
        //set it to 1 if sent
     }
   }

   $options = get_option('XX_theme_settings');
   $merged = array_merge($options, $input);  
   return $merged;  
}

Thanks :)

Here's how Chip Bennett does it exactly, but even with all these great comments I can't get how it exactly works.

share|improve this question

1 Answer 1

up vote 3 down vote accepted

If the setting in question is $setting, and is a checkbox type, you validate it like so:

<?php
$valid_input[$setting] = ( isset( $input[$setting] ) && true == $input[$setting] ? true : false );
?>

In this case, $input is the form data passed to the validation callback, where $input is an array-of-arrays. The validation method is known as whitelisting, where the current settings array is called (in this case, as $valid_input), and each setting in the settings array is only updated if the value in $input[$setting] passes the validation.

With checkboxes, if the checkbox isn't set, then the setting itself doesn't get populated in the $input array. So, the first step to validate it is to determine if it's been set in $input. The second step is to ensure that the value that is set is true (or 'true', or 'on', or whatever it is to which you set the checkbox value in the settings form). If both those conditions are met, return true; otherwise, return false.

See: it's quite simple, really. :)

Edit

Regarding this:

function setting_validate($input) {
   foreach($options as $option) {
     if($option['type'] == "checkbox") { 
        //set it to 1 if sent
     }
   }

   $options = get_option('XX_theme_settings');
   $merged = array_merge($options, $input);  
   return $merged;  
}

...that's not exactly the way you want to do it. You want to limit the return value to valid options; that is, you want to return, explicitly, the settings that you know you've defined. If, somehow, someone can populate $input with additional data - i.e. malicious code - your method would simply pass that additional data right into the database.

Don't do an array_merge(). Update each $valid_options[$setting] separately/individually, and only ever return $valid_options.

Here's the process:

  1. Define the currently valid data:

    $valid_input = get_option( 'XX_theme_settings' );
    
  2. Update the currently valid data with $input only if $input passes your validation/sanitization.
  3. Then return the updated, currently valid data.

If the fields are being generated dynamically, then you should also step through them dynamically, in your validation callback. You have this correct, with foreach( $options as $option ).

Putting it all together might look like this:

<?php
function setting_validate( $input ) {
    // Get current setting values
    $valid_options = get_option( 'XX_theme_options' );
    // Get option parameters array
    // Note: XX_theme_get_option_parameters() function
    // should be defined to return the array you've 
    // defined for $options
    $options = XX_theme_get_option_parameters();
    // Now step through the option parameters,
    // and validate each $input[$option]
    foreach( $options as $option ) {
         // If $option['type] is a checkbox
         if( 'checkbox' == $option['type'] ) { 
             // verify that $input[$option] is set
             // and is set with a valid value;
             // if so, set $valid_input[$option] to 1
             $valid_input[$option] = ( isset( $input[$option] && true == $input[$option] ? 1 : 0 );
         }
     }
     // Return the updated $valid_input array
     return $valid_input;
}
?>
share|improve this answer
    
Chip Bennett, it's all becoming clearer now, I'm a bit scared when it comes to editing validation callbacks (see wordpress.stackexchange.com/questions/43749/broken-settings-api ), so I'll ask before doing - is this code valid: pastebin.com/5fmqWkDA ? Of course fields are being generated dynamically based on $options arrays. Thanks a lot, you're really patient ;) –  Wordpressor Feb 28 '12 at 2:14
1  
See updated answer. I've tried to step through your code, rearranging as necessary. –  Chip Bennett Feb 28 '12 at 2:38
1  
@ChipBennett You are the Settings API boss for true. –  Brian Fegter Feb 28 '12 at 3:10
    
It still doesn't save checkboxes, XX_theme_get_option_parameters() returns $options array, but nothing happes when I submit data. When I tried adding another if statement, like: "else if ('textarea' == $option['type']) { $valid_input[$option] = wp_filter_nohtml_kses( $input[$option] ); } I'm getting tons of ": Illegal offset type" errors. –  Wordpressor Feb 28 '12 at 12:57
    
The next thing to look at, then, is your setting callback. What are the contents of $args passed to the checkbox field callback? –  Chip Bennett Feb 28 '12 at 13:07

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.