Understanding the APIs Related to Theme Options

There seems to be a great deal of confusion regarding the various APIs involved with Theme options, especially regarding the interactions among those APIs. This confusion is obvious in discussions involving the CustomizerCustomizer Tool built into WordPress core that hooks into most modern themes. You can use it to preview and modify many of your site’s appearance settings.. This post will attempt to explain the various APIs and how they work together.

The first thing to understand is the various interactions with options: storing options in the database, retrieving options from the database, and user configuration of options.

Storing and Retrieving Options

WordPress has two APIs for storing and retrieving Theme options: the Options API and the Theme Modification (Theme Mods) API. The Options APIAPI An API or Application Programming Interface is a software intermediary that allows programs to interact with each other and share data in limited, clearly defined ways. is the “granddaddy” API, used by coreCore Core is the set of software required to run WordPress. The Core Development Team builds WordPress. and Plugins, as well as Themes. The Theme Mods API is a Theme-specific API.

The Options API uses the add_option() and update_option() functions to store options to the database, and get_option() to retrieve options from the database. The Theme Mods API uses the set_theme_mod() to store options to the database, and get_theme_mod() and get_theme_mods() to retrieve options from the database. Neither API deals with user configuration (e.g. Settings pages) of options.

User Configuration of Options

There are essentially three ways to allow users to configure Theme options: a Settings API-generated settings page, a custom settings page, and the Customizer API. Both a settings page and the Customizer display options retrieved by either the Settings API or the Theme Mods API, then return user-configured settings to that same API for storage in the database.

(Note: where the Theme Review Guidelines formerly recommended using the Settings API, that recommendation applied to using the Settings API to generate the settings page, rather than the Theme creating a custom settings page. That recommendation has been superseded by the recommendation to use the Customizer.)

The Settings API includes a robust set of functions to generate a Settings page, but is missing some key elements such as default markup for settings fields, and standard sanitization/validation based on option data type. This void is frequently filled by the various option framework libraries available. Using such frameworks avoids the necessity of the Theme developer to roll their own code. These frameworks generally also handle the sometimes complex callback structure needed to implement the Settings API fully. (And no joke; fully implementing the Settings API is so complex that I wrote a ten-page tutorial on it a few years ago.)

Until the Customizer, the only other option was a completely custom Theme settings page. These used to be all the rage (and can still be found in many options frameworks), and were promoted as a Theme “feature”. All they really did was add a non-core UIUI UI is an acronym for User Interface - the layout of the page the user interacts with. Think ‘how are they doing that’ and less about what they are doing. and increase the learning curve for Theme developers and users alike. That’s why the Theme Review Guidelines used to recommend use of the Settings API to generate Theme settings pages.

Now, for Themes that opted to use the Theme Mods API, a custom Theme settings page was the only option. The Theme Mods API is, overall, probably a better and easier API to understand and to use – but it did not include an API for creating a settings page.

Customizer API

Now, a third option exists: the Customizer.

It is important to keep in mind here that the Customizer is not an API for storing or retrieving settings; it is an API for user configuration of settings. It is not a replacement for either the Settings API or the Theme Mods API for storing/retrieving options; it is a replacement for Theme settings pages. The Customizer does not store options to or retrieve options from the database. It merely displays options retrieved by either the Theme Mods API or the Settings API, and returns settings to either the Theme Mods API or the Settings API for storage in the database.

This is a very important distinction to remember, because, while the Customizer defaults to using the Theme Mods API, it can be used with either the Theme Mods API or the Settings API. This flexibility is important for existing Themes as well as for new Themes. Developers of existing Themes that use the Settings API, and who want to migrate away from settings pages and toward use of the Customizer can do so quite easily. And Developers of new Themes that want to take advantage of the Customizer from the beginning can do so just as easily.

Key Points

  1. Theme Mods API and Options API are used to store/retrieve options
  2. Settings pages and the Customizer are used to allow users to configure options
  3. The Customizer can replace a Settings page and the Settings API, but cannot replace either the Theme Mods API or the Options API
  4. The Customizer can be used on top of either the Theme Mods API or the Options API
  5. Themes that currently use the Settings API, either directly or using an options framework library, can use the Customizer without changing any of the underlying options code already in use
  6. Themes that currently use a Settings page with the Settings API can add Customizer support without impacting or removing the current Settings page
  7. New Themes are recommended to use the Customizer with the Theme Mods API

