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 the theme options from the underscores (_s) WP theme as a base for my own theme options. If I wanted to insert the validation from the bottom function into the top function's $output array, how would this be done?

At the moment I seem to be replacing the entire array with my validation, rather than adding to it.

// the default validation function looks like this
function theme_options_validate( $input ) {
    $output = array();

    // standard validation goes here. I would like to add the validation in the bottom function into here

    return apply_filters( 'theme_options_validate', $output, $input );
}


// I want this function to make use of the apply_filters above so I can add to the validation without editing the top one
function add_validation( $input ) {

    $output[] = array(); // not sure about this, I thought I could add onto array using []

    // here I want to add some validation for a simple field named 'example'
    if ( isset( $input['example'] ) && !empty( $input['example'] ) )
        $output['example'] = wp_filter_nohtml_kses( $input['example'] );

    // pretty sure I have to return $output
    return $output;
}
add_filter( 'theme_options_validate', 'add_validation' );
share|improve this question
add comment

2 Answers

You want to manipulate and return the same input you have coming into the function. In your case that is $input. That is how filters work.

function add_validation( $input ) {
    // here I want to add some validation for a simple field named 'example'
    if ( isset( $input['example'] ) && !empty( $input['example'] ) )
        $input['example'] = wp_filter_nohtml_kses( $input['example'] );
    return $input;
}
add_filter( 'theme_options_validate', 'add_validation' );

If you return something other than what you start with you will be overwriting everything that came before your filter. You can do if you want, just be aware that it is likely to break things.

share|improve this answer
    
Doesn't seem to work. I'm not sure I follow why the $output['example'] = line is now $input['example'] =. My understanding was that you validate the $input and then the $output is the data sent to the DB. If I use my original validation, but within the top function (what I'm trying to avoid) then it stores to the DB fine. –  Andrew Dec 4 '12 at 5:54
    
Ok I think I got it, I need to keep it how I had it, return $output, but add $output to the function's parameters, then add a 10, 2 onto the end of my filter so the 2 parameters are accepts. Just going to do some more testing and then I'll update your answer and accept it, thanks –  Andrew Dec 4 '12 at 6:25
    
Sorry, I edited your answer but it didn't make it through peer review. –  Andrew Dec 4 '12 at 20:26
    
You shouldn't have to return a different variable. You can if you want, but either way you have to be aware of what you are altering or overwriting, or deleting. –  s_ha_dum Dec 4 '12 at 20:41
1  
The filter is applied to $output, and $output is the expected return value for a callback applied to the filter. But the original function helpfully exposes $input to the filter as well, and since the data to be manipulated are in $input, it must also be passed to the callback. –  Chip Bennett Dec 4 '12 at 20:43
add comment

Start with the Underscores apply_filters() call:

return apply_filters( 'theme_options_validate', $output, $input );

This says:

  1. The filter name is theme_options_validate
  2. The filter is applied to the $output content
  3. The $input content passed into the validation function can also be passed on to a callback

So, here's how it works:

  1. WordPress passes $input, which basically contains the $_POST data from the settings form, to the validation callback.
  2. The validation callback manipulates $input, to sanitize/validate it
  3. The validation callback stores the manipulated results of $input as $output
  4. The validation callback passes $output through the theme_options_validate filter
  5. The validation callback returns the filtered result of $output

So, when you write a callback to apply to the theme_options_validate filter, that callback receives and should return $output. That is: you're returning your manipulation of the already manipulated data:

function example_filter_theme_options_validate( $output ) {
    // Do stuff to $output
    // return $output
    return $output;
}
add_filter( 'theme_options_validate', 'example_filter_theme_options_validate' );

That's great, if you want to make a change to the already manipulated data; but if you want to add data, you can't do that using only $output. For example, if you've added a Theme option via Child Theme, that option won't survive the default validation callback, because that option won't have been whitelisted in the callback. That option will be in $input, but it won't be in $output.

In steps the additional option in the apply_filters() call:

return apply_filters( 'theme_options_validate', $output, $input );

By adding $input as an additional parameter, Underscores is helpfully passing $input to any callback that wants to use it. So, instead of this:

function example_filter_theme_options_validate( $output ) {
    // Do stuff;
    // return $output
    return $output;
}

Your function declaration will look like this:

function example_filter_theme_options_validate( $output, $input ) {
    // Do stuff;
    // return $output
    return $output;
}

Now, your function has access to both $output and $input, and you can then manipulate your custom Theme option from $input, and then add it to $output, thereby whitelisting it.

Note that it is imperative to specify the number of parameters in your callback, by modifying your add_filter() call:

add_filter( $filter, $callback, $priority, $parameters );

Since you're now passing two variables, you have to set $parameters to 2 (the default is 1):

add_filter( 'theme_options_validate', 'example_filter_theme_options_validate', 10, 2 );

Putting it all together:

// this works

function add_validation( $output, $input ) {
    if ( isset( $input['example'] ) && !empty( $input['example'] ) )
        $output['example'] = wp_filter_nohtml_kses( $input['example'] );
        return $output;
    }
add_filter( 'theme_options_validate', 'add_validation', 10, 2 );
share|improve this answer
1  
Yep, you figured it out! :) The original function returns (and applies its filter to) $output, but the data you want to manipulate are in $input. So, you must pass both to your callback, manipulate $input, add the manipulated result to $output, and then return $output. –  Chip Bennett Dec 4 '12 at 20:42
    
Awesome thanks. It all makes sense now. You don't want to know how many combinations I tried to get it working :) The 2 on the add_filter really tripped me up. –  Andrew Dec 4 '12 at 20:48
    
I edited your answer to provide the explanation. Let me know if any of it is unclear. –  Chip Bennett Dec 4 '12 at 20:59
add comment

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.