Make WordPress Core

Changeset 41806


Ignore:
Timestamp:
10/10/2017 05:33:57 AM (9 years ago)
Author:
pento
Message:

File Editor: Add support for more than one sub-directory level.

The theme and plugin editors now list all files in the selected theme or plugin, recursing through subdirectories as necessary.

Props WraithKenny, schlessera, chsxf, MikeHansenMe, Daedalon, valendesigns, westonruter, pento.
Fixes #6531.

Location:
trunk
Files:
1 added
5 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/wp-admin/includes/file.php

    r41805 r41806  
    121121 *
    122122 * @since 2.6.0
     123 * @since 4.9.0 Added the `$exclusions` parameter.
    123124 *
    124125 * @param string $folder Optional. Full path to folder. Default empty.
    125126 * @param int    $levels Optional. Levels of folders to follow, Default 100 (PHP Loop limit).
     127 * @param array  $exclusions Optional. List of folders and files to skip.
    126128 * @return bool|array False on failure, Else array of files
    127129 */
    128 function list_files( $folder = '', $levels = 100 ) {
    129         if ( empty($folder) )
     130function list_files( $folder = '', $levels = 100, $exclusions = array() ) {
     131        if ( empty( $folder ) ) {
    130132                return false;
    131 
    132         if ( ! $levels )
     133        }
     134
     135        $folder = trailingslashit( $folder );
     136
     137        if ( ! $levels ) {
    133138                return false;
     139        }
    134140
    135141        $files = array();
    136         if ( $dir = @opendir( $folder ) ) {
    137                 while (($file = readdir( $dir ) ) !== false ) {
    138                         if ( in_array($file, array('.', '..') ) )
     142
     143        $dir = @opendir( $folder );
     144        if ( $dir ) {
     145                while ( ( $file = readdir( $dir ) ) !== false ) {
     146                        // Skip current and parent folder links.
     147                        if ( in_array( $file, array( '.', '..' ), true ) ) {
    139148                                continue;
    140                         if ( is_dir( $folder . '/' . $file ) ) {
    141                                 $files2 = list_files( $folder . '/' . $file, $levels - 1);
    142                                 if ( $files2 )
     149                        }
     150
     151                        // Skip hidden and excluded files.
     152                        if ( '.' === $file[0] || in_array( $file, $exclusions, true ) ) {
     153                                continue;
     154                        }
     155
     156                        if ( is_dir( $folder . $file ) ) {
     157                                $files2 = list_files( $folder . $file, $levels - 1 );
     158                                if ( $files2 ) {
    143159                                        $files = array_merge($files, $files2 );
    144                                 else
    145                                         $files[] = $folder . '/' . $file . '/';
     160                                } else {
     161                                        $files[] = $folder . $file . '/';
     162                                }
    146163                        } else {
    147                                 $files[] = $folder . '/' . $file;
     164                                $files[] = $folder . $file;
    148165                        }
    149166                }
    150167        }
    151168        @closedir( $dir );
     169
    152170        return $files;
    153171}
  • trunk/src/wp-admin/includes/plugin.php

    r41713 r41806  
    191191 * @return array List of files relative to the plugin root.
    192192 */
    193 function get_plugin_files($plugin) {
     193function get_plugin_files( $plugin ) {
    194194        $plugin_file = WP_PLUGIN_DIR . '/' . $plugin;
    195         $dir = dirname($plugin_file);
    196         $plugin_files = array($plugin);
    197         if ( is_dir($dir) && $dir != WP_PLUGIN_DIR ) {
    198                 $plugins_dir = @ opendir( $dir );
    199                 if ( $plugins_dir ) {
    200                         while (($file = readdir( $plugins_dir ) ) !== false ) {
    201                                 if ( substr($file, 0, 1) == '.' )
    202                                         continue;
    203                                 if ( is_dir( $dir . '/' . $file ) ) {
    204                                         $plugins_subdir = @ opendir( $dir . '/' . $file );
    205                                         if ( $plugins_subdir ) {
    206                                                 while (($subfile = readdir( $plugins_subdir ) ) !== false ) {
    207                                                         if ( substr($subfile, 0, 1) == '.' )
    208                                                                 continue;
    209                                                         $plugin_files[] = plugin_basename("$dir/$file/$subfile");
    210                                                 }
    211                                                 @closedir( $plugins_subdir );
    212                                         }
    213                                 } else {
    214                                         if ( plugin_basename("$dir/$file") != $plugin )
    215                                                 $plugin_files[] = plugin_basename("$dir/$file");
    216                                 }
    217                         }
    218                         @closedir( $plugins_dir );
    219                 }
    220         }
     195        $dir = dirname( $plugin_file );
     196
     197        $data = get_plugin_data( $plugin_file );
     198        $label = isset( $data['Version'] )
     199                ? sanitize_key( 'files_' . $plugin . '-' . $data['Version'] )
     200                : sanitize_key( 'files_' . $plugin );
     201        $transient_key = substr( $label, 0, 29 ) . md5( $label );
     202
     203        $plugin_files = get_transient( $transient_key );
     204        if ( false !== $plugin_files ) {
     205                return $plugin_files;
     206        }
     207
     208        $plugin_files = array( plugin_basename( $plugin_file ) );
     209
     210        if ( is_dir( $dir ) && WP_PLUGIN_DIR !== $dir ) {
     211
     212                /**
     213                 * Filters the array of excluded directories and files while scanning the folder.
     214                 *
     215                 * @since 4.9.0
     216                 *
     217                 * @param array $exclusions Array of excluded directories and files.
     218                 */
     219                $exclusions = (array) apply_filters( 'plugin_files_exclusions', array( 'CVS', 'node_modules', 'vendor', 'bower_components' ) );
     220
     221                $list_files = list_files( $dir, 100, $exclusions );
     222                $list_files = array_map( 'plugin_basename', $list_files );
     223
     224                $plugin_files = array_merge( $plugin_files, $list_files );
     225                $plugin_files = array_values( array_unique( $plugin_files ) );
     226        }
     227
     228        set_transient( $transient_key, $plugin_files, HOUR_IN_SECONDS );
    221229
    222230        return $plugin_files;
  • trunk/src/wp-admin/theme-editor.php

    r41774 r41806  
    7676        switch ( $type ) {
    7777                case 'php':
    78                         $allowed_files += $theme->get_files( 'php', 1 );
     78                        $allowed_files += $theme->get_files( 'php', -1 );
    7979                        $has_templates = ! empty( $allowed_files );
    8080                        break;
    8181                case 'css':
    82                         $style_files = $theme->get_files( 'css' );
     82                        $style_files = $theme->get_files( 'css', -1 );
    8383                        $allowed_files['style.css'] = $style_files['style.css'];
    8484                        $allowed_files += $style_files;
    8585                        break;
    8686                default:
    87                         $allowed_files += $theme->get_files( $type );
     87                        $allowed_files += $theme->get_files( $type, -1 );
    8888                        break;
    8989        }
  • trunk/src/wp-includes/class-wp-theme.php

    r41688 r41806  
    982982         * @param bool $search_parent Optional. Whether to return parent files. Defaults to false.
    983983         * @return array Array of files, keyed by the path to the file relative to the theme's directory, with the values
    984          *                   being absolute paths.
     984         *               being absolute paths.
    985985         */
    986986        public function get_files( $type = null, $depth = 0, $search_parent = false ) {
    987                 $files = (array) self::scandir( $this->get_stylesheet_directory(), $type, $depth );
    988 
    989                 if ( $search_parent && $this->parent() )
    990                         $files += (array) self::scandir( $this->get_template_directory(), $type, $depth );
     987                // get and cache all theme files to start with.
     988                $label = sanitize_key( 'files_' . $this->cache_hash . '-' . $this->get( 'Version' ) );
     989                $transient_key = substr( $label, 0, 29 ) . md5( $label );
     990
     991                $all_files = get_transient( $transient_key );
     992                if ( false === $all_files ) {
     993                        $all_files = (array) self::scandir( $this->get_stylesheet_directory(), null, -1 );
     994
     995                        if ( $search_parent && $this->parent() ) {
     996                                $all_files += (array) self::scandir( $this->get_template_directory(), null, -1 );
     997                        }
     998
     999                        set_transient( $transient_key, $all_files, HOUR_IN_SECONDS );
     1000                }
     1001
     1002                // Filter $all_files by $type & $depth.
     1003                $files = array();
     1004                if ( $type ) {
     1005                        $type = (array) $type;
     1006                        $_extensions = implode( '|', $type );
     1007                }
     1008                foreach ( $all_files as $key => $file ) {
     1009                        if ( $depth >= 0 && substr_count( $key, '/' ) > $depth ) {
     1010                                continue; // Filter by depth.
     1011                        }
     1012                        if ( ! $type || preg_match( '~\.(' . $_extensions . ')$~', $file ) ) { // Filter by type.
     1013                                $files[ $key ] = $file;
     1014                        }
     1015                }
    9911016
    9921017                return $files;
     
    11081133         */
    11091134        private static function scandir( $path, $extensions = null, $depth = 0, $relative_path = '' ) {
    1110                 if ( ! is_dir( $path ) )
     1135                if ( ! is_dir( $path ) ) {
    11111136                        return false;
     1137                }
    11121138
    11131139                if ( $extensions ) {
     
    11171143
    11181144                $relative_path = trailingslashit( $relative_path );
    1119                 if ( '/' == $relative_path )
     1145                if ( '/' == $relative_path ) {
    11201146                        $relative_path = '';
     1147                }
    11211148
    11221149                $results = scandir( $path );
     
    11261153                 * Filters the array of excluded directories and files while scanning theme folder.
    11271154                 *
    1128                  * @since 4.7.4
     1155                 * @since 4.7.4
    11291156                 *
    11301157                 * @param array $exclusions Array of excluded directories and files.
    11311158                 */
    1132                 $exclusions = (array) apply_filters( 'theme_scandir_exclusions', array( 'CVS', 'node_modules' ) );
     1159                $exclusions = (array) apply_filters( 'theme_scandir_exclusions', array( 'CVS', 'node_modules', 'vendor', 'bower_components' ) );
    11331160
    11341161                foreach ( $results as $result ) {
     
    11371164                        }
    11381165                        if ( is_dir( $path . '/' . $result ) ) {
    1139                                 if ( ! $depth )
     1166                                if ( ! $depth ) {
    11401167                                        continue;
     1168                                }
    11411169                                $found = self::scandir( $path . '/' . $result, $extensions, $depth - 1 , $relative_path . $result );
    11421170                                $files = array_merge_recursive( $files, $found );
  • trunk/tests/phpunit/tests/admin/includesPlugin.php

    r35242 r41806  
    9595
    9696        /**
     97         * @covers ::get_plugin_files
     98         */
     99        public function test_get_plugin_files_folder() {
     100                $plugin_dir = WP_PLUGIN_DIR . '/list_files_test_plugin';
     101                @mkdir( $plugin_dir );
     102                $plugin = $this->_create_plugin(null, 'list_files_test_plugin.php', $plugin_dir );
     103
     104                $sub_dir = trailingslashit( dirname( $plugin[1] ) ) . 'subdir';
     105                @mkdir( $sub_dir );
     106                @file_put_contents( $sub_dir . '/subfile.php', '<?php // Silence.' );
     107
     108                $plugin_files = get_plugin_files( plugin_basename( $plugin[1] ) );
     109                $expected = array(
     110                        'list_files_test_plugin/list_files_test_plugin.php',
     111                        'list_files_test_plugin/subdir/subfile.php',
     112                );
     113                $this->assertEquals( $expected, $plugin_files );
     114
     115                unlink( $sub_dir . '/subfile.php' );
     116                unlink( $plugin[1] );
     117                rmdir( $sub_dir );
     118                rmdir( $plugin_dir );
     119        }
     120
     121        /**
    97122         * @covers ::get_mu_plugins
    98123         */
Note: See TracChangeset for help on using the changeset viewer.