<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head><meta http-equiv="content-type" content="text/html; charset=utf-8" /><style type="text/css"><!--
#msg dl { border: 1px #006 solid; background: #369; padding: 6px; color: #fff; }
#msg dt { float: left; width: 6em; font-weight: bold; }
#msg dt:after { content:':';}
#msg dl, #msg dt, #msg ul, #msg li, #header, #footer { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt;  }
#msg dl a { font-weight: bold}
#msg dl a:link    { color:#fc3; }
#msg dl a:active  { color:#ff0; }
#msg dl a:visited { color:#cc6; }
h3 { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt; font-weight: bold; }
#msg pre, #msg p { overflow: auto; background: #ffc; border: 1px #fc0 solid; padding: 6px; }
#msg ul { overflow: auto; }
#header, #footer { color: #fff; background: #636; border: 1px #300 solid; padding: 6px; }
#patch { width: 100%; }
#patch h4 {font-family: verdana,arial,helvetica,sans-serif;font-size:10pt;padding:8px;background:#369;color:#fff;margin:0;}
#patch .propset h4, #patch .binary h4 {margin:0;}
#patch pre {padding:0;line-height:1.2em;margin:0;}
#patch .diff {width:100%;background:#eee;padding: 0 0 10px 0;overflow:auto;}
#patch .propset .diff, #patch .binary .diff  {padding:10px 0;}
#patch span {display:block;padding:0 10px;}
#patch .modfile, #patch .addfile, #patch .delfile, #patch .propset, #patch .binary, #patch .copfile {border:1px solid #ccc;margin:10px 0;}
#patch ins {background:#dfd;text-decoration:none;display:block;padding:0 10px;}
#patch del {background:#fdd;text-decoration:none;display:block;padding:0 10px;}
#patch .lines, .info {color:#888;background:#fff;}
--></style>
<title>[12025] trunk: Introducing register_theme_directory()
  which takes a wp-content-relative path and will additionally scan it for themes
 .</title>
</head>
<body>

<div id="msg">
<dl>
<dt>Revision</dt> <dd><a href="http://trac.wordpress.org/changeset/12025">12025</a></dd>
<dt>Author</dt> <dd>markjaquith</dd>
<dt>Date</dt> <dd>2009-10-13 19:06:35 +0000 (Tue, 13 Oct 2009)</dd>
</dl>

<h3>Log Message</h3>
<pre>Introducing register_theme_directory() which takes a wp-content-relative path and will additionally scan it for themes. Plugins can use this to add themes without requiring copying by the user. props apeatling. fixes <a href="http://trac.wordpress.org/ticket/10467">#10467</a></pre>

<h3>Modified Paths</h3>
<ul>
<li><a href="#trunkwpadminincludesthemephp">trunk/wp-admin/includes/theme.php</a></li>
<li><a href="#trunkwpadminthemesphp">trunk/wp-admin/themes.php</a></li>
<li><a href="#trunkwpincludesthemephp">trunk/wp-includes/theme.php</a></li>
</ul>

