Earlier this week, I received an email from someone who was asking about the Settings API. Specifically, he was curious as to how the WordPress defaults array works.

For those of who may have worked with theme development, plugin development, or the Settings API in general, then you may be familiar with functions that look like this:

/**
 * Provides a default value for the theme layout setting.
 *
 * @since    1.0.0
 */
function get_theme_default_layout_options() {

	$defaults = array(
	    'layout'                         => 'right_sidebar_layout',
	    'display_featured_images'        => 'always'
	);

	return apply_filters ( 'theme_default_layout_options', $defaults );

}

But if you’re not familiar with the Settings API or with how to `apply_filters` call works, then this particular function can be confusing especially when it comes to understanding the serialization lifecycle of saving options to the database.

The WordPress defaults Array

In short, the `$defaults` array provides values to be serialized if the user doesn’t provide anything themselves. In a real world scenario, this may play out like this:

Let’s say…

  • The theme offers the ability to place the sidebar on the left or the right of the page
  • The user can select “left” or the user can select “right”
  • If the user does not select an option, then one will be set for him/her. We’ll say the “right” sidebar.

Defining The Setting

If you opt to use the Settings API, then these options may be kept under a “Layout” section with fields for “Left” or “Right” and then registered with a setting called the “theme_layout_options.”

Programmatically, it would look something like this (note that this code is for example purposes only – if you opt to use it in your own work, then make sure you prefix function names with the name of your theme or your plugin):

/**
 * Defines the theme's layout options.
 *
 * @since    1.0.0
 */
function setup_theme_layout_options() {

	// If the layout options don't exist, create them.
	if( false == get_option( 'theme_layout_options' ) ) {
		add_option( 'theme_layout_options', apply_filters( 'theme_default_layout_options', get_theme_default_layout_options() ) );
	} // end if

	add_settings_section(
		'layout',
		__( 'Layout', 'standard' ),
		'theme_layout_options_display',
		'theme_layout_options'
	);

	add_settings_field(
		'left_sidebar_layout',
		'Left Sidebar',
		'left_sidebar_layout_display',
		'theme_layout_options',
		'layout'
	);

	add_settings_field(
		'right_sidebar_layout',
		'Right Sidebar',
		'right_sidebar_layout_display',
		'theme_layout_options',
		'layout'
	);

	register_setting(
		'theme_layout_options',
		'theme_layout_options'
	);

}
add_action( 'admin_init', 'setup_theme_layout_options' );

Here, notice two things:

  1. The function is hooked into the `admin_init` action
  2. One of the first thing the function does is create the option in the database and sets defaults values with the function that we provided earlier in the post.

The Flow of Control

So how does this play out in the serialization lifecycle? Though others may have a more complicated, or even simpler explanation, this is how I’ve always broken it down for others:

  • First, I assume that use of `apply_filters` is being properly used and that there is a function that’s defined for setting those default options
  • Next, during serialization, WordPress will look to see if the option is set. If not, it will use the function that contains the `$defaults` array and save those values to the database. This provides the user with something rather than nothing so that the site, application, or blog doesn’t look borked.
  • Otherwise, it will take the value that the user has provided and use it instead of the default options.

Relatively simple, right?

But that’s part of what programming is about: taking the difficult ideas, breaking them into smaller functions, and making the user’s experience much easier through the use of code.

That said, these functions can get more complicated especially if you introduce validation (which is obviously outside the scope of this post), more options, and other settings.

But even still, the flow of control remains the same.