For my next (still forthcoming) version of my WordPress calendar plugin, My Calendar, I had a need to add custom screen options to a couple of editing screens. Now, there’s a great tutorial on adding screen options by Chris Marslender that I found very useful.

It is, however, incomplete.

Now, if what you want to do is add one basic control, that tutorial is definitely going to get you where you need to go. It’s simple, straightforward, and accurate. However, it has one tiny error and one large omission.

The tiny error is simple: for saving the option, the tutorial specifies this code:


add_filter('set-screen-option', 'cmi_set_option', 10, 3);
 
function cmi_set_option($status, $option, $value) {
    if ( 'cmi_movies_per_page' == $option ) return $value;
}

This will work, for a single field. But, if you add two, you’ll notice that this filter *prevents* any other screen option value from being sent if it is not equal to ‘cmi_movies_per_page’. It doesn’t stop any of the default screen options, which are all whitelisted in the WordPress function handling updating options. When you add another custom function, however…no go.

Easy fix:


add_filter('set-screen-option', 'cmi_set_option', 10, 3);
 
function cmi_set_option($status, $option, $value) {
    return $value;
}

Because the value being returned by the function named is very simple; just an integer; there’s no need to filter it in any way; just make sure it gets passed to the function and then saved in the user’s meta data.

Adding custom controls to Screen Options

That was the error. The omission (which is entirely fair, because it was already a long tutorial — no need to cover everything!) is about adding custom controls and saving their data. Because, in fact, you can add any control to the screen options — you’re not constrained to the standard control types that WordPress uses.

For consistency, I’m basing my settings on the same type of data used in Chris’s tutorial; I think this will make it easier to compare the two tutorials and make use of them together.

First, getting some fields into your screen options. This can be ignored when using the default screen options, because they’ll provide your HTML (HyperText Markup Language) controls for you. But you can attach your own custom controls through the filter screen_settings.


add_filter('screen_settings', 'cmi_show_screen_options', 10, 2 );

The function itself needs to do a handful of things:

  1. Define what it will return, whether it’s the desired screen or not.
  2. Determine whether it’s on the right screen for the controls.
  3. Return the form fields (the form itself is automatic)

The form fields must include an array of inputs named wp_screen_options[option] and wp_screen_options[value], or the submission will be ignored. As you’ll see further along, the option parameter is the important one; you need value to be present, but you don’t necessarily need to use it. That’s a choice, however, depending on what you’re doing with the data.

The current screen is passed to the screen settings function in an object variable of arguments, here called ‘$args’. You can test against your current screen using the $args->base member.


function cmi_show_screen_options( $status, $args ) {
    $return = $status;
        if ( $args->base == 'toplevel_page_my-calendar' ) {    
            $button = get_submit_button( __( 'Apply' ), 'button', 'screen-options-apply', false );
            $return .= "
            <fieldset>
            <legend>Show Columns</legend>
            <div class='metabox-prefs'>
            <div><input type='hidden' name='wp_screen_options[option]' value='cmi_show_columns' /></div>
            <div><input type='hidden' name='wp_screen_options[value]' value='yes' /></div>
            <div class='cmi_custom_fields'>
                <label for='cmi_producer'><input type='checkbox' value='on' name='cmi_columns[]' id='cmi_producer' /> Producer</label>
                <label for='cmi_director'><input type='checkbox' value='on' name='cmi_columns[]' id='cmi_director' /> Director</label>
            </div>
            </div>
            </fieldset>
            <br class='clear'>
            $button";
        }
        return $return;
}

In this example, I’m passing data using an arbitrarily named field called cmi_columns. I’m hypothesizing this as a group of controls to limit which fields you’re showing on a plug-in page.

Saving your Custom Screen Options

You’ll be using the same filter as in the other tutorial to save your data:


add_filter('set-screen-option', 'cmi_set_screen_options', 11, 3);

In the function itself, you can manipulate the POST data sent from your custom screen options however you wish. You can dance with it, change it, ignore it; whatever is relevant for you. If you need to interpret the data sent and use it in a way other than that directly posted, here’s where you can do it. Not in this example, however — which simply takes the posted data, and returns it to be saved in the user data.


function cmi_set_screen_options($status, $option, $value) {
	if ( 'cmi_show_columns' == $option ) { 
		$value = $_POST['cmi_columns'];
	}
	return $value;
}

That’s it. Value saved and passed.

What’s important in this tutorial?

If you’re trying to use the information from Chris’s tutorial to create multiple screen options, you’re going to get a little frustrated when the second one just won’t save. That’s because of the failure to return a value in the filter unless the specific field is passed. If you need to pass a type of data other than defaults, that tutorial doesn’t cover it. So here you are. Enjoy!