</div>
<div id="patch">
<h3>Diff</h3>
<a id="trunkwpadminincludesthemephp"></a>
<div class="modfile"><h4>Modified: trunk/wp-admin/includes/theme.php (12024 => 12025)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/wp-admin/includes/theme.php        2009-10-13 18:50:16 UTC (rev 12024)
+++ trunk/wp-admin/includes/theme.php        2009-10-13 19:06:35 UTC (rev 12025)
</span><span class="lines">@@ -28,6 +28,8 @@
</span><span class="cx">         $ct-&gt;description = $themes[$current_theme]['Description'];
</span><span class="cx">         $ct-&gt;author = $themes[$current_theme]['Author'];
</span><span class="cx">         $ct-&gt;tags = $themes[$current_theme]['Tags'];
</span><ins>+        $ct-&gt;theme_root = $themes[$current_theme]['Theme Root'];
+        $ct-&gt;theme_root_uri = $themes[$current_theme]['Theme Root URI'];
</ins><span class="cx">         return $ct;
</span><span class="cx"> }
</span><span class="cx"> 
</span></span></pre></div>
<a id="trunkwpadminthemesphp"></a>
<div class="modfile"><h4>Modified: trunk/wp-admin/themes.php (12024 => 12025)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/wp-admin/themes.php        2009-10-13 18:50:16 UTC (rev 12024)
+++ trunk/wp-admin/themes.php        2009-10-13 19:06:35 UTC (rev 12025)
</span><span class="lines">@@ -132,16 +132,16 @@
</span><span class="cx"> &lt;h3&gt;&lt;?php _e('Current Theme'); ?&gt;&lt;/h3&gt;
</span><span class="cx"> &lt;div id=&quot;current-theme&quot;&gt;
</span><span class="cx"> &lt;?php if ( $ct-&gt;screenshot ) : ?&gt;
</span><del>-&lt;img src=&quot;&lt;?php echo content_url($ct-&gt;stylesheet_dir . '/' . $ct-&gt;screenshot); ?&gt;&quot; alt=&quot;&lt;?php _e('Current theme preview'); ?&gt;&quot; /&gt;
</del><ins>+&lt;img src=&quot;&lt;?php echo $ct-&gt;theme_root_uri . '/' . $ct-&gt;stylesheet . '/' . $ct-&gt;screenshot; ?&gt;&quot; alt=&quot;&lt;?php _e('Current theme preview'); ?&gt;&quot; /&gt;
</ins><span class="cx"> &lt;?php endif; ?&gt;
</span><span class="cx"> &lt;h4&gt;&lt;?php
</span><span class="cx">         /* translators: 1: theme title, 2: theme version, 3: theme author */
</span><span class="cx">         printf(__('%1$s %2$s by %3$s'), $ct-&gt;title, $ct-&gt;version, $ct-&gt;author) ; ?&gt;&lt;/h4&gt;
</span><span class="cx"> &lt;p class=&quot;theme-description&quot;&gt;&lt;?php echo $ct-&gt;description; ?&gt;&lt;/p&gt;
</span><span class="cx"> &lt;?php if ($ct-&gt;parent_theme) { ?&gt;
</span><del>-        &lt;p&gt;&lt;?php printf(__('The template files are located in &lt;code&gt;%2$s&lt;/code&gt;.  The stylesheet files are located in &lt;code&gt;%3$s&lt;/code&gt;.  &lt;strong&gt;%4$s&lt;/strong&gt; uses templates from &lt;strong&gt;%5$s&lt;/strong&gt;.  Changes made to the templates will affect both themes.'), $ct-&gt;title, $ct-&gt;template_dir, $ct-&gt;stylesheet_dir, $ct-&gt;title, $ct-&gt;parent_theme); ?&gt;&lt;/p&gt;
</del><ins>+        &lt;p&gt;&lt;?php printf(__('The template files are located in &lt;code&gt;%2$s&lt;/code&gt;.  The stylesheet files are located in &lt;code&gt;%3$s&lt;/code&gt;.  &lt;strong&gt;%4$s&lt;/strong&gt; uses templates from &lt;strong&gt;%5$s&lt;/strong&gt;.  Changes made to the templates will affect both themes.'), $ct-&gt;title, str_replace( WP_CONTENT_DIR, '', $ct-&gt;template_dir ), str_replace( WP_CONTENT_DIR, '', $ct-&gt;stylesheet_dir ), $ct-&gt;title, $ct-&gt;parent_theme); ?&gt;&lt;/p&gt;
</ins><span class="cx"> &lt;?php } else { ?&gt;
</span><del>-        &lt;p&gt;&lt;?php printf(__('All of this theme&amp;#8217;s files are located in &lt;code&gt;%2$s&lt;/code&gt;.'), $ct-&gt;title, $ct-&gt;template_dir, $ct-&gt;stylesheet_dir); ?&gt;&lt;/p&gt;
</del><ins>+        &lt;p&gt;&lt;?php printf(__('All of this theme&amp;#8217;s files are located in &lt;code&gt;%2$s&lt;/code&gt;.'), $ct-&gt;title, str_replace( WP_CONTENT_DIR, '', $ct-&gt;template_dir ), str_replace( WP_CONTENT_DIR, '', $ct-&gt;stylesheet_dir ) ); ?&gt;&lt;/p&gt;
</ins><span class="cx"> &lt;?php } ?&gt;
</span><span class="cx"> &lt;?php if ( $ct-&gt;tags ) : ?&gt;
</span><span class="cx"> &lt;p&gt;&lt;?php _e('Tags:'); ?&gt; &lt;?php echo join(', ', $ct-&gt;tags); ?&gt;&lt;/p&gt;
</span><span class="lines">@@ -203,6 +203,8 @@
</span><span class="cx">         $stylesheet_dir = $themes[$theme_name]['Stylesheet Dir'];
</span><span class="cx">         $template_dir = $themes[$theme_name]['Template Dir'];
</span><span class="cx">         $parent_theme = $themes[$theme_name]['Parent Theme'];
</span><ins>+        $theme_root = $themes[$theme_name]['Theme Root'];
+        $theme_root_uri = $themes[$theme_name]['Theme Root URI'];
</ins><span class="cx">         $preview_link = esc_url(get_option('home') . '/');
</span><span class="cx">         if ( is_ssl() )
</span><span class="cx">                 $preview_link = str_replace( 'http://', 'https://', $preview_link );
</span><span class="lines">@@ -223,7 +225,7 @@
</span><span class="cx"> ?&gt;
</span><span class="cx">                 &lt;a href=&quot;&lt;?php echo $preview_link; ?&gt;&quot; class=&quot;&lt;?php echo $thickbox_class; ?&gt; screenshot&quot;&gt;
</span><span class="cx"> &lt;?php if ( $screenshot ) : ?&gt;
</span><del>-                        &lt;img src=&quot;&lt;?php echo content_url($stylesheet_dir . '/' . $screenshot); ?&gt;&quot; alt=&quot;&quot; /&gt;
</del><ins>+                        &lt;img src=&quot;&lt;?php echo $theme_root_uri . '/' . $stylesheet . '/' . $screenshot; ?&gt;&quot; alt=&quot;&quot; /&gt;
</ins><span class="cx"> &lt;?php endif; ?&gt;
</span><span class="cx">                 &lt;/a&gt;
</span><span class="cx"> &lt;h3&gt;&lt;?php
</span><span class="lines">@@ -233,9 +235,9 @@
</span><span class="cx"> &lt;span class='action-links'&gt;&lt;?php echo $actions ?&gt;&lt;/span&gt;
</span><span class="cx">         &lt;?php if ($parent_theme) {
</span><span class="cx">         /* translators: 1: theme title, 2:  template dir, 3: stylesheet_dir, 4: theme title, 5: parent_theme */ ?&gt;
</span><del>-        &lt;p&gt;&lt;?php printf(__('The template files are located in &lt;code&gt;%2$s&lt;/code&gt;.  The stylesheet files are located in &lt;code&gt;%3$s&lt;/code&gt;.  &lt;strong&gt;%4$s&lt;/strong&gt; uses templates from &lt;strong&gt;%5$s&lt;/strong&gt;.  Changes made to the templates will affect both themes.'), $title, $template_dir, $stylesheet_dir, $title, $parent_theme); ?&gt;&lt;/p&gt;
</del><ins>+        &lt;p&gt;&lt;?php printf(__('The template files are located in &lt;code&gt;%2$s&lt;/code&gt;.  The stylesheet files are located in &lt;code&gt;%3$s&lt;/code&gt;.  &lt;strong&gt;%4$s&lt;/strong&gt; uses templates from &lt;strong&gt;%5$s&lt;/strong&gt;.  Changes made to the templates will affect both themes.'), $title, str_replace( WP_CONTENT_DIR, '', $template_dir ), str_replace( WP_CONTENT_DIR, '', $stylesheet_dir ), $title, $parent_theme); ?&gt;&lt;/p&gt;
</ins><span class="cx"> &lt;?php } else { ?&gt;
</span><del>-        &lt;p&gt;&lt;?php printf(__('All of this theme&amp;#8217;s files are located in &lt;code&gt;%2$s&lt;/code&gt;.'), $title, $template_dir, $stylesheet_dir); ?&gt;&lt;/p&gt;
</del><ins>+        &lt;p&gt;&lt;?php printf(__('All of this theme&amp;#8217;s files are located in &lt;code&gt;%2$s&lt;/code&gt;.'), $title, str_replace( WP_CONTENT_DIR, '', $template_dir ), str_replace( WP_CONTENT_DIR, '', $stylesheet_dir ) ); ?&gt;&lt;/p&gt;
</ins><span class="cx"> &lt;?php } ?&gt;
</span><span class="cx"> &lt;?php if ( $tags ) : ?&gt;
</span><span class="cx"> &lt;p&gt;&lt;?php _e('Tags:'); ?&gt; &lt;?php echo join(', ', $tags); ?&gt;&lt;/p&gt;
</span></span></pre></div>
<a id="trunkwpincludesthemephp"></a>
<div class="modfile"><h4>Modified: trunk/wp-includes/theme.php (12024 => 12025)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/wp-includes/theme.php        2009-10-13 18:50:16 UTC (rev 12024)
+++ trunk/wp-includes/theme.php        2009-10-13 19:06:35 UTC (rev 12025)
</span><span class="lines">@@ -34,8 +34,10 @@
</span><span class="cx">  */
</span><span class="cx"> function get_stylesheet_directory() {
</span><span class="cx">         $stylesheet = get_stylesheet();
</span><del>-        $stylesheet_dir = get_theme_root() . &quot;/$stylesheet&quot;;
-        return apply_filters('stylesheet_directory', $stylesheet_dir, $stylesheet);
</del><ins>+        $theme_root = get_theme_root( $stylesheet );
+        $stylesheet_dir = &quot;$theme_root/$stylesheet&quot;;
+
+        return apply_filters( 'stylesheet_directory', $stylesheet_dir, $stylesheet, $theme_root );
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> /**
</span><span class="lines">@@ -47,8 +49,10 @@
</span><span class="cx">  */
</span><span class="cx"> function get_stylesheet_directory_uri() {
</span><span class="cx">         $stylesheet = get_stylesheet();
</span><del>-        $stylesheet_dir_uri = get_theme_root_uri() . &quot;/$stylesheet&quot;;
-        return apply_filters('stylesheet_directory_uri', $stylesheet_dir_uri, $stylesheet);
</del><ins>+        $theme_root_uri = get_theme_root_uri( $stylesheet );
+        $stylesheet_dir_uri = &quot;$theme_root_uri/$stylesheet&quot;;
+
+        return apply_filters( 'stylesheet_directory_uri', $stylesheet_dir_uri, $stylesheet, $theme_root_uri );
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> /**
</span><span class="lines">@@ -123,8 +127,10 @@
</span><span class="cx">  */
</span><span class="cx"> function get_template_directory() {
</span><span class="cx">         $template = get_template();
</span><del>-        $template_dir = get_theme_root() . &quot;/$template&quot;;
-        return apply_filters('template_directory', $template_dir, $template);
</del><ins>+        $theme_root = get_theme_root( $template );
+        $template_dir = &quot;$theme_root/$template&quot;;
+                
+        return apply_filters( 'template_directory', $template_dir, $template, $theme_root );
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> /**
</span><span class="lines">@@ -137,8 +143,10 @@
</span><span class="cx">  */
</span><span class="cx"> function get_template_directory_uri() {
</span><span class="cx">         $template = get_template();
</span><del>-        $template_dir_uri = get_theme_root_uri() . &quot;/$template&quot;;
-        return apply_filters('template_directory_uri', $template_dir_uri, $template);
</del><ins>+        $theme_root_uri = get_theme_root_uri( $template );
+        $template_dir_uri = &quot;$theme_root_uri/$template&quot;;
+        
+        return apply_filters( 'template_directory_uri', $template_dir_uri, $template, $theme_root_uri );
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> /**
</span><span class="lines">@@ -253,65 +261,18 @@
</span><span class="cx">         if ( isset($wp_themes) )
</span><span class="cx">                 return $wp_themes;
</span><span class="cx"> 
</span><del>-        $themes = array();
-        $wp_broken_themes = array();
-        $theme_loc = $theme_root = get_theme_root();
-        if ( '/' != WP_CONTENT_DIR ) // don't want to replace all forward slashes, see Trac #4541
-                $theme_loc = str_replace(WP_CONTENT_DIR, '', $theme_root);
</del><ins>+        /* Register wp-content/themes as a theme directory */
+        register_theme_directory( 'themes' );
</ins><span class="cx"> 
</span><del>-        // Files in wp-content/themes directory and one subdir down
-        $themes_dir = @ opendir($theme_root);
-        if ( !$themes_dir )
</del><ins>+        if ( !$theme_files = search_theme_directories() )
</ins><span class="cx">                 return false;
</span><ins>+        
+        asort( $theme_files );
+        
+        foreach ( (array) $theme_files as $theme_file ) {
+                $theme_root = $theme_file['theme_root'];
+                $theme_file = $theme_file['theme_file'];
</ins><span class="cx"> 
</span><del>-        while ( ($theme_dir = readdir($themes_dir)) !== false ) {
-                if ( is_dir($theme_root . '/' . $theme_dir) &amp;&amp; is_readable($theme_root . '/' . $theme_dir) ) {
-                        if ( $theme_dir{0} == '.' || $theme_dir == '..' || $theme_dir == 'CVS' )
-                                continue;
-                        $stylish_dir = @ opendir($theme_root . '/' . $theme_dir);
-                        $found_stylesheet = false;
-                        while ( ($theme_file = readdir($stylish_dir)) !== false ) {
-                                if ( $theme_file == 'style.css' ) {
-                                        $theme_files[] = $theme_dir . '/' . $theme_file;
-                                        $found_stylesheet = true;
-                                        break;
-                                }
-                        }
-                        @closedir($stylish_dir);
-                        if ( !$found_stylesheet ) { // look for themes in that dir
-                                $subdir = &quot;$theme_root/$theme_dir&quot;;
-                                $subdir_name = $theme_dir;
-                                $theme_subdir = @ opendir( $subdir );
-                                while ( ($theme_dir = readdir($theme_subdir)) !== false ) {
-                                        if ( is_dir( $subdir . '/' . $theme_dir) &amp;&amp; is_readable($subdir . '/' . $theme_dir) ) {
-                                                if ( $theme_dir{0} == '.' || $theme_dir == '..' || $theme_dir == 'CVS' )
-                                                        continue;
-                                                $stylish_dir = @ opendir($subdir . '/' . $theme_dir);
-                                                $found_stylesheet = false;
-                                                while ( ($theme_file = readdir($stylish_dir)) !== false ) {
-                                                        if ( $theme_file == 'style.css' ) {
-                                                                $theme_files[] = $subdir_name . '/' . $theme_dir . '/' . $theme_file;
-                                                                $found_stylesheet = true;
-                                                                break;
-                                                        }
-                                                }
-                                                @closedir($stylish_dir);
-                                        }
-                                }
-                                @closedir($theme_subdir);
-                                $wp_broken_themes[$theme_dir] = array('Name' =&gt; $theme_dir, 'Title' =&gt; $theme_dir, 'Description' =&gt; __('Stylesheet is missing.'));
-                        }
-                }
-        }
-        if ( is_dir( $theme_dir ) )
-                @closedir( $theme_dir );
-
-        if ( !$themes_dir || !$theme_files )
-                return $themes;
-
-        sort($theme_files);
-
-        foreach ( (array) $theme_files as $theme_file ) {
</del><span class="cx">                 if ( !is_readable(&quot;$theme_root/$theme_file&quot;) ) {
</span><span class="cx">                         $wp_broken_themes[$theme_file] = array('Name' =&gt; $theme_file, 'Title' =&gt; $theme_file, 'Description' =&gt; __('File not readable.'));
</span><span class="cx">                         continue;
</span><span class="lines">@@ -346,19 +307,31 @@
</span><span class="cx">                         else
</span><span class="cx">                                 continue;
</span><span class="cx">                 }
</span><ins>+                
+                $template = trim( $template );
</ins><span class="cx"> 
</span><del>-                $template = trim($template);
-
</del><span class="cx">                 if ( !file_exists(&quot;$theme_root/$template/index.php&quot;) ) {
</span><span class="cx">                         $parent_dir = dirname(dirname($theme_file));
</span><span class="cx">                         if ( file_exists(&quot;$theme_root/$parent_dir/$template/index.php&quot;) ) {
</span><del>-                                $template = &quot;$parent_dir/$template&quot;;
</del><ins>+                                $template = &quot;$theme_root/$parent_dir/$template&quot;;
</ins><span class="cx">                         } else {
</span><del>-                                $wp_broken_themes[$name] = array('Name' =&gt; $name, 'Title' =&gt; $title, 'Description' =&gt; __('Template is missing.'));
-                                continue;
</del><ins>+                                /**  
+                                 * The parent theme doesn't exist in the current theme's folder or sub folder 
+                                 * so lets use the theme root for the parent template. 
+                                 */
+                                $parent_theme_root = $theme_files[$template]['theme_root'];
+                                if ( file_exists( &quot;$parent_theme_root/$template/index.php&quot; ) ) {
+                                        $template = &quot;$parent_theme_root/$template&quot;;
+                                } else {
+                                        $wp_broken_themes[$name] = array('Name' =&gt; $name, 'Title' =&gt; $title, 'Description' =&gt; __('Template is missing.'));
+                                        continue;
+                                }
+                                
</ins><span class="cx">                         }
</span><ins>+                } else {
+                        $template = trim( $theme_root . '/' . $template );
</ins><span class="cx">                 }
</span><del>-
</del><ins>+                
</ins><span class="cx">                 $stylesheet_files = array();
</span><span class="cx">                 $template_files = array();
</span><span class="cx"> 
</span><span class="lines">@@ -367,28 +340,28 @@
</span><span class="cx">                         while ( ($file = $stylesheet_dir-&gt;read()) !== false ) {
</span><span class="cx">                                 if ( !preg_match('|^\.+$|', $file) ) {
</span><span class="cx">                                         if ( preg_match('|\.css$|', $file) )
</span><del>-                                                $stylesheet_files[] = &quot;$theme_loc/$stylesheet/$file&quot;;
</del><ins>+                                                $stylesheet_files[] = &quot;$theme_root/$stylesheet/$file&quot;;
</ins><span class="cx">                                         elseif ( preg_match('|\.php$|', $file) )
</span><del>-                                                $template_files[] = &quot;$theme_loc/$stylesheet/$file&quot;;
</del><ins>+                                                $template_files[] = &quot;$theme_root/$stylesheet/$file&quot;;
</ins><span class="cx">                                 }
</span><span class="cx">                         }
</span><span class="cx">                         @ $stylesheet_dir-&gt;close();
</span><span class="cx">                 }
</span><span class="cx"> 
</span><del>-                $template_dir = @ dir(&quot;$theme_root/$template&quot;);
</del><ins>+                $template_dir = @ dir(&quot;$template&quot;);
</ins><span class="cx">                 if ( $template_dir ) {
</span><span class="cx">                         while ( ($file = $template_dir-&gt;read()) !== false ) {
</span><span class="cx">                                 if ( preg_match('|^\.+$|', $file) )
</span><span class="cx">                                         continue;
</span><span class="cx">                                 if ( preg_match('|\.php$|', $file) ) {
</span><del>-                                        $template_files[] = &quot;$theme_loc/$template/$file&quot;;
-                                } elseif ( is_dir(&quot;$theme_root/$template/$file&quot;) ) {
-                                        $template_subdir = @ dir(&quot;$theme_root/$template/$file&quot;);
</del><ins>+                                        $template_files[] = &quot;$template/$file&quot;;
+                                } elseif ( is_dir(&quot;$template/$file&quot;) ) {
+                                        $template_subdir = @ dir(&quot;$template/$file&quot;);
</ins><span class="cx">                                         while ( ($subfile = $template_subdir-&gt;read()) !== false ) {
</span><span class="cx">                                                 if ( preg_match('|^\.+$|', $subfile) )
</span><span class="cx">                                                         continue;
</span><span class="cx">                                                 if ( preg_match('|\.php$|', $subfile) )
</span><del>-                                                        $template_files[] = &quot;$theme_loc/$template/$file/$subfile&quot;;
</del><ins>+                                                        $template_files[] = &quot;$template/$file/$subfile&quot;;
</ins><span class="cx">                                         }
</span><span class="cx">                                         @ $template_subdir-&gt;close();
</span><span class="cx">                                 }
</span><span class="lines">@@ -422,12 +395,17 @@
</span><span class="cx">                         }
</span><span class="cx">                 }
</span><span class="cx"> 
</span><del>-                $themes[$name] = array('Name' =&gt; $name, 'Title' =&gt; $title, 'Description' =&gt; $description, 'Author' =&gt; $author, 'Version' =&gt; $version, 'Template' =&gt; $template, 'Stylesheet' =&gt; $stylesheet, 'Template Files' =&gt; $template_files, 'Stylesheet Files' =&gt; $stylesheet_files, 'Template Dir' =&gt; $template_dir, 'Stylesheet Dir' =&gt; $stylesheet_dir, 'Status' =&gt; $theme_data['Status'], 'Screenshot' =&gt; $screenshot, 'Tags' =&gt; $theme_data['Tags']);
</del><ins>+                $theme_roots[$stylesheet] = str_replace( WP_CONTENT_DIR, '', $theme_root );
+                $themes[$name] = array( 'Name' =&gt; $name, 'Title' =&gt; $title, 'Description' =&gt; $description, 'Author' =&gt; $author, 'Version' =&gt; $version, 'Template' =&gt; basename( $template ), 'Stylesheet' =&gt; $stylesheet, 'Template Files' =&gt; $template_files, 'Stylesheet Files' =&gt; $stylesheet_files, 'Template Dir' =&gt; $template_dir, 'Stylesheet Dir' =&gt; $stylesheet_dir, 'Status' =&gt; $theme_data['Status'], 'Screenshot' =&gt; $screenshot, 'Tags' =&gt; $theme_data['Tags'], 'Theme Root' =&gt; $theme_root, 'Theme Root URI' =&gt; str_replace( WP_CONTENT_DIR, content_url(), $theme_root ) );
</ins><span class="cx">         }
</span><span class="cx"> 
</span><del>-        // Resolve theme dependencies.
-        $theme_names = array_keys($themes);
</del><ins>+        /* Resolve theme dependencies. */
+        $theme_names = array_keys( $themes );
</ins><span class="cx"> 
</span><ins>+        /* Store theme roots in the DB */
+        if ( get_transient( 'theme_roots' ) != $theme_roots )
+                set_transient( 'theme_roots', $theme_roots, 7200 ); // cache for two hours
+
</ins><span class="cx">         foreach ( (array) $theme_names as $theme_name ) {
</span><span class="cx">                 $themes[$theme_name]['Parent Theme'] = '';
</span><span class="cx">                 if ( $themes[$theme_name]['Stylesheet'] != $themes[$theme_name]['Template'] ) {
</span><span class="lines">@@ -441,11 +419,27 @@
</span><span class="cx">         }
</span><span class="cx"> 
</span><span class="cx">         $wp_themes = $themes;
</span><del>-
</del><ins>+        
</ins><span class="cx">         return $themes;
</span><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> /**
</span><ins>+ * Retrieve theme roots.
+ *
+ * @since 2.9.0
+ *
+ * @return array Theme roots
+ */
+function get_theme_roots() {
+        $theme_roots = get_transient( 'theme_roots' );
+        if ( false === $theme_roots ) {
+                get_themes();
+                $theme_roots = get_transient( 'theme_roots' ); // this is set in get_theme()
+        }
+        return $theme_roots;
+}
+
+/**
</ins><span class="cx">  * Retrieve theme data.
</span><span class="cx">  *
</span><span class="cx">  * @since 1.5.0
</span><span class="lines">@@ -499,17 +493,130 @@
</span><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> /**
</span><ins>+ * Register a directory that contains themes relative to the content directory.
+ *
+ * @since 2.9.0
+ *
+ * @return bool
+ */
+function register_theme_directory( $directory ) {
+        global $wp_theme_directories;
+        
+        /* The theme directory should be relative to the content directory */
+        $registered_directory = WP_CONTENT_DIR . '/' . $directory;
+        
+        /* If this folder does not exist, return and do not register */
+        if ( !file_exists( $registered_directory ) )
+                return false;
+        
+        $wp_theme_directories[] = $registered_directory;
+        
+        return true;
+}
+
+/**
+ * Search all registered theme directories for complete and valid themes.
+ *
+ * @since 2.9.0
+ *
+ * @return array Valid themes found
+ */
+function search_theme_directories() {
+        global $wp_theme_directories, $wp_broken_themes;
+        
+        if ( empty( $wp_theme_directories ) )
+                return false;
+
+        $theme_files = array();
+        $wp_broken_themes = array();
+
+        /* Loop the registered theme directories and extract all themes */
+        foreach ( (array) $wp_theme_directories as $theme_root ) {
+                $theme_loc = $theme_root;
+                
+                /* We don't want to replace all forward slashes, see Trac #4541 */
+                if ( '/' != WP_CONTENT_DIR ) 
+                        $theme_loc = str_replace(WP_CONTENT_DIR, '', $theme_root);
+
+                /* Files in the root of the current theme directory and one subdir down */
+                $themes_dir = @ opendir($theme_root);
+
+                if ( !$themes_dir )
+                        return false;
+
+                while ( ($theme_dir = readdir($themes_dir)) !== false ) {
+                        if ( is_dir($theme_root . '/' . $theme_dir) &amp;&amp; is_readable($theme_root . '/' . $theme_dir) ) {
+                                if ( $theme_dir{0} == '.' || $theme_dir == '..' || $theme_dir == 'CVS' )
+                                        continue;
+
+                                $stylish_dir = @ opendir($theme_root . '/' . $theme_dir);
+                                $found_stylesheet = false;
+                                
+                                while ( ($theme_file = readdir($stylish_dir)) !== false ) {
+                                        if ( $theme_file == 'style.css' ) {
+                                                $theme_files[$theme_dir] = array( 'theme_file' =&gt; $theme_dir . '/' . $theme_file, 'theme_root' =&gt; $theme_root );
+                                                $found_stylesheet = true;
+                                                break;
+                                        }
+                                }
+                                @closedir($stylish_dir);
+                                
+                                if ( !$found_stylesheet ) { // look for themes in that dir
+                                        $subdir = &quot;$theme_root/$theme_dir&quot;;
+                                        $subdir_name = $theme_dir;
+                                        $theme_subdir = @ opendir( $subdir );
+                                        
+                                        while ( ($theme_dir = readdir($theme_subdir)) !== false ) {
+                                                if ( is_dir( $subdir . '/' . $theme_dir) &amp;&amp; is_readable($subdir . '/' . $theme_dir) ) {
+                                                        if ( $theme_dir{0} == '.' || $theme_dir == '..' || $theme_dir == 'CVS' )
+                                                                continue;
+                                                                
+                                                        $stylish_dir = @ opendir($subdir . '/' . $theme_dir);
+                                                        $found_stylesheet = false;
+                                                        
+                                                        while ( ($theme_file = readdir($stylish_dir)) !== false ) {
+                                                                if ( $theme_file == 'style.css' ) {
+                                                                        $theme_files[$theme_dir] = array( 'theme_file' =&gt; $subdir_name . '/' . $theme_dir . '/' . $theme_file, 'theme_root' =&gt; $theme_root );
+                                                                        $found_stylesheet = true;
+                                                                        break;
+                                                                }
+                                                        }
+                                                        @closedir($stylish_dir);
+                                                }
+                                        }
+                                        @closedir($theme_subdir);
+                                        
+                                        $wp_broken_themes[$theme_dir] = array('Name' =&gt; $theme_dir, 'Title' =&gt; $theme_dir, 'Description' =&gt; __('Stylesheet is missing.'));
+                                }
+                        }
+                }
+                if ( is_dir( $theme_dir ) )
+                        @closedir( $theme_dir );
+        }
+        
+        return $theme_files;
+}
+
+/**
</ins><span class="cx">  * Retrieve path to themes directory.
</span><span class="cx">  *
</span><span class="cx">  * Does not have trailing slash.
</span><span class="cx">  *
</span><span class="cx">  * @since 1.5.0
</span><ins>+ * @param $stylesheet_or_template The stylesheet or template name of the theme
</ins><span class="cx">  * @uses apply_filters() Calls 'theme_root' filter on path.
</span><span class="cx">  *
</span><span class="cx">  * @return string Theme path.
</span><span class="cx">  */
</span><del>-function get_theme_root() {
-        return apply_filters('theme_root', WP_CONTENT_DIR . &quot;/themes&quot;);
</del><ins>+function get_theme_root( $stylesheet_or_template = false ) {
+        $theme_roots = get_theme_roots();
+        
+        if ( $theme_roots[$stylesheet_or_template] )
+                $theme_root = WP_CONTENT_DIR . '/' . $theme_roots[$stylesheet_or_template];
+        else
+                $theme_root = WP_CONTENT_DIR . '/themes';
+
+        return apply_filters( 'theme_root', $theme_root );
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> /**
</span><span class="lines">@@ -518,11 +625,19 @@
</span><span class="cx">  * Does not have trailing slash.
</span><span class="cx">  *
</span><span class="cx">  * @since 1.5.0
</span><ins>+ * @param $stylesheet_or_template The stylesheet or template name of the theme
</ins><span class="cx">  *
</span><span class="cx">  * @return string Themes URI.
</span><span class="cx">  */
</span><del>-function get_theme_root_uri() {
-        return apply_filters('theme_root_uri', content_url('themes'), get_option('siteurl'));
</del><ins>+function get_theme_root_uri( $stylesheet_or_template = false ) {
+        $theme_roots = get_theme_roots();
+        
+        if ( $theme_roots[$stylesheet_or_template] )
+                $theme_root_uri = content_url( $theme_roots[$stylesheet_or_template] );
+        else
+                $theme_root_uri = content_url( 'themes' );
+
+        return apply_filters( 'theme_root_uri', $theme_root_uri, get_option('siteurl'), $stylesheet_or_template );
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> /**
</span></span></pre>
</div>
</div>

</body>
</html>