From e71167bbeee0e510cf9c04966eaa3f3726aea944 Mon Sep 17 00:00:00 2001 From: Andrew Nacin Date: Thu, 15 Mar 2012 15:39:21 +0000 Subject: [PATCH] Updates to WP_Theme, wp_get_themes(), and related deprecated functions, after [UT570] [UT578] [UT579]. see #20103. * ['Template Files'] and ['Stylesheet Files'] need to return files from the parent theme as well. * Don't strip links from the Author header. Some themes rely on the previous behavior, such as to link multiple authors (Sandbox, for example.) Don't restore links to the Name, that's just a bad idea. * Ensure we are always passing around arrays in get_files/scandir. * Better inline doc for wp_get_themes() arguments. * Introduce a 'force' flag for search_theme_directories() to re-scan, rather than return the cache. We will use this to re-build the theme_roots transient in get_theme_roots(), but it is more helpful for unit tests. Since search_theme_directories() is cached, don't cache again in wp_get_themes(). (Again benefits testing.) * Handle duplicate theme names in the old get_themes() when two themes match (and neither are a default theme, which is already handled). wp_get_themes() will consider both names to be the same; this is just for back compat since get_themes() is keyed by name. * Include an old array key in wp_broken_themes(). git-svn-id: https://develop.svn.wordpress.org/trunk@20193 602fd350-edb4-49c9-b593-d223f7449a82 --- wp-admin/includes/deprecated.php | 6 +++-- wp-includes/class-wp-theme.php | 24 +++++++++---------- wp-includes/deprecated.php | 6 ++++- wp-includes/theme.php | 40 ++++++++++++++++++-------------- 4 files changed, 43 insertions(+), 33 deletions(-) diff --git a/wp-admin/includes/deprecated.php b/wp-admin/includes/deprecated.php index ff24583e8c..747b228d53 100644 --- a/wp-admin/includes/deprecated.php +++ b/wp-admin/includes/deprecated.php @@ -917,8 +917,10 @@ function get_broken_themes() { $themes = wp_get_themes( array( 'errors' => true ) ); $broken = array(); foreach ( $themes as $theme ) { - $broken[ $theme->get('Name') ] = array( - 'Title' => $theme->get('Name'), + $name = $theme->get('Name'); + $broken[ $name ] = array( + 'Name' => $name, + 'Title' => $name, 'Description' => $theme->errors()->get_error_message(), ); } diff --git a/wp-includes/class-wp-theme.php b/wp-includes/class-wp-theme.php index 4e020d28a4..a4ee60906b 100644 --- a/wp-includes/class-wp-theme.php +++ b/wp-includes/class-wp-theme.php @@ -384,12 +384,12 @@ final class WP_Theme implements ArrayAccess { case 'Stylesheet' : return $this->get_stylesheet(); case 'Template Files' : - $files = $this->get_files('php'); + $files = $this->get_files('php', true); foreach ( $files as &$file ) $file = $this->theme_root . '/' . $file; return $files; case 'Stylesheet Files' : - $files = $this->get_files('css'); + $files = $this->get_files('css', true); foreach ( $files as &$file ) $file = $this->theme_root . '/' . $file; return $files; @@ -555,7 +555,6 @@ final class WP_Theme implements ArrayAccess { } // Fall through otherwise. case 'Name' : - case 'Author' : static $header_tags = array( 'abbr' => array( 'title' => true ), 'acronym' => array( 'title' => true ), @@ -565,6 +564,8 @@ final class WP_Theme implements ArrayAccess { ); $value = wp_kses( $value, $header_tags ); break; + case 'Author' : + // There shouldn't be anchor tags in Author, but some themes like to be challenging. case 'Description' : static $header_tags_with_a = array( 'a' => array( 'href' => true, 'title' => true ), @@ -935,7 +936,9 @@ final class WP_Theme implements ArrayAccess { if ( $include_parent_files || ! $this->is_child_theme() ) // Template files can be one level down for the purposes of the theme editor, so this should be $depth = 1. // Todo: We ignore this for now, but this is why the branching is weird. - $files = (array) self::scandir( $this->get_template_directory(), $this->get_template(), array( 'php', 'css' ) ); + $files = self::scandir( $this->get_template_directory(), $this->get_template(), array( 'php', 'css' ) ); + else + $files = array(); if ( $this->is_child_theme() ) $files = array_merge_recursive( $files, (array) self::scandir( $this->get_stylesheet_directory(), $this->get_stylesheet(), array( 'php', 'css' ) ) ); foreach ( $files as &$group ) @@ -989,14 +992,14 @@ final class WP_Theme implements ArrayAccess { * @depth int How deep to search for files. Optional, defaults to a flat scan (0 depth). */ private static function scandir( $path, $relative_path, $extensions, $depth = 0 ) { - if ( is_array( $extensions ) ) - $extensions = implode( '|', $extensions ); - if ( ! is_dir( $path ) ) return false; $results = scandir( $path ); - $files = array(); + + $extensions = (array) $extensions; + $files = array_fill_keys( $extensions, array() ); + $extensions = implode( '|', $extensions ); foreach ( $results as $result ) { if ( '.' == $result || '..' == $result ) @@ -1007,10 +1010,7 @@ final class WP_Theme implements ArrayAccess { $found = self::scandir( $path . '/' . $result, $relative_path . '/' . $result, $extensions, $depth - 1 ); $files = array_merge_recursive( $files, $found ); } elseif ( preg_match( '~\.(' . $extensions . ')$~', $result, $match ) ) { - if ( ! isset( $files[ $match[1] ] ) ) - $files[ $match[1] ] = array( $relative_path . '/'. $result ); - else - $files[ $match[1] ][] = $relative_path . '/' . $result; + $files[ $match[1] ][] = $relative_path . '/' . $result; } } return $files; diff --git a/wp-includes/deprecated.php b/wp-includes/deprecated.php index 490ec50d3a..2c92952974 100644 --- a/wp-includes/deprecated.php +++ b/wp-includes/deprecated.php @@ -2933,7 +2933,11 @@ function get_themes() { $wp_themes = array(); foreach ( $themes as $theme ) { - $wp_themes[ $theme->get('Name') ] = $theme; + $name = $theme->get('Name'); + if ( isset( $wp_themes[ $name ] ) ) + $wp_themes[ $name . '/' . $theme->get_stylesheet() ] = $theme; + else + $wp_themes[ $name ] = $theme; } return $wp_themes; diff --git a/wp-includes/theme.php b/wp-includes/theme.php index 65da096c04..0e7fb184c3 100644 --- a/wp-includes/theme.php +++ b/wp-includes/theme.php @@ -9,14 +9,19 @@ /** * Returns an array of WP_Theme objects based on the arguments. * - * Despite advances over get_themes(), this function is still quite expensive, and grows + * 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 * - * @param array $args Arguments. Currently 'errors' (defaults to false), 'allowed' - * (true, false; null for either; defaults to null; only applies to multisite), and 'blog_id' - * (defaults to current blog; used to find allowed themes; only applies to multisite). + * @param array $args The search arguments. Optional. + * - errors mixed True to return themes with errors, false to return themes without errors, null + * to return all themes. Defaults to false. + * - allowed mixed (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. + * - blog_id int (Multisite) The blog ID used to calculate which themes are allowed. Defaults to 0, + * synonymous for the current blog. * @return Array of WP_Theme objects. */ function wp_get_themes( $args = array() ) { @@ -25,25 +30,23 @@ function wp_get_themes( $args = array() ) { $defaults = array( 'errors' => false, 'allowed' => null, 'blog_id' => 0 ); $args = wp_parse_args( $args, $defaults ); - static $_theme_directories, $_themes = array(); - if ( ! isset( $_theme_directories ) ) { - $_theme_directories = search_theme_directories(); - if ( 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(); + $theme_directories = search_theme_directories(); + + if ( 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; + $theme_directories[ $current_theme ]['theme_root'] = $root_of_current_theme; } } - if ( empty( $_theme_directories ) ) + if ( empty( $theme_directories ) ) return array(); - $theme_directories = $_theme_directories; - if ( is_multisite() && null !== $args['allowed'] ) { $allowed = $args['allowed']; if ( 'network' === $allowed ) @@ -355,7 +358,7 @@ function get_theme_roots() { $theme_roots = get_site_transient( 'theme_roots' ); if ( false === $theme_roots ) { - search_theme_directories(); // Regenerate the transient. + search_theme_directories( true ); // Regenerate the transient. $theme_roots = get_site_transient( 'theme_roots' ); } return $theme_roots; @@ -390,15 +393,16 @@ function register_theme_directory( $directory ) { * * @since 2.9.0 * + * @param bool $force Optional. Whether to force a new directory scan. Defaults to false. * @return array Valid themes found */ -function search_theme_directories() { +function search_theme_directories( $force = false ) { global $wp_theme_directories; if ( empty( $wp_theme_directories ) ) return false; static $found_themes; - if ( isset( $found_themes ) ) + if ( ! $force && isset( $found_themes ) ) return $found_themes; $found_themes = array();