Creating Custom Theme Feature Support

medium_3022885734Since WordPress version 2.9 theme developers have taken advantage of the add_theme_support feature. Built-in theme features include custom header images, custom backgrounds, post formats, and more. However, we’ve also been given a filter in the current_theme_supports function that allows us to expand theme feature support beyond the built-in options.

The most obvious, and simplest, usage of theme features is to first use add_theme_support to register a feature supported by your theme. Then we can verify the feature is supported with the conditional current_theme_supports function. For example:

<?php
/**
* Basic Theme Support usage. Add this to your functions.php file
*/
add_theme_support( 'custom-footer-text' );
/**
* Elsewhere in your theme...
*/
if( current_theme_supports( 'custom-footer-text' ) ) {
echo 'Custom Footer Text!';
}
view raw basic-usage.php hosted with ❤ by GitHub

Expanding Custom Theme Features With Arguments

That’s all fine and dandy, but what if you have a lot of potential theme features that could vary depending on the theme? You might be creating a theme extending plugin or theme extension for plugins to use, perhaps. Instead of listing out a ton of add_theme_support declarations (and their conditionals all over the place), let’s simplify it to a single declaration, shall we?

Thanks to the way current_theme_supports is written, we can create a single feature and pass through a multitude of “sub-features” in an array with a second $arguments variable like this: add_theme_support( $feature, $arguments );. In order for this to be useful, however, we’ll need to amend the current_theme_supports function to accept the secondary features, using a feature-specific filter, then we can use it accordingly.

For example, I’m creating a theme extending plugin. Each theme will use a single line to add theme support for a multitude of features. First, we’ll create a function to add the arguments as acceptable values in the current_theme_supports function. Then we’ll add the features to our theme.

<?php
/**
* Determines, whether the specific theme feature is actually supported. Place this in your plugin file.
*
* @link https://github.com/zamoose/themehookalliance/blob/master/tha-theme-hooks.php
*
* @param bool $bool true
* @param array $args The hook type being checked
* @param array $registered All registered hook types
*
* @return bool
*/
if( ! function_exists( 'jdn_toolkit_current_theme_supports' ) ) {
function jdn_toolkit_current_theme_supports( $bool, $args, $registered ) {
if( isset( $args[0] ) && isset( $registered[0] ) ) {
return in_array( $args[0], $registered[0] );
} else {
return false;
}
}
}
add_filter( 'current_theme_supports-jdn-toolkit', 'jdn_toolkit_current_theme_supports', 10, 3 );

Now I can use the current_theme_supports function in my plugin/theme to add functionality that is supported, like this:

<?php
/**
* Add theme support to your function.php file
*/
add_theme_support( 'jdn-toolkit', array( 'theme-options', 'portfolio', 'custom-footer-text' ) );
/**
* Elsewhere in your theme...
*/
if( current_theme_supports( 'jdn-toolkit', 'custom-footer-text' ) {
echo 'Custom Footer Text!';
}

And there you have it! You’ve easily extended this core function to further your theme development powers.

Expanding The require_if_theme_supports Function

Another great function related to theme features is the require_if_theme_supports function. Justin Tadlock has a great write up on theme supported features that touches on this function.

Basically, it allows you to conditionally require another file – if theme supports X, include file Y. What if you want to use this function with our example above? Well, you can, but you can’t pass our new sub-features through it. What if you only want to include a file if the custom-footer-text is supported? I’ve written another function you can use in a similar manner. Instead of the main feature, use the sub feature.

<?php
/**
* Checks a theme's support for a given feature before loading the functions which implement it.
*
* @param string $feature The feature being checked.
* @param string $include Path to the file.
* @return bool True if the current theme supports the supplied feature, false otherwise.
*/
if( !function_exists( 'require_if_jdn_toolkit_supports' ) ) {
function require_if_jdn_toolkit_supports( $feature, $include ) {
if( current_theme_supports( 'jdn-toolkit', $feature ) ) {
require ( $include );
return true;
}
return false;
}
}
/**
* Usage
*/
require_if_jdn_toolkit_supports( 'theme-options', 'path/to/file.php' );

Image Credit: Express Monorail, cc

Discussion

  1. Thanks for sharing this idea. At first the sub-feature mechanism seemed awkward, but then I thought of it as creating a namespace and it makes sense. You’d have to make sure none of the sub-features needed to get arguments, though. 🙂