How can I insert some extra validation into the theme options’ validation function using add_filter?

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' );

Related posts

Leave a Reply

2 comments

  1. 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.

  2. 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 );