#customizer-api, #options-api, #settings-api, #theme-mods-api

Using Sane Defaults in Themes

With the release of WordPress 3.9, one of the changes to the Theme Review Guidelines is that Themes must use sane defaults. That means that Themes must not write default setting values to the database. For many Themes, this may seem like a major change; but it doesn’t have to be. This post will step through a few ways to implement sane defaults.

Portability/DRY

To make this method easier, put all of your defaults inside a function:

function themeslug_get_option_defaults() {
	$defaults = array(
		'option_1' => 'value_1',
		'option_2' => 'value_2',
		'option_3' => 'value_3'
	);
	return apply_filters( 'themeslug_option_defaults', $defaults );
}

(Note: by making the return valuable filterable, the Theme defaults can be easily overridden by a Child ThemeChild theme A Child Theme is a customized theme based upon a Parent Theme. It’s considered best practice to create a child theme if you want to modify the CSS of your theme. https://developer.wordpress.org/themes/advanced-topics/child-themes/. or PluginPlugin A plugin is a piece of software containing a group of functions that can be added to a WordPress website. They can extend functionality or add new features to your WordPress websites. WordPress plugins are written in the PHP programming language and integrate seamlessly with WordPress. These can be free in the WordPress.org Plugin Directory https://wordpress.org/plugins/ or can be cost-based plugin from a third-party.)

We’ll make use of this function later.

Options APIAPI An API or Application Programming Interface is a software intermediary that allows programs to interact with each other and share data in limited, clearly defined ways.

Most Themes use the Options API, and will use get_option() to put Theme settings into a global:

$themeslug_options = get_option( 'theme_themeslug_options' );

Knowing that this get_option() caall will return FALSE if the option has not yet been saved to the database, Theme developers have taken to saving default values to the database as part of Theme initialization, like so:

if ( false == get_option( 'theme_themeslug_options' ) ) {
	update_option( 'theme_themeslug_options', themeslug_get_option_defaults() );
}
$themeslug_options = get_option( 'theme_themeslug_options' );

But this is entirely unnecessary. And everything needed to implement a better solution already exists.

As a first step, consider that get_option() includes a second parameter, which specifies the default value to return, if nothing is returned from the database:

get_option( $name, $default );

So, the simplest solution is merely to tell get_option() to return the defaults, using the function we previously defined:

$themeslug_options = get_option( 'theme_themeslug_options', themeslug_get_option_defaults() );

This works, but isn’t perfect. It will return the Theme-defined defaults if the user hasn’t saved settings to the databse. But if later versions of the Theme add, remove, or change options, this might break, since the return value is either/or: either the database-saved setting, or else the defaults. So, if the user saves settings, and then a new setting is added in a later Theme version, the new setting value won’t be included in $themeslug_options unless/until the user saves settings again.

The solution is to merge the arrays, rather than to return one or the other. WordPress has a coreCore Core is the set of software required to run WordPress. The Core Development Team builds WordPress. function specifically for this purpose: wp_parse_args(), which will use the settings array, and “fill in the blanks” with the defaults array:

wp_parse_args( $settings, $defaults );

Caveat: bearing in mind that wp_parse_args() expects both parameters to be arrays, and knowing that get_option() returns FALSE by default, be sure to specify get_option() returns an empty array by default: get_option( ‘theme_themeslug_options’, array() ); otherwise, wp_parse_args() will (might – see note below) choke if the user hasn’t saved settings to the database.

The construct will look something like this:

$themeslug_options = wp_parse_args( 
    get_option( 'theme_themeslug_options', array() ), 
    themeslug_get_option_defaults() 
);

This is perhaps the simplest, most elegant way to implement sane defaults.

(Note: according to Otto, passing an empty arrayy() as the second parameter to get_option() isn’t necessary. In his words: “The wp_parse_args() function checks for the first parameter to be an object or an array. If it’s neither, then it calls wp_parse_str on it, because it can take a GET URLURL A specific web address of a website or web page on the Internet, such as a website’s URL www.wordpress.org-like array of parameters too. The wp_parse_str() function calls PHPPHP PHP (recursive acronym for PHP: Hypertext Preprocessor) is a widely-used open source general-purpose scripting language that is especially suited for web development and can be embedded into HTML. http://php.net/manual/en/intro-whatis.php.’s parse_str on it, and does a deep strip_slashes if magic quotes is on, then filters the result. So, because false maps to the empty string, parse_str will return an empty array for it, so passing false to wp_parse_args should be A-OK and probably has been like that for a very long time. Doesn’t hurt to add the empty array(), but doesn’t really change anything.” YMMV.)

Theme Modification API

Using the Theme Modification API (get_theme_mod()/get_theme_mods()) is fairly similar.

An individual setting can be called via:

get_theme_mod( $name, $default );

But perhaps more useful, all settings can be called via:

$themeslug_options = get_theme_mods();

Since get_theme_mods() returns an array, you can use the same technique as with Options API settings:

$themeslug_options = wp_parse_args( 
    get_theme_mods(), 
    themeslug_get_option_defaults() 
);

Portability/DRY (Part 2)

To be able to use this method throughout the Theme, wrap the wp_parse_args() call inside a function:

function themeslug_get_options() {
    // Options API
    return wp_parse_args( 
        get_option( 'theme_themeslug_options', array() ), 
        themeslug_get_option_defaults() 
    );
    // Theme Mods API:
    /*
    return wp_parse_args( 
        get_theme_mods(), 
        themeslug_get_option_defaults() 
    );
    */
}

Then, wherever you need access to Theme options:

$themeslug_options = themeslug_get_options();

From there, you can globalize $themeslug_options, or cache/transient it, etc. When you need to add a new option, simply add the new option default to the defaults array, and the Theme will handle it automatically.

#guidelines, #sane-defaults, #settings-api, #theme-mods-api

Proper Copyright/License Attribution for Themes

There seems to be a great deal of confusion/misunderstanding regarding what constitutes proper copyright/license attribution for Themes, and several Themes are being approved without proper copyright/license attribution.

There are four primary types of attribution: the Theme itself, derivative-work, incorporated code, and bundled resources. For works licensed under (or compatibly with) GPLGPL GPL is an acronym for GNU Public License. It is the standard license WordPress uses for Open Source licensing https://wordpress.org/about/license/. The GPL is a ‘copyleft’ license https://www.gnu.org/licenses/copyleft.en.html. This means that derivative work can only be distributed under the same license terms. This is in distinction to permissive free software licenses, of which the BSD license and the MIT License are widely used examples., this attribution is important, because it ensures that end users know their rights regarding modification and distribution of the copyrighted work. The “copyleft” nature of GPL ensures that those same rights are preserved in downstream distributions of a copyrighted work, or works derived from that work – which is why it is imperative that correct copyright/license attribution be included in GPL-compatible works.

Theme Copyright Attribution

Fred WordPress Theme, Copyright 2012 Joe Smith
Fred is distributed under the terms of the GNU GPL

The Theme itself is a copyrighted work, and requires copyright attribution. According to GNU (the maintainer of the GPL):

Whichever license you plan to use, the process involves adding two elements to each source file of your program: a copyright notice (such as “Copyright 1999 Terry Jones”), and a statement of copying permission, saying that the program is distributed under the terms of the GNU General Public License (or the Lesser GPL).

The copyright notice:

The copyright notice should include the year in which you finished preparing the release (so if you finished it in 1998 but didn’t post it until 1999, use 1998). You should add the proper year for each release; for example, “Copyright 1998, 1999 Terry Jones” if some versions were finished in 1998 and some were finished in 1999. If several people helped write the code, use all their names.

The statement of copying permission:

This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program. If not, see < http://www.gnu.org/licenses/ >.

Derivative Themes and Incorporated Code Copyright Attribution

Themes that are derived from other Themes (such as Twenty Twelve or Underscores) must declare that they are derived from another work, and include the original copyright notice from that work. For derivative works, the declaration would follow the Theme’s own copyright notice, and would take a form similar to the following:

Ginger WordPress Theme is derived from Fred WordPress Theme, Copyright 2012 Joe Smith
Fred WordPress Theme is distributed under the terms of the GNU GPL

Incorporated Code Copyright Attribution

Themes that incorporate code from other Themes (or Plugins) must declare that they incorporate code from another Theme/PluginPlugin A plugin is a piece of software containing a group of functions that can be added to a WordPress website. They can extend functionality or add new features to your WordPress websites. WordPress plugins are written in the PHP programming language and integrate seamlessly with WordPress. These can be free in the WordPress.org Plugin Directory https://wordpress.org/plugins/ or can be cost-based plugin from a third-party. The difference between a derivative work and incorporated code is, generally, a matter of extent. If you use a Theme as a “starter” or a base (such as Underscores), then you have created a derivative work. If you use one or more functions from another Theme, then you have incorporated code from that Theme.

For incorporated code, the declaration should be added to the headerHeader The header of your site is typically the first thing people will experience. The masthead or header art located across the top of your page is part of the look and feel of your website. It can influence a visitor’s opinion about your content and you/ your organization’s brand. It may also look different on different screen sizes. comments for the files and/or the doc blocks for the incorporated functions, including copyright, license, and a source link, using appropriate syntax (such as phpDoc for incorporated PHPPHP PHP (recursive acronym for PHP: Hypertext Preprocessor) is a widely-used open source general-purpose scripting language that is especially suited for web development and can be embedded into HTML. http://php.net/manual/en/intro-whatis.php. code). The Theme readme (or license) file should include a declaration of incorporated code:

Ginger WordPress Theme incorporates code from Fred WordPress Theme, Copyright 2012 Joe Smith
Fred WordPress Theme is distributed under the terms of the GNU GPL

Bundled Resource Copyright Attribution

Themes that bundle third-party resources (such as script libraries, PHP or CSSCSS CSS is an acronym for cascading style sheets. This is what controls the design or look and feel of a site. frameworks, images, fonts, etc.) must declare that they bundle those resources. For bundled resources, the original copyright notice (normally found in file headers, or a license file) should be retained if it exists. Additionally, the Theme readme (or license) file should include a declaration of bundled resources, including copyright, license, and a source link.

Ginger WordPress Theme bundles the following third-party resources:

Genericons icon font, Copyright 2013 Automattic
Genericons are licensed under the terms of the GNU GPL, Version 2 (or later)
Source: http://www.genericons.com

Cycle2 jQuery library, Copyright 2012 M. Alsup
Cycle2 is dual-licensed under the terms of the GNU GPL, Version 2, and the MIT license
Source: http://jquery.malsup.com/cycle2/

Requiring this information to be listed in the readme when it is available in file headers is a bit redundant; but it is a matter of ensuring that the Theme developer has considered/verified that the licenses for all bundled resources are GPL-compatible, and that end users (and reviewers) have a known location to find this information. Note that, because binary files (such as images) do not have human-readable file headers, the inclusion of copyright, license, and source link in the readme is critical, since otherwise the end user will have no way to know how to find this information.

Putting it All Together

Here is an example of a complete copyright/license attribution section in a Theme readme (or license) file:

Ginger WordPress Theme, Copyright 2012 Joe Smith
Ginger is distributed under the terms of the GNU GPL

This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program.  If not, see .

Ginger WordPress Theme is derived from Underscores WordPress Theme, Copyright 2013 Automattic, Inc.
Underscores WordPress Theme is distributed under the terms of the GNU GPL

Ginger WordPress Theme incorporates code from Fred WordPress Theme, Copyright 2012 Joe Smith
Fred WordPress Theme is distributed under the terms of the GNU GPL

Ginger WordPress Theme bundles the following third-party resources:

Genericons icon font, Copyright 2013 Automattic
Genericons are licensed under the terms of the GNU GPL, Version 2 (or later)
Source: http://www.genericons.com

Cycle2 jQuery library, Copyright 2012 M. Alsup
Cycle2 is dual-licensed under the terms of the GNU GPL, Version 2, and the MIT license
Source: http://jquery.malsup.com/cycle2/

Hopefully this post helps clarify the requirements for proper copyright/license attribution, and will help ensure that review of license requirements is more consistent. As a reminder: under the current guidelines, these copyright statements must be included in the Theme readme (or license) file. The examples given above are intended to describe required content, and not necessarily a required format for that content.

#copyright, #license

Correct Handling of Static Front Page and Custom Blog Posts Index Template

Recently, there have been several Themes submitted – and approved – that include a template-blog.php (or page-blog.php) custom page template, or that include a static front pageStatic Front Page A WordPress website can have a dynamic blog-like front page, or a “static front page” which is used to show customized content. Typically this is the first page you see when you visit a site url, like wordpress.org for example. template (front-page.php) that doesn’t properly account for the user configuration to display the blog posts index on the front page. In order to be approved, Theems must handle these correctly.

Themes must properly support user configuration of the front page display, as configured via Settings -> Reading, Front page displays, Front page, and Page for posts.

The “Front page displays” option correlates to get_option( ‘show_on_front’ ), and returns a value of ‘page’ (static front page) or ‘posts’ (blog posts index). Themes must account for both values, whether or not the Theme uses front-page.php. For more information, see here.

Theme support extends beyond the “Front page displays” setting, however. Themes must also properly implement support for the “Front page” and “Page for posts” settings, as defined by the Template Hierarchy. To understand the implementation, consider the user configuration. Users set up a static front page like so:

  1. Create two static pages, which we’ll call “Front Page” and “Blog”
  2. In Settings -> Reading, set “Front page displays” to “a static page”
  3. In Settings -> Reading, set “Front page” to “Front Page”
  4. In Settings -> Reading, set “Posts page” to “Blog”

In this scenario, using the Template Hierarchy, WordPress will determine what to display in the context of Front Page and Blog Posts Index.

Front Page:

  • front-page.php
  • Page Template Hierarchy (custom page template, page-slug.php, page-id.php, page.php, index.php)

Blog Post Index:

  • Home Template Hierarchy (home.php, index.php)

That means that, according to the Template Hierarchy, the correct file to use to define a custom blog posts index is the home.php template file, and not a custom page template. In fact, when users have properly configured a static front page and assigned pages to display the site front page and the blog posts index, a custom page template is pointless. Even if the user applies the template-blog.php custom page template to the page assigned to display the blog posts index, WordPress will ignore it, because the blog posts index uses the Home template hierarchy, and not the Page template hierarchy. WordPress will look for the home.php template file, and will fall back to the index.php template file.

So, the only possible way for the user to use a template-blog.php custom paage template would be for the Theme to instruct the user to configure the site front page and blog posts index in a way other than the way that coreCore Core is the set of software required to run WordPress. The Core Development Team builds WordPress. defines. Forcing the user into a different configuration than the one defined by core is poor UXUX UX is an acronym for User Experience - the way the user uses the UI. Think ‘what they are doing’ and less about how they do it.. Users should not have to configure core WordPress features differently whenever they install a new Theme.

So, if a Theme incorporates a custom template for the blog posts index, it must be implemented as the home.php template file, and not as a template-blog.php custom page template. If you are reviewing a Theme, please ensure that this is part of your review. If you’re a Theme developer, please ensure that you’re instructing your users to implement static front pages (and blog posts index pages) consistently with the core implementation, and that your Theme properly implements the Template Hierarchy.

(Side note: I strongly recommend the habit of prefixing custom page templates with “template” or “tpl” or something similar, rather than “page”. Naming a custom page template ‘page-foobar.php’ will cause WordPress to use that custom page template any time the user creates a static page with the slug “foobar”. Using something else, such as ‘template-foobar.php’ or ‘tpl-foobar.php’ will prevent that from happening, and will ensure that the custom page template is only used if the user explicitly assigns the custom page template to a given static page.)

#template-hierarchy

Review Workflow and Closing Tickets

There seems to be some misunderstanding about the review workflow. A few of the newer reviewers are leaving initial review comments, and immediately closing the ticket. While that was our old workflow, it has not been our current workflow for about a year.
Our current workflow is designed such that, as long as the ticket remains open, any subsequent Theme updates that get submitted are automatically appended to the open ticket – which allows for the review process to take place in a single ticket. This process is much easier both for the reviewers and for developers.
Tickets should only be closed under two circumstances:
  1. The developer fails to respond within a reasonable time
  2. The submission is not legitimate (ripped theme, spam theme, etc.)
We currently define “reasonable time” as a week. But in order to make things even easier and consistent, I am asking that reviewers not close tickets due to lack of developer response. This is something that I check for, usually daily, in order to close tickets with no response, or to request a status update.
So:
  1. Do not close tickets due to lack of developer response. Admins will take care of such ticket closures.
  2. Do not post “bump” comments, as doing so impacts Admins’ ability to follow up on idle tickets.
The idea is that reviewers can just focus on doing reviews, and helping developers proceed toward approval; Admins can focus on dealing with tickets without developer response and otherwise idle tickets.