Make WordPress Core

Changeset 20020


Ignore:
Timestamp:
02/28/2012 08:05:00 PM (13 years ago)
Author:
nacin
Message:

Rewrite search_theme_directories() -- better performance and allow for caching.

  • Update it to use PHP5 scandir().
  • Don't scan individual theme dirs -- we only need to check for style.css. (Solid performance gains.)
  • Improve and simplify branching.
  • Introduce wp_cache_themes_persistently filter to enable persistent caching of the return value, based on the theme_roots transient.

see #20103.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/wp-includes/theme.php

    r20018 r20020  
    572572 */
    573573function search_theme_directories() {
    574     global $wp_theme_directories, $wp_broken_themes;
     574    global $wp_theme_directories;
    575575    if ( empty( $wp_theme_directories ) )
    576576        return false;
    577577
    578     $theme_files = array();
    579     $wp_broken_themes = array();
     578    static $found_themes;
     579    if ( isset( $found_themes ) )
     580        return $found_themes;
     581
     582    $found_themes = array();
     583
     584    if ( $cache_expiration = apply_filters( 'wp_cache_themes_persistently', false, 'search_theme_directories' ) ) {
     585        $cached_roots = get_site_transient( 'theme_roots' );
     586        if ( is_array( $cached_roots ) ) {
     587            foreach ( $cached_roots as $theme_dir => $theme_root ) {
     588                $found_themes[ $theme_dir ] = array(
     589                    'theme_file' => $theme_dir . '/style.css',
     590                    'theme_root' => $theme_root,
     591                );
     592            }
     593            return $found_themes;
     594        }
     595        if ( ! is_int( $cache_expiration ) )
     596            $cache_expiration = 7200;
     597    } else {
     598        // Two hours is the default.
     599        $cache_expiration = 7200;
     600    }
    580601
    581602    /* Loop the registered theme directories and extract all themes */
    582     foreach ( (array) $wp_theme_directories as $theme_root ) {
    583         $theme_loc = $theme_root;
    584 
    585         /* We don't want to replace all forward slashes, see Trac #4541 */
    586         if ( '/' != WP_CONTENT_DIR )
    587             $theme_loc = str_replace(WP_CONTENT_DIR, '', $theme_root);
    588 
    589         /* Files in the root of the current theme directory and one subdir down */
    590         $themes_dir = @ opendir($theme_root);
    591 
    592         if ( !$themes_dir )
     603    foreach ( $wp_theme_directories as $theme_root ) {
     604
     605        // Start with directories in the root of the current theme directory.
     606        $dirs = @ scandir( $theme_root );
     607        if ( ! $dirs )
    593608            return false;
    594 
    595         while ( ($theme_dir = readdir($themes_dir)) !== false ) {
    596             if ( is_dir($theme_root . '/' . $theme_dir) && is_readable($theme_root . '/' . $theme_dir) ) {
    597                 if ( $theme_dir[0] == '.' || $theme_dir == 'CVS' )
    598                     continue;
    599 
    600                 $stylish_dir = @opendir($theme_root . '/' . $theme_dir);
    601                 $found_stylesheet = false;
    602 
    603                 while ( ($theme_file = readdir($stylish_dir)) !== false ) {
    604                     if ( $theme_file == 'style.css' ) {
    605                         $theme_files[$theme_dir] = array( 'theme_file' => $theme_dir . '/' . $theme_file, 'theme_root' => $theme_root );
    606                         $found_stylesheet = true;
    607                         break;
    608                     }
     609        foreach ( $dirs as $dir ) {
     610            if ( ! is_dir( $theme_root . '/' . $dir ) || $dir[0] == '.' || $dir == 'CVS' )
     611                continue;
     612            if ( file_exists( $theme_root . '/' . $dir . '/style.css' ) ) {
     613                // wp-content/themes/a-single-theme
     614                // wp-content/themes is $theme_root, a-single-theme is $dir
     615                $found_themes[ $dir ] = array(
     616                    'theme_file' => $dir . '/style.css',
     617                    'theme_root' => $theme_root,
     618                );
     619            } else {
     620                $found_theme = false;
     621                // wp-content/themes/a-folder-of-themes/*
     622                // wp-content/themes is $theme_root, a-folder-of-themes is $dir, then themes are $sub_dirs
     623                $sub_dirs = @ scandir( $theme_root . '/' . $dir );
     624                if ( ! $sub_dirs )
     625                    return false;
     626                foreach ( $sub_dirs as $sub_dir ) {
     627                    if ( ! is_dir( $theme_root . '/' . $dir ) || $dir[0] == '.' || $dir == 'CVS' )
     628                        continue;
     629                    if ( ! file_exists( $theme_root . '/' . $dir . '/' . $sub_dir . '/style.css' ) )
     630                        continue;
     631                    $found_themes[ $dir . '/' . $sub_dir ] = array(
     632                        'theme_file' => $dir . '/' . $sub_dir . '/style.css',
     633                        'theme_root' => $theme_root,
     634                    );
     635                    $found_theme = true;
    609636                }
    610                 @closedir($stylish_dir);
    611 
    612                 if ( !$found_stylesheet ) { // look for themes in that dir
    613                     $subdir = "$theme_root/$theme_dir";
    614                     $subdir_name = $theme_dir;
    615                     $theme_subdirs = @opendir( $subdir );
    616 
    617                     $found_subdir_themes = false;
    618                     while ( ($theme_subdir = readdir($theme_subdirs)) !== false ) {
    619                         if ( is_dir( $subdir . '/' . $theme_subdir) && is_readable($subdir . '/' . $theme_subdir) ) {
    620                             if ( $theme_subdir[0] == '.' || $theme_subdir == 'CVS' )
    621                                 continue;
    622 
    623                             $stylish_dir = @opendir($subdir . '/' . $theme_subdir);
    624                             $found_stylesheet = false;
    625 
    626                             while ( ($theme_file = readdir($stylish_dir)) !== false ) {
    627                                 if ( $theme_file == 'style.css' ) {
    628                                     $theme_files["$theme_dir/$theme_subdir"] = array( 'theme_file' => $subdir_name . '/' . $theme_subdir . '/' . $theme_file, 'theme_root' => $theme_root );
    629                                     $found_stylesheet = true;
    630                                     $found_subdir_themes = true;
    631                                     break;
    632                                 }
    633                             }
    634                             @closedir($stylish_dir);
    635                         }
    636                     }
    637                     @closedir($theme_subdirs);
    638                     if ( !$found_subdir_themes )
    639                         $wp_broken_themes[$theme_dir] = array('Name' => $theme_dir, 'Title' => $theme_dir, 'Description' => __('Stylesheet is missing.'));
    640                 }
     637                // Never mind the above, it's just a theme missing a style.css.
     638                // Return it; WP_Theme will catch the error.
     639                if ( ! $found_theme )
     640                    $found_themes[ $dir ] = array(
     641                        'theme_file' => $dir . '/style.css',
     642                        'theme_root' => $theme_root,
     643                    );
    641644            }
    642645        }
    643         @closedir( $themes_dir );
    644     }
    645     return $theme_files;
     646    }
     647
     648    asort( $found_themes );
     649
     650    $theme_roots = array();
     651    foreach ( $found_themes as $theme_dir => $theme_data ) {
     652        $theme_roots[ $theme_dir ] = $theme_data['theme_root'];
     653    }
     654
     655    if ( $theme_roots != get_site_transient( 'theme_roots' ) )
     656        set_site_transient( 'theme_roots', $theme_roots, $cache_expiration );
     657
     658    return $found_themes;
    646659}
    647660
Note: See TracChangeset for help on using the changeset viewer.