Introduce WP_Theme->exists() to check if the queried theme actually exists. WP_Theme->exists() is a subset of errors() -- a theme with errors may still exist, but a theme that does not exist has an error of theme_not_found. wp_get_theme() now returns false if the theme does not exist. Improve scandir() and get_files() logic. see #20103.

git-svn-id: http://svn.automattic.com/wordpress/trunk@20312 1a063a9b-81f0-0310-95a4-ce76da25c4cd
This commit is contained in:
nacin 2012-03-29 02:59:48 +00:00
parent 3a722f41d7
commit bb4cca4c55
2 changed files with 65 additions and 33 deletions

View File

@ -195,7 +195,10 @@ final class WP_Theme implements ArrayAccess {
$theme_root_template = $cache['theme_root_template'];
} elseif ( ! file_exists( $this->theme_root . '/' . $theme_file ) ) {
$this->headers['Name'] = $this->stylesheet;
$this->errors = new WP_Error( 'theme_no_stylesheet', __( 'Stylesheet is missing.' ) );
if ( ! file_exists( $this->theme_root . '/' . $this->stylesheet ) )
$this->errors = new WP_Error( 'theme_not_found', __( 'The theme directory does not exist.' ) );
else
$this->errors = new WP_Error( 'theme_no_stylesheet', __( 'Stylesheet is missing.' ) );
$this->cache_add( 'theme', array( 'headers' => $this->headers, 'errors' => $this->errors, 'stylesheet' => $this->stylesheet ) );
if ( ! file_exists( $this->theme_root ) ) // Don't cache this one.
$this->errors->add( 'theme_root_missing', __( 'ERROR: The themes directory is either empty or doesn’t exist. Please check your installation.' ) );
@ -384,14 +387,14 @@ final class WP_Theme implements ArrayAccess {
case 'Stylesheet' :
return $this->get_stylesheet();
case 'Template Files' :
$files = $this->get_files('php', true);
foreach ( $files as &$file )
$file = $this->theme_root . '/' . $file;
$files = $this->get_files( 'php', 1 );
if ( $this->parent() )
$files = array_merge( $files, $this->parent()->get_files( 'php', 1 ) );
return $files;
case 'Stylesheet Files' :
$files = $this->get_files('css', true);
foreach ( $files as &$file )
$file = $this->theme_root . '/' . $file;
$files = $this->get_files( 'css' );
if ( $this->parent() )
$files = array_merge( $files, $this->parent()->get_files( 'css' ) );
return $files;
case 'Template Dir' :
return $this->get_template_directory();
@ -424,6 +427,21 @@ final class WP_Theme implements ArrayAccess {
return is_wp_error( $this->errors ) ? $this->errors : false;
}
/**
* Whether the theme exists.
*
* A theme with errors exists. A theme with the error of 'theme_not_found',
* meaning that the theme directory was not found, does not exist.
*
* @since 3.4.0
* @access public
*
* @return bool Whether the theme exists.
*/
public function exists() {
return ! ( is_wp_error( $this->errors ) && in_array( 'theme_not_found', $this->errors->get_error_codes() ) );
}
/**
* Returns reference to the parent theme.
*
@ -474,7 +492,7 @@ final class WP_Theme implements ArrayAccess {
* @since 3.4.0
*/
public function cache_delete() {
foreach ( array( 'theme', 'screenshot', 'screenshot_count', 'files', 'headers' ) as $key )
foreach ( array( 'theme', 'screenshot', 'screenshot_count', 'files', 'headers', 'page_templates' ) as $key )
wp_cache_delete( $key . '-' . $this->cache_hash, 'themes' );
}
@ -891,7 +909,7 @@ final class WP_Theme implements ArrayAccess {
return 0;
$prefix = $this->get_stylesheet() . '/screenshot-';
$files = self::scandir( $this->get_stylesheet_directory(), $this->get_stylesheet(), 'png', 0 );
$files = self::scandir( $this->get_stylesheet_directory(), $this->get_stylesheet(), 'png' );
$screenshot_count = 1;
while ( in_array( $prefix . ( $screenshot_count + 1 ) . '.png', $files['png'] ) )
@ -925,7 +943,7 @@ final class WP_Theme implements ArrayAccess {
}
/**
* Return files in the template and stylesheet directories.
* Return files in the theme's directory. Does not return files found in the parent theme.
*
* @since 3.4.0
* @access public
@ -934,19 +952,13 @@ final class WP_Theme implements ArrayAccess {
* @return array If a specific $type is requested, returns an array of PHP files. If no $type is requested,
* returns an array, with the keys being the file types, and the values being an array of files for those type.
*/
public function get_files( $type = null, $include_parent_files = false ) {
public function get_files( $type = null, $depth = 0 ) {
$files = $this->cache_get( 'files' );
if ( ! is_array( $files ) ) {
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 = 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' ) ) );
$files = (array) self::scandir( $this->get_stylesheet_directory(), array( 'php', 'css' ), $depth );
foreach ( $files as &$group )
sort( $group );
ksort( $group );
unset( $group );
$this->cache_add( 'files', $files );
}
@ -958,6 +970,14 @@ final class WP_Theme implements ArrayAccess {
return array();
}
/**
* Returns the theme's page templates.
*
* @since 3.4.0
* @access public
*
* @return array Array of page templates, keyed by filename, with the value of the translated header name.
*/
public function get_page_templates() {
// If you screw up your current theme and we invalidate your parent, most things still work. Let it slide.
if ( $this->errors() && $this->errors()->get_error_codes() !== array( 'theme_parent_invalid' ) )
@ -968,9 +988,9 @@ final class WP_Theme implements ArrayAccess {
return $page_templates;
$page_templates = array();
$files = (array) self::scandir( $this->get_template_directory(), $this->get_template_directory(), 'php' );
$files = (array) self::scandir( $this->get_template_directory(), 'php' );
if ( $this->is_child_theme() )
$files = array_merge_recursive( $files, (array) self::scandir( $this->get_stylesheet_directory(), $this->get_stylesheet_directory(), 'php' ) );
$files = array_merge_recursive( $files, (array) self::scandir( $this->get_stylesheet_directory(), 'php' ) );
foreach ( $files['php'] as $file ) {
$headers = get_file_data( $file, array( 'Template Name' => 'Template Name' ) );
@ -990,12 +1010,12 @@ final class WP_Theme implements ArrayAccess {
* @access public
*
* @param string $path Absolute path to search.
* @param array|string $extensions Array of extensions to find, or string of a single extension
* @param int $depth How deep to search for files. Optional, defaults to a flat scan (0 depth). -1 depth is infinite.
* @param string $relative_path The basename of the absolute path. Used to control the returned path
* for the found files, particularly when this function recurses to lower depths.
* @param array|string $extensions Array of extensions to find, or string of a single extension.
* @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 ) {
private static function scandir( $path, $extensions, $depth = 1, $relative_path = '' ) {
if ( ! is_dir( $path ) )
return false;
@ -1003,20 +1023,25 @@ final class WP_Theme implements ArrayAccess {
$extensions = (array) $extensions;
$files = array_fill_keys( $extensions, array() );
$extensions = implode( '|', $extensions );
$_extensions = implode( '|', $extensions );
$relative_path = trailingslashit( $relative_path );
if ( '/' == $relative_path )
$relative_path = '';
foreach ( $results as $result ) {
if ( '.' == $result || '..' == $result )
if ( '.' == $result[0] )
continue;
if ( is_dir( $path . '/' . $result ) ) {
if ( ! $depth )
if ( ! $depth || 'CVS' == $result )
continue;
$found = self::scandir( $path . '/' . $result, $relative_path . '/' . $result, $extensions, $depth - 1 );
$found = self::scandir( $path . '/' . $result, $extensions, $depth - 1 , $relative_path . $result );
$files = array_merge_recursive( $files, $found );
} elseif ( preg_match( '~\.(' . $extensions . ')$~', $result, $match ) ) {
$files[ $match[1] ][] = $relative_path . '/' . $result;
} elseif ( preg_match( '~\.(' . $_extensions . ')$~', $result, $match ) ) {
$files[ $match[1] ][ $relative_path . $result ] = $path . '/' . $result;
}
}
return $files;
}

View File

@ -87,7 +87,7 @@ function wp_get_themes( $args = array() ) {
* @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
* @return WP_Theme|bool WP_Theme object. False if the theme is not found.
*/
function wp_get_theme( $stylesheet = null, $theme_root = null ) {
global $wp_theme_directories;
@ -97,11 +97,18 @@ function wp_get_theme( $stylesheet = null, $theme_root = null ) {
if ( empty( $theme_root ) ) {
$theme_root = get_raw_theme_root( $stylesheet );
if ( false === $theme_root )
return false;
if ( ! in_array( $theme_root, (array) $wp_theme_directories ) )
$theme_root = WP_CONTENT_DIR . $theme_root;
}
return new WP_Theme( $stylesheet, $theme_root );
$theme = new WP_Theme( $stylesheet, $theme_root );
if ( $theme->exists() )
return $theme;
return false;
}
/**