diff options
Diffstat (limited to 'srcs/wordpress/wp-includes/theme.php')
| -rw-r--r-- | srcs/wordpress/wp-includes/theme.php | 3364 |
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(); + |
