aboutsummaryrefslogtreecommitdiff
path: root/srcs/wordpress/wp-includes/theme.php
diff options
context:
space:
mode:
Diffstat (limited to 'srcs/wordpress/wp-includes/theme.php')
-rw-r--r--srcs/wordpress/wp-includes/theme.php3364
1 files changed, 3364 insertions, 0 deletions
diff --git a/srcs/wordpress/wp-includes/theme.php b/srcs/wordpress/wp-includes/theme.php
new file mode 100644
index 0000000..f20d2a0
--- /dev/null
+++ b/srcs/wordpress/wp-includes/theme.php
@@ -0,0 +1,3364 @@
+<?php
+/**
+ * Theme, template, and stylesheet functions.
+ *
+ * @package WordPress
+ * @subpackage Theme
+ */
+
+/**
+ * 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.
+ *
+ * @since 3.4.0
+ *
+ * @global array $wp_theme_directories
+ * @staticvar array $_themes
+ *
+ * @param array $args {
+ * Optional. The search arguments.
+ *
+ * @type mixed $errors True to return themes with errors, false to return themes without errors, null to return all themes.
+ * Defaults to false.
+ * @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. Defaults to null.
+ * @type int $blog_id (Multisite) The blog ID used to calculate which themes are allowed.
+ * Defaults to 0, synonymous for the current blog.
+ * }
+ * @return WP_Theme[] Array of WP_Theme objects.
+ */
+function wp_get_themes( $args = array() ) {
+ global $wp_theme_directories;
+
+ $defaults = array(
+ 'errors' => false,
+ 'allowed' => null,
+ 'blog_id' => 0,
+ );
+ $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 ) ) {
+ $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 ) ) {
+ return array();
+ }
+
+ 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'] ) );
+ } elseif ( $allowed ) {
+ $theme_directories = array_intersect_key( $theme_directories, WP_Theme::get_allowed( $args['blog_id'] ) );
+ } else {
+ $theme_directories = array_diff_key( $theme_directories, WP_Theme::get_allowed( $args['blog_id'] ) );
+ }
+ }
+
+ $themes = array();
+ 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 ];
+ } else {
+ $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 ] );
+ }
+ }
+ }
+
+ return $themes;
+}
+
+/**
+ * Gets a WP_Theme object for a theme.
+ *
+ * @since 3.4.0
+ *
+ * @global array $wp_theme_directories
+ *
+ * @param string $stylesheet Directory name for the theme. Optional. Defaults to current theme.
+ * @param string $theme_root Absolute path of the theme root to look in. Optional. 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 ) ) {
+ $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.
+ *
+ * @since 3.5.0
+ * @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 ) {
+ $theme->cache_delete();
+ }
+}
+
+/**
+ * Whether a child theme is in use.
+ *
+ * @since 3.0.0
+ *
+ * @return bool true if a child theme is in use, false otherwise.
+ */
+function is_child_theme() {
+ return ( TEMPLATEPATH !== STYLESHEETPATH );
+}
+
+/**
+ * Retrieve name of the current stylesheet.
+ *
+ * The theme name that the administrator has currently set the front end theme
+ * as.
+ *
+ * For all intents and purposes, the template name and the stylesheet name are
+ * going to be the same for most cases.
+ *
+ * @since 1.5.0
+ *
+ * @return string Stylesheet name.
+ */
+function get_stylesheet() {
+ /**
+ * Filters the name of current stylesheet.
+ *
+ * @since 1.5.0
+ *
+ * @param string $stylesheet Name of the current stylesheet.
+ */
+ return apply_filters( 'stylesheet', get_option( 'stylesheet' ) );
+}
+
+/**
+ * Retrieve stylesheet directory path for current theme.
+ *
+ * @since 1.5.0
+ *
+ * @return string Path to current theme 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.
+ *
+ * @since 1.5.0
+ *
+ * @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 );
+}
+
+/**
+ * Retrieve stylesheet directory URI.
+ *
+ * @since 1.5.0
+ *
+ * @return string
+ */
+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.
+ *
+ * @since 1.5.0
+ *
+ * @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 the URI of current theme stylesheet.
+ *
+ * The stylesheet file name is 'style.css' which is appended to the stylesheet directory URI path.
+ * See get_stylesheet_directory_uri().
+ *
+ * @since 1.5.0
+ *
+ * @return string
+ */
+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.
+ *
+ * @since 1.5.0
+ *
+ * @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.
+ *
+ * @since 2.1.0
+ *
+ * @global WP_Locale $wp_locale WordPress date and time locale object.
+ *
+ * @return string
+ */
+function get_locale_stylesheet_uri() {
+ global $wp_locale;
+ $stylesheet_dir_uri = get_stylesheet_directory_uri();
+ $dir = get_stylesheet_directory();
+ $locale = get_locale();
+ 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";
+ } else {
+ $stylesheet_uri = '';
+ }
+ /**
+ * Filters the localized stylesheet URI.
+ *
+ * @since 2.1.0
+ *
+ * @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 );
+}
+
+/**
+ * Retrieve name of the current theme.
+ *
+ * @since 1.5.0
+ *
+ * @return string Template name.
+ */
+function get_template() {
+ /**
+ * Filters the name of the current theme.
+ *
+ * @since 1.5.0
+ *
+ * @param string $template Current theme's directory name.
+ */
+ return apply_filters( 'template', get_option( 'template' ) );
+}
+
+/**
+ * Retrieve current theme directory.
+ *
+ * @since 1.5.0
+ *
+ * @return string Template directory path.
+ */
+function get_template_directory() {
+ $template = get_template();
+ $theme_root = get_theme_root( $template );
+ $template_dir = "$theme_root/$template";
+
+ /**
+ * Filters the current theme directory path.
+ *
+ * @since 1.5.0
+ *
+ * @param string $template_dir The URI 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 );
+}
+
+/**
+ * Retrieve theme directory URI.
+ *
+ * @since 1.5.0
+ *
+ * @return string Template directory URI.
+ */
+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.
+ *
+ * @since 1.5.0
+ *
+ * @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 );
+}
+
+/**
+ * Retrieve theme roots.
+ *
+ * @since 2.9.0
+ *
+ * @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 ) {
+ return '/themes';
+ }
+
+ $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' );
+ }
+ return $theme_roots;
+}
+
+/**
+ * Register a directory that contains themes.
+ *
+ * @since 2.9.0
+ *
+ * @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
+ */
+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 ) ) {
+ return false;
+ }
+ }
+
+ if ( ! is_array( $wp_theme_directories ) ) {
+ $wp_theme_directories = array();
+ }
+
+ $untrailed = untrailingslashit( $directory );
+ if ( ! empty( $untrailed ) && ! in_array( $untrailed, $wp_theme_directories ) ) {
+ $wp_theme_directories[] = $untrailed;
+ }
+
+ return true;
+}
+
+/**
+ * Search all registered theme directories for complete and valid themes.
+ *
+ * @since 2.9.0
+ *
+ * @global array $wp_theme_directories
+ * @staticvar array $found_themes
+ *
+ * @param bool $force Optional. Whether to force a new directory scan. Defaults to false.
+ * @return array|false Valid themes found
+ */
+function search_theme_directories( $force = false ) {
+ global $wp_theme_directories;
+ static $found_themes = null;
+
+ if ( empty( $wp_theme_directories ) ) {
+ return false;
+ }
+
+ if ( ! $force && isset( $found_themes ) ) {
+ return $found_themes;
+ }
+
+ $found_themes = array();
+
+ $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;
+ } else {
+ $relative_theme_roots[ $theme_root ] = $theme_root;
+ }
+ }
+
+ /**
+ * Filters whether to get the cache of the registered theme directories.
+ *
+ * @since 3.4.0
+ *
+ * @param bool $cache_expiration Whether to get the cache of the theme directories. Default false.
+ * @param string $cache_directory Directory to be searched for the cache.
+ */
+ $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 ] ) ) {
+ continue;
+ }
+ $found_themes[ $theme_dir ] = array(
+ 'theme_file' => $theme_dir . '/style.css',
+ 'theme_root' => $relative_theme_roots[ $theme_root ], // Convert relative to absolute.
+ );
+ }
+ return $found_themes;
+ }
+ if ( ! is_int( $cache_expiration ) ) {
+ $cache_expiration = 1800; // half hour
+ }
+ } else {
+ $cache_expiration = 1800; // half hour
+ }
+
+ /* Loop the registered theme directories and extract all themes */
+ foreach ( $wp_theme_directories as $theme_root ) {
+
+ // Start with directories in the root of the current theme directory.
+ $dirs = @ scandir( $theme_root );
+ if ( ! $dirs ) {
+ trigger_error( "$theme_root is not readable", E_USER_NOTICE );
+ continue;
+ }
+ foreach ( $dirs as $dir ) {
+ if ( ! is_dir( $theme_root . '/' . $dir ) || $dir[0] == '.' || $dir == 'CVS' ) {
+ continue;
+ }
+ if ( file_exists( $theme_root . '/' . $dir . '/style.css' ) ) {
+ // wp-content/themes/a-single-theme
+ // wp-content/themes is $theme_root, a-single-theme is $dir
+ $found_themes[ $dir ] = array(
+ 'theme_file' => $dir . '/style.css',
+ 'theme_root' => $theme_root,
+ );
+ } else {
+ $found_theme = false;
+ // wp-content/themes/a-folder-of-themes/*
+ // wp-content/themes is $theme_root, a-folder-of-themes is $dir, then themes are $sub_dirs
+ $sub_dirs = @ scandir( $theme_root . '/' . $dir );
+ if ( ! $sub_dirs ) {
+ trigger_error( "$theme_root/$dir is not readable", E_USER_NOTICE );
+ continue;
+ }
+ foreach ( $sub_dirs as $sub_dir ) {
+ if ( ! is_dir( $theme_root . '/' . $dir . '/' . $sub_dir ) || $dir[0] == '.' || $dir == 'CVS' ) {
+ continue;
+ }
+ if ( ! file_exists( $theme_root . '/' . $dir . '/' . $sub_dir . '/style.css' ) ) {
+ continue;
+ }
+ $found_themes[ $dir . '/' . $sub_dir ] = array(
+ 'theme_file' => $dir . '/' . $sub_dir . '/style.css',
+ 'theme_root' => $theme_root,
+ );
+ $found_theme = true;
+ }
+ // Never mind the above, it's just a theme missing a style.css.
+ // Return it; WP_Theme will catch the error.
+ if ( ! $found_theme ) {
+ $found_themes[ $dir ] = array(
+ 'theme_file' => $dir . '/style.css',
+ 'theme_root' => $theme_root,
+ );
+ }
+ }
+ }
+ }
+
+ asort( $found_themes );
+
+ $theme_roots = array();
+ $relative_theme_roots = array_flip( $relative_theme_roots );
+
+ foreach ( $found_themes as $theme_dir => $theme_data ) {
+ $theme_roots[ $theme_dir ] = $relative_theme_roots[ $theme_data['theme_root'] ]; // Convert absolute to relative.
+ }
+
+ if ( $theme_roots != get_site_transient( 'theme_roots' ) ) {
+ set_site_transient( 'theme_roots', $theme_roots, $cache_expiration );
+ }
+
+ return $found_themes;
+}
+
+/**
+ * Retrieve path to themes directory.
+ *
+ * Does not have trailing slash.
+ *
+ * @since 1.5.0
+ *
+ * @global array $wp_theme_directories
+ *
+ * @param string $stylesheet_or_template Optional. The stylesheet or template name of the theme.
+ * Default is to leverage the main theme root.
+ * @return string Themes directory path.
+ */
+function get_theme_root( $stylesheet_or_template = '' ) {
+ global $wp_theme_directories;
+
+ $theme_root = '';
+
+ if ( $stylesheet_or_template ) {
+ $theme_root = get_raw_theme_root( $stylesheet_or_template );
+ if ( $theme_root ) {
+ // Always prepend WP_CONTENT_DIR unless the root currently registered as a theme directory.
+ // This gives relative theme roots the benefit of the doubt when things go haywire.
+ if ( ! in_array( $theme_root, (array) $wp_theme_directories ) ) {
+ $theme_root = WP_CONTENT_DIR . $theme_root;
+ }
+ }
+ }
+
+ if ( ! $theme_root ) {
+ $theme_root = WP_CONTENT_DIR . '/themes';
+ }
+
+ /**
+ * Filters the absolute path to the themes directory.
+ *
+ * @since 1.5.0
+ *
+ * @param string $theme_root Absolute path to themes directory.
+ */
+ return apply_filters( 'theme_root', $theme_root );
+}
+
+/**
+ * Retrieve URI for themes directory.
+ *
+ * Does not have trailing slash.
+ *
+ * @since 1.5.0
+ *
+ * @global array $wp_theme_directories
+ *
+ * @param string $stylesheet_or_template Optional. The stylesheet or template name of the theme.
+ * Default is to leverage the main theme root.
+ * @param string $theme_root Optional. The theme root for which calculations will be based,
+ * preventing the need for a get_raw_theme_root() call. Default empty.
+ * @return string Themes directory URI.
+ */
+function get_theme_root_uri( $stylesheet_or_template = '', $theme_root = '' ) {
+ global $wp_theme_directories;
+
+ if ( $stylesheet_or_template && ! $theme_root ) {
+ $theme_root = get_raw_theme_root( $stylesheet_or_template );
+ }
+
+ if ( $stylesheet_or_template && $theme_root ) {
+ if ( in_array( $theme_root, (array) $wp_theme_directories ) ) {
+ // Absolute path. Make an educated guess. YMMV -- but note the filter below.
+ if ( 0 === strpos( $theme_root, WP_CONTENT_DIR ) ) {
+ $theme_root_uri = content_url( str_replace( WP_CONTENT_DIR, '', $theme_root ) );
+ } elseif ( 0 === strpos( $theme_root, ABSPATH ) ) {
+ $theme_root_uri = site_url( str_replace( ABSPATH, '', $theme_root ) );
+ } elseif ( 0 === strpos( $theme_root, WP_PLUGIN_DIR ) || 0 === strpos( $theme_root, WPMU_PLUGIN_DIR ) ) {
+ $theme_root_uri = plugins_url( basename( $theme_root ), $theme_root );
+ } else {
+ $theme_root_uri = $theme_root;
+ }
+ } else {
+ $theme_root_uri = content_url( $theme_root );
+ }
+ } else {
+ $theme_root_uri = content_url( 'themes' );
+ }
+
+ /**
+ * Filters the URI for themes directory.
+ *
+ * @since 1.5.0
+ *
+ * @param string $theme_root_uri The URI for themes directory.
+ * @param string $siteurl WordPress web address which is set in General Options.
+ * @param string $stylesheet_or_template The stylesheet or template name of the theme.
+ */
+ return apply_filters( 'theme_root_uri', $theme_root_uri, get_option( 'siteurl' ), $stylesheet_or_template );
+}
+
+/**
+ * Get the raw theme root relative to the content directory with no filters applied.
+ *
+ * @since 3.1.0
+ *
+ * @global array $wp_theme_directories
+ *
+ * @param string $stylesheet_or_template The stylesheet or template name of the theme.
+ * @param bool $skip_cache Optional. Whether to skip the cache.
+ * Defaults to false, meaning the cache is used.
+ * @return string Theme root.
+ */
+function get_raw_theme_root( $stylesheet_or_template, $skip_cache = false ) {
+ global $wp_theme_directories;
+
+ if ( ! is_array( $wp_theme_directories ) || count( $wp_theme_directories ) <= 1 ) {
+ return '/themes';
+ }
+
+ $theme_root = false;
+
+ // If requesting the root for the current theme, consult options to avoid calling get_theme_roots()
+ if ( ! $skip_cache ) {
+ if ( get_option( 'stylesheet' ) == $stylesheet_or_template ) {
+ $theme_root = get_option( 'stylesheet_root' );
+ } elseif ( get_option( 'template' ) == $stylesheet_or_template ) {
+ $theme_root = get_option( 'template_root' );
+ }
+ }
+
+ if ( empty( $theme_root ) ) {
+ $theme_roots = get_theme_roots();
+ if ( ! empty( $theme_roots[ $stylesheet_or_template ] ) ) {
+ $theme_root = $theme_roots[ $stylesheet_or_template ];
+ }
+ }
+
+ return $theme_root;
+}
+
+/**
+ * Display localized stylesheet link element.
+ *
+ * @since 2.1.0
+ */
+function locale_stylesheet() {
+ $stylesheet = get_locale_stylesheet_uri();
+ if ( empty( $stylesheet ) ) {
+ return;
+ }
+
+ $type_attr = current_theme_supports( 'html5', 'style' ) ? '' : ' type="text/css"';
+
+ printf(
+ '<link rel="stylesheet" href="%s"%s media="screen" />',
+ $stylesheet,
+ $type_attr
+ );
+}
+
+/**
+ * Switches the theme.
+ *
+ * Accepts one argument: $stylesheet of the theme. It also accepts an additional function signature
+ * of two arguments: $template then $stylesheet. This is for backward compatibility.
+ *
+ * @since 2.5.0
+ *
+ * @global array $wp_theme_directories
+ * @global WP_Customize_Manager $wp_customize
+ * @global array $sidebars_widgets
+ *
+ * @param string $stylesheet Stylesheet name
+ */
+function switch_theme( $stylesheet ) {
+ global $wp_theme_directories, $wp_customize, $sidebars_widgets;
+
+ $_sidebars_widgets = null;
+ if ( 'wp_ajax_customize_save' === current_action() ) {
+ $old_sidebars_widgets_data_setting = $wp_customize->get_setting( 'old_sidebars_widgets_data' );
+ if ( $old_sidebars_widgets_data_setting ) {
+ $_sidebars_widgets = $wp_customize->post_value( $old_sidebars_widgets_data_setting );
+ }
+ } elseif ( is_array( $sidebars_widgets ) ) {
+ $_sidebars_widgets = $sidebars_widgets;
+ }
+
+ if ( is_array( $_sidebars_widgets ) ) {
+ set_theme_mod(
+ 'sidebars_widgets',
+ array(
+ 'time' => time(),
+ 'data' => $_sidebars_widgets,
+ )
+ );
+ }
+
+ $nav_menu_locations = get_theme_mod( 'nav_menu_locations' );
+ update_option( 'theme_switch_menu_locations', $nav_menu_locations );
+
+ if ( func_num_args() > 1 ) {
+ $stylesheet = func_get_arg( 1 );
+ }
+
+ $old_theme = wp_get_theme();
+ $new_theme = wp_get_theme( $stylesheet );
+ $template = $new_theme->get_template();
+
+ if ( wp_is_recovery_mode() ) {
+ $paused_themes = wp_paused_themes();
+ $paused_themes->delete( $old_theme->get_stylesheet() );
+ $paused_themes->delete( $old_theme->get_template() );
+ }
+
+ update_option( 'template', $template );
+ update_option( 'stylesheet', $stylesheet );
+
+ if ( count( $wp_theme_directories ) > 1 ) {
+ update_option( 'template_root', get_raw_theme_root( $template, true ) );
+ update_option( 'stylesheet_root', get_raw_theme_root( $stylesheet, true ) );
+ } else {
+ delete_option( 'template_root' );
+ delete_option( 'stylesheet_root' );
+ }
+
+ $new_name = $new_theme->get( 'Name' );
+
+ update_option( 'current_theme', $new_name );
+
+ // Migrate from the old mods_{name} option to theme_mods_{slug}.
+ if ( is_admin() && false === get_option( 'theme_mods_' . $stylesheet ) ) {
+ $default_theme_mods = (array) get_option( 'mods_' . $new_name );
+ if ( ! empty( $nav_menu_locations ) && empty( $default_theme_mods['nav_menu_locations'] ) ) {
+ $default_theme_mods['nav_menu_locations'] = $nav_menu_locations;
+ }
+ add_option( "theme_mods_$stylesheet", $default_theme_mods );
+ } else {
+ /*
+ * Since retrieve_widgets() is called when initializing a theme in the Customizer,
+ * we need to remove the theme mods to avoid overwriting changes made via
+ * the Customizer when accessing wp-admin/widgets.php.
+ */
+ if ( 'wp_ajax_customize_save' === current_action() ) {
+ remove_theme_mod( 'sidebars_widgets' );
+ }
+ }
+
+ update_option( 'theme_switched', $old_theme->get_stylesheet() );
+
+ /**
+ * Fires after the theme is switched.
+ *
+ * @since 1.5.0
+ * @since 4.5.0 Introduced the `$old_theme` parameter.
+ *
+ * @param string $new_name Name of the new theme.
+ * @param WP_Theme $new_theme WP_Theme instance of the new theme.
+ * @param WP_Theme $old_theme WP_Theme instance of the old theme.
+ */
+ do_action( 'switch_theme', $new_name, $new_theme, $old_theme );
+}
+
+/**
+ * Checks that current theme files 'index.php' and 'style.css' exists.
+ *
+ * Does not initially check the default theme, which is the fallback and should always exist.
+ * But if it doesn't exist, it'll fall back to the latest core default theme that does exist.
+ * Will switch theme to the fallback theme if current theme does not validate.
+ *
+ * You can use the {@see 'validate_current_theme'} filter to return false to
+ * disable this functionality.
+ *
+ * @since 1.5.0
+ * @see WP_DEFAULT_THEME
+ *
+ * @return bool
+ */
+function validate_current_theme() {
+ /**
+ * Filters whether to validate the current theme.
+ *
+ * @since 2.7.0
+ *
+ * @param bool $validate Whether to validate the current theme. Default true.
+ */
+ if ( wp_installing() || ! apply_filters( 'validate_current_theme', true ) ) {
+ return true;
+ }
+
+ if ( ! file_exists( get_template_directory() . '/index.php' ) ) {
+ // Invalid.
+ } elseif ( ! file_exists( get_template_directory() . '/style.css' ) ) {
+ // Invalid.
+ } elseif ( is_child_theme() && ! file_exists( get_stylesheet_directory() . '/style.css' ) ) {
+ // Invalid.
+ } else {
+ // Valid.
+ return true;
+ }
+
+ $default = wp_get_theme( WP_DEFAULT_THEME );
+ if ( $default->exists() ) {
+ switch_theme( WP_DEFAULT_THEME );
+ return false;
+ }
+
+ /**
+ * If we're in an invalid state but WP_DEFAULT_THEME doesn't exist,
+ * switch to the latest core default theme that's installed.
+ * If it turns out that this latest core default theme is our current
+ * theme, then there's nothing we can do about that, so we have to bail,
+ * rather than going into an infinite loop. (This is why there are
+ * checks against WP_DEFAULT_THEME above, also.) We also can't do anything
+ * if it turns out there is no default theme installed. (That's `false`.)
+ */
+ $default = WP_Theme::get_core_default_theme();
+ if ( false === $default || get_stylesheet() == $default->get_stylesheet() ) {
+ return true;
+ }
+
+ switch_theme( $default->get_stylesheet() );
+ return false;
+}
+
+/**
+ * Retrieve all theme modifications.
+ *
+ * @since 3.1.0
+ *
+ * @return array|void Theme modifications.
+ */
+function get_theme_mods() {
+ $theme_slug = get_option( 'stylesheet' );
+ $mods = get_option( "theme_mods_$theme_slug" );
+ if ( false === $mods ) {
+ $theme_name = get_option( 'current_theme' );
+ if ( false === $theme_name ) {
+ $theme_name = wp_get_theme()->get( 'Name' );
+ }
+ $mods = get_option( "mods_$theme_name" ); // Deprecated location.
+ if ( is_admin() && false !== $mods ) {
+ update_option( "theme_mods_$theme_slug", $mods );
+ delete_option( "mods_$theme_name" );
+ }
+ }
+ return $mods;
+}
+
+/**
+ * Retrieve theme modification value for the current theme.
+ *
+ * If the modification name does not exist, then the $default will be passed
+ * through {@link https://secure.php.net/sprintf sprintf()} PHP function with
+ * the template directory URI as the first string and the stylesheet directory URI
+ * as the second string.
+ *
+ * @since 2.1.0
+ *
+ * @param string $name Theme modification name.
+ * @param string|false $default Optional. Theme modification default value. Default false.
+ * @return mixed Theme modification value.
+ */
+function get_theme_mod( $name, $default = false ) {
+ $mods = get_theme_mods();
+
+ if ( isset( $mods[ $name ] ) ) {
+ /**
+ * Filters the theme modification, or 'theme_mod', value.
+ *
+ * The dynamic portion of the hook name, `$name`, refers to the key name
+ * of the modification array. For example, 'header_textcolor', 'header_image',
+ * and so on depending on the theme options.
+ *
+ * @since 2.2.0
+ *
+ * @param string $current_mod The value of the current theme modification.
+ */
+ return apply_filters( "theme_mod_{$name}", $mods[ $name ] );
+ }
+
+ if ( is_string( $default ) ) {
+ // Only run the replacement if an sprintf() string format pattern was found.
+ if ( preg_match( '#(?<!%)%(?:\d+\$?)?s#', $default ) ) {
+ $default = sprintf( $default, get_template_directory_uri(), get_stylesheet_directory_uri() );
+ }
+ }
+
+ /** This filter is documented in wp-includes/theme.php */
+ return apply_filters( "theme_mod_{$name}", $default );
+}
+
+/**
+ * Update theme modification value for the current theme.
+ *
+ * @since 2.1.0
+ *
+ * @param string $name Theme modification name.
+ * @param mixed $value Theme modification value.
+ */
+function set_theme_mod( $name, $value ) {
+ $mods = get_theme_mods();
+ $old_value = isset( $mods[ $name ] ) ? $mods[ $name ] : false;
+
+ /**
+ * Filters the theme modification, or 'theme_mod', value on save.
+ *
+ * The dynamic portion of the hook name, `$name`, refers to the key name
+ * of the modification array. For example, 'header_textcolor', 'header_image',
+ * and so on depending on the theme options.
+ *
+ * @since 3.9.0
+ *
+ * @param string $value The new value of the theme modification.
+ * @param string $old_value The current value of the theme modification.
+ */
+ $mods[ $name ] = apply_filters( "pre_set_theme_mod_{$name}", $value, $old_value );
+
+ $theme = get_option( 'stylesheet' );
+ update_option( "theme_mods_$theme", $mods );
+}
+
+/**
+ * Remove theme modification name from current theme list.
+ *
+ * If removing the name also removes all elements, then the entire option will
+ * be removed.
+ *
+ * @since 2.1.0
+ *
+ * @param string $name Theme modification name.
+ */
+function remove_theme_mod( $name ) {
+ $mods = get_theme_mods();
+
+ if ( ! isset( $mods[ $name ] ) ) {
+ return;
+ }
+
+ unset( $mods[ $name ] );
+
+ if ( empty( $mods ) ) {
+ remove_theme_mods();
+ return;
+ }
+ $theme = get_option( 'stylesheet' );
+ update_option( "theme_mods_$theme", $mods );
+}
+
+/**
+ * Remove theme modifications option for current theme.
+ *
+ * @since 2.1.0
+ */
+function remove_theme_mods() {
+ delete_option( 'theme_mods_' . get_option( 'stylesheet' ) );
+
+ // Old style.
+ $theme_name = get_option( 'current_theme' );
+ if ( false === $theme_name ) {
+ $theme_name = wp_get_theme()->get( 'Name' );
+ }
+ delete_option( 'mods_' . $theme_name );
+}
+
+/**
+ * Retrieves the custom header text color in 3- or 6-digit hexadecimal form.
+ *
+ * @since 2.1.0
+ *
+ * @return string Header text color in 3- or 6-digit hexadecimal form (minus the hash symbol).
+ */
+function get_header_textcolor() {
+ return get_theme_mod( 'header_textcolor', get_theme_support( 'custom-header', 'default-text-color' ) );
+}
+
+/**
+ * Displays the custom header text color in 3- or 6-digit hexadecimal form (minus the hash symbol).
+ *
+ * @since 2.1.0
+ */
+function header_textcolor() {
+ echo get_header_textcolor();
+}
+
+/**
+ * Whether to display the header text.
+ *
+ * @since 3.4.0
+ *
+ * @return bool
+ */
+function display_header_text() {
+ if ( ! current_theme_supports( 'custom-header', 'header-text' ) ) {
+ return false;
+ }
+
+ $text_color = get_theme_mod( 'header_textcolor', get_theme_support( 'custom-header', 'default-text-color' ) );
+ return 'blank' !== $text_color;
+}
+
+/**
+ * Check whether a header image is set or not.
+ *
+ * @since 4.2.0
+ *
+ * @see get_header_image()
+ *
+ * @return bool Whether a header image is set or not.
+ */
+function has_header_image() {
+ return (bool) get_header_image();
+}
+
+/**
+ * Retrieve header image for custom header.
+ *
+ * @since 2.1.0
+ *
+ * @return string|false
+ */
+function get_header_image() {
+ $url = get_theme_mod( 'header_image', get_theme_support( 'custom-header', 'default-image' ) );
+
+ if ( 'remove-header' == $url ) {
+ return false;
+ }
+
+ if ( is_random_header_image() ) {
+ $url = get_random_header_image();
+ }
+
+ return esc_url_raw( set_url_scheme( $url ) );
+}
+
+/**
+ * Create image tag markup for a custom header image.
+ *
+ * @since 4.4.0
+ *
+ * @param array $attr Optional. Additional attributes for the image tag. Can be used
+ * to override the default attributes. Default empty.
+ * @return string HTML image element markup or empty string on failure.
+ */
+function get_header_image_tag( $attr = array() ) {
+ $header = get_custom_header();
+ $header->url = get_header_image();
+