* Theme, template, and stylesheet functions.
* Returns an array of WP_Theme objects based on the arguments.
* Despite advances over get_themes(), this function is quite expensive, and grows
* linearly with additional themes. Stick to wp_get_theme() if possible.
* @global array $wp_theme_directories
* Optional. The search arguments.
* @type mixed $errors True to return themes with errors, false to return
* themes without errors, null to return all themes.
* @type mixed $allowed (Multisite) True to return only allowed themes for a site.
* False to return only disallowed themes for a site.
* 'site' to return only site-allowed themes.
* 'network' to return only network-allowed themes.
* Null to return all themes. Default null.
* @type int $blog_id (Multisite) The blog ID used to calculate which themes
* are allowed. Default 0, synonymous for the current blog.
* @return WP_Theme[] Array of WP_Theme objects.
function wp_get_themes( $args = array() ) {
global $wp_theme_directories;
$args = wp_parse_args( $args, $defaults );
$theme_directories = search_theme_directories();
if ( is_array( $wp_theme_directories ) && count( $wp_theme_directories ) > 1 ) {
// Make sure the current theme wins out, in case search_theme_directories() picks the wrong
// one in the case of a conflict. (Normally, last registered theme root wins.)
$current_theme = get_stylesheet();
if ( isset( $theme_directories[ $current_theme ] ) ) {
$root_of_current_theme = get_raw_theme_root( $current_theme );
if ( ! in_array( $root_of_current_theme, $wp_theme_directories, true ) ) {
$root_of_current_theme = WP_CONTENT_DIR . $root_of_current_theme;
$theme_directories[ $current_theme ]['theme_root'] = $root_of_current_theme;
if ( empty( $theme_directories ) ) {
if ( is_multisite() && null !== $args['allowed'] ) {
$allowed = $args['allowed'];
if ( 'network' === $allowed ) {
$theme_directories = array_intersect_key( $theme_directories, WP_Theme::get_allowed_on_network() );
} elseif ( 'site' === $allowed ) {
$theme_directories = array_intersect_key( $theme_directories, WP_Theme::get_allowed_on_site( $args['blog_id'] ) );
$theme_directories = array_intersect_key( $theme_directories, WP_Theme::get_allowed( $args['blog_id'] ) );
$theme_directories = array_diff_key( $theme_directories, WP_Theme::get_allowed( $args['blog_id'] ) );
static $_themes = array();
foreach ( $theme_directories as $theme => $theme_root ) {
if ( isset( $_themes[ $theme_root['theme_root'] . '/' . $theme ] ) ) {
$themes[ $theme ] = $_themes[ $theme_root['theme_root'] . '/' . $theme ];
$themes[ $theme ] = new WP_Theme( $theme, $theme_root['theme_root'] );
$_themes[ $theme_root['theme_root'] . '/' . $theme ] = $themes[ $theme ];
if ( null !== $args['errors'] ) {
foreach ( $themes as $theme => $wp_theme ) {
if ( $wp_theme->errors() != $args['errors'] ) {
unset( $themes[ $theme ] );
* Gets a WP_Theme object for a theme.
* @global array $wp_theme_directories
* @param string $stylesheet Optional. Directory name for the theme. Defaults to current theme.
* @param string $theme_root Optional. Absolute path of the theme root to look in.
* If not specified, get_raw_theme_root() is used to calculate
* the theme root for the $stylesheet provided (or current theme).
* @return WP_Theme Theme object. Be sure to check the object's exists() method
* if you need to confirm the theme's existence.
function wp_get_theme( $stylesheet = '', $theme_root = '' ) {
global $wp_theme_directories;
if ( empty( $stylesheet ) ) {
$stylesheet = get_stylesheet();
if ( empty( $theme_root ) ) {
$theme_root = get_raw_theme_root( $stylesheet );
if ( false === $theme_root ) {
$theme_root = WP_CONTENT_DIR . '/themes';
} elseif ( ! in_array( $theme_root, (array) $wp_theme_directories, true ) ) {
$theme_root = WP_CONTENT_DIR . $theme_root;
return new WP_Theme( $stylesheet, $theme_root );
* Clears the cache held by get_theme_roots() and WP_Theme.
* @param bool $clear_update_cache Whether to clear the theme updates cache.
function wp_clean_themes_cache( $clear_update_cache = true ) {
if ( $clear_update_cache ) {
delete_site_transient( 'update_themes' );
search_theme_directories( true );
foreach ( wp_get_themes( array( 'errors' => null ) ) as $theme ) {
* Whether a child theme is in use.
* @return bool True if a child theme is in use, false otherwise.
function is_child_theme() {
return ( TEMPLATEPATH !== STYLESHEETPATH );
* Retrieves name of the current stylesheet.
* The theme name that is currently set as the front end theme.
* For all intents and purposes, the template name and the stylesheet name
* are going to be the same for most cases.
* @return string Stylesheet name.
function get_stylesheet() {
* Filters the name of current stylesheet.
* @param string $stylesheet Name of the current stylesheet.
return apply_filters( 'stylesheet', get_option( 'stylesheet' ) );
* Retrieves stylesheet directory path for current theme.
* @return string Path to current theme's stylesheet directory.
function get_stylesheet_directory() {
$stylesheet = get_stylesheet();
$theme_root = get_theme_root( $stylesheet );
$stylesheet_dir = "$theme_root/$stylesheet";
* Filters the stylesheet directory path for current theme.
* @param string $stylesheet_dir Absolute path to the current theme.
* @param string $stylesheet Directory name of the current theme.
* @param string $theme_root Absolute path to themes directory.
return apply_filters( 'stylesheet_directory', $stylesheet_dir, $stylesheet, $theme_root );
* Retrieves stylesheet directory URI for current theme.
* @return string URI to current theme's stylesheet directory.
function get_stylesheet_directory_uri() {
$stylesheet = str_replace( '%2F', '/', rawurlencode( get_stylesheet() ) );
$theme_root_uri = get_theme_root_uri( $stylesheet );
$stylesheet_dir_uri = "$theme_root_uri/$stylesheet";
* Filters the stylesheet directory URI.
* @param string $stylesheet_dir_uri Stylesheet directory URI.
* @param string $stylesheet Name of the activated theme's directory.
* @param string $theme_root_uri Themes root URI.
return apply_filters( 'stylesheet_directory_uri', $stylesheet_dir_uri, $stylesheet, $theme_root_uri );
* Retrieves stylesheet URI for current theme.
* The stylesheet file name is 'style.css' which is appended to the stylesheet directory URI path.
* See get_stylesheet_directory_uri().
* @return string URI to current theme's stylesheet.
function get_stylesheet_uri() {
$stylesheet_dir_uri = get_stylesheet_directory_uri();
$stylesheet_uri = $stylesheet_dir_uri . '/style.css';
* Filters the URI of the current theme stylesheet.
* @param string $stylesheet_uri Stylesheet URI for the current theme/child theme.
* @param string $stylesheet_dir_uri Stylesheet directory URI for the current theme/child theme.
return apply_filters( 'stylesheet_uri', $stylesheet_uri, $stylesheet_dir_uri );
* Retrieves the localized stylesheet URI.
* The stylesheet directory for the localized stylesheet files are located, by
* default, in the base theme directory. The name of the locale file will be the
* locale followed by '.css'. If that does not exist, then the text direction
* stylesheet will be checked for existence, for example 'ltr.css'.
* The theme may change the location of the stylesheet directory by either using
* the {@see 'stylesheet_directory_uri'} or {@see 'locale_stylesheet_uri'} filters.
* If you want to change the location of the stylesheet files for the entire
* WordPress workflow, then change the former. If you just have the locale in a
* separate folder, then change the latter.
* @global WP_Locale $wp_locale WordPress date and time locale object.
* @return string URI to current theme's localized stylesheet.
function get_locale_stylesheet_uri() {
$stylesheet_dir_uri = get_stylesheet_directory_uri();
$dir = get_stylesheet_directory();
if ( file_exists( "$dir/$locale.css" ) ) {
$stylesheet_uri = "$stylesheet_dir_uri/$locale.css";
} elseif ( ! empty( $wp_locale->text_direction ) && file_exists( "$dir/{$wp_locale->text_direction}.css" ) ) {
$stylesheet_uri = "$stylesheet_dir_uri/{$wp_locale->text_direction}.css";
* Filters the localized stylesheet URI.
* @param string $stylesheet_uri Localized stylesheet URI.
* @param string $stylesheet_dir_uri Stylesheet directory URI.
return apply_filters( 'locale_stylesheet_uri', $stylesheet_uri, $stylesheet_dir_uri );
* Retrieves name of the current theme.
* @return string Template name.
function get_template() {
* Filters the name of the current theme.
* @param string $template Current theme's directory name.
return apply_filters( 'template', get_option( 'template' ) );
* Retrieves template directory path for current theme.
* @return string Path to current theme's template directory.
function get_template_directory() {
$template = get_template();
$theme_root = get_theme_root( $template );
$template_dir = "$theme_root/$template";
* Filters the current theme directory path.
* @param string $template_dir The path of the current theme directory.
* @param string $template Directory name of the current theme.
* @param string $theme_root Absolute path to the themes directory.
return apply_filters( 'template_directory', $template_dir, $template, $theme_root );
* Retrieves template directory URI for current theme.
* @return string URI to current theme's template directory.
function get_template_directory_uri() {
$template = str_replace( '%2F', '/', rawurlencode( get_template() ) );
$theme_root_uri = get_theme_root_uri( $template );
$template_dir_uri = "$theme_root_uri/$template";
* Filters the current theme directory URI.
* @param string $template_dir_uri The URI of the current theme directory.
* @param string $template Directory name of the current theme.
* @param string $theme_root_uri The themes root URI.
return apply_filters( 'template_directory_uri', $template_dir_uri, $template, $theme_root_uri );
* @global array $wp_theme_directories
* @return array|string An array of theme roots keyed by template/stylesheet
* or a single theme root if all themes have the same root.
function get_theme_roots() {
global $wp_theme_directories;
if ( ! is_array( $wp_theme_directories ) || count( $wp_theme_directories ) <= 1 ) {
$theme_roots = get_site_transient( 'theme_roots' );
if ( false === $theme_roots ) {
search_theme_directories( true ); // Regenerate the transient.
$theme_roots = get_site_transient( 'theme_roots' );
* Registers a directory that contains themes.
* @global array $wp_theme_directories
* @param string $directory Either the full filesystem path to a theme folder
* or a folder within WP_CONTENT_DIR.
* @return bool True if successfully registered a directory that contains themes,
* false if the directory does not exist.
function register_theme_directory( $directory ) {
global $wp_theme_directories;
if ( ! file_exists( $directory ) ) {
// Try prepending as the theme directory could be relative to the content directory.
$directory = WP_CONTENT_DIR . '/' . $directory;
// If this directory does not exist, return and do not register.
if ( ! file_exists( $directory ) ) {
if ( ! is_array( $wp_theme_directories ) ) {
$wp_theme_directories = array();
$untrailed = untrailingslashit( $directory );
if ( ! empty( $untrailed ) && ! in_array( $untrailed, $wp_theme_directories, true ) ) {
$wp_theme_directories[] = $untrailed;
* Searches all registered theme directories for complete and valid themes.
* @global array $wp_theme_directories
* @param bool $force Optional. Whether to force a new directory scan. Default false.
* @return array|false Valid themes found on success, false on failure.
function search_theme_directories( $force = false ) {
global $wp_theme_directories;
static $found_themes = null;
if ( empty( $wp_theme_directories ) ) {
if ( ! $force && isset( $found_themes ) ) {
$wp_theme_directories = (array) $wp_theme_directories;
$relative_theme_roots = array();
* Set up maybe-relative, maybe-absolute array of theme directories.
* We always want to return absolute, but we need to cache relative
* to use in get_theme_root().
foreach ( $wp_theme_directories as $theme_root ) {
if ( 0 === strpos( $theme_root, WP_CONTENT_DIR ) ) {
$relative_theme_roots[ str_replace( WP_CONTENT_DIR, '', $theme_root ) ] = $theme_root;
$relative_theme_roots[ $theme_root ] = $theme_root;
* Filters whether to get the cache of the registered theme directories.
* @param bool $cache_expiration Whether to get the cache of the theme directories. Default false.
* @param string $context The class or function name calling the filter.
$cache_expiration = apply_filters( 'wp_cache_themes_persistently', false, 'search_theme_directories' );
if ( $cache_expiration ) {
$cached_roots = get_site_transient( 'theme_roots' );
if ( is_array( $cached_roots ) ) {
foreach ( $cached_roots as $theme_dir => $theme_root ) {
// A cached theme root is no longer around, so skip it.
if ( ! isset( $relative_theme_roots[ $theme_root ] ) ) {
$found_themes[ $theme_dir ] = array(
'theme_file' => $theme_dir . '/style.css',
'theme_root' => $relative_theme_roots[ $theme_root ], // Convert relative to absolute.
if ( ! is_int( $cache_expiration ) ) {
$cache_expiration = 30 * MINUTE_IN_SECONDS;
$cache_expiration = 30 * MINUTE_IN_SECONDS;
/* Loop the registered theme directories and extract all themes */
foreach ( $wp_theme_directories as $theme_root ) {