Ticket #24048: 24048.2.diff
File 24048.2.diff, 45.4 KB (added by , 7 years ago) |
---|
-
src/wp-admin/css/common.css
1466 1466 .wrap #templateside .notice { 1467 1467 display: block; 1468 1468 margin: 0; 1469 padding: 5px 12px;1470 1469 font-weight: 600; 1470 padding: 5px 8px; 1471 1471 text-decoration: none; 1472 1472 } 1473 1473 … … 1476 1476 } 1477 1477 1478 1478 #templateside li.notice a { 1479 1479 padding: 0; 1480 1480 } 1481 1481 1482 1482 /* Update icon. */ … … 3038 3038 } 3039 3039 #templateside { 3040 3040 margin-top: 31px; 3041 overflow: scroll; 3041 overflow: auto; 3042 padding: 2px; 3042 3043 } 3043 3044 3045 #templateside ul ul { 3046 padding-left: .9em; 3047 } 3048 3049 [role="treeitem"][aria-expanded="false"] > ul { 3050 display: none; 3051 } 3052 3053 [role="treeitem"][aria-expanded="false"] > span:after { 3054 content: ' ▶'; 3055 } 3056 3057 [role="treeitem"][aria-expanded="true"] > span:after { 3058 content: ' ▼'; 3059 } 3060 [role="treeitem"] { 3061 outline: 0; 3062 } 3063 [role="treeitem"] span { 3064 display: block; 3065 padding: 3px 3px 3px .9em; 3066 } 3067 [role="treeitem"] span.focus { 3068 color: #124964; 3069 box-shadow: 0 0 0 1px #5b9dd9, 0 0 2px 1px rgba(30, 140, 190, .8); 3070 } 3071 [role="treeitem"].hover, 3072 [role="treeitem"] span.hover { 3073 background-color: #DDDDDD; 3074 } 3075 #templateside ul[role="group"] { 3076 margin: 0; 3077 } 3078 #templateside [role="group"] [role="group"]::after { 3079 content: ' '; 3080 display: block; 3081 position: absolute; 3082 left: 2px; 3083 border-left: 1px solid #ccc; 3084 top: -13px; 3085 bottom: 10px; 3086 } 3087 #templateside [role="group"] li:last-child > [role="group"]::after { 3088 display: none; 3089 } 3090 [role="group"] > li { 3091 position: relative; 3092 } 3093 [role="group"] > li::before { 3094 content: ' '; 3095 position: absolute; 3096 display: block; 3097 border-left: 1px solid #ccc; 3098 left: 2px; 3099 top: 0; 3100 height: 13px; 3101 width: 7px; 3102 border-bottom: 1px solid #ccc; 3103 } 3104 #templateside li.current-file a { 3105 padding: 0 3px 0 12px; 3106 } 3107 [role="group"] > .current-file::before { 3108 left: 4px; 3109 height: 15px; 3110 width: 6px; 3111 border-left: none; 3112 } 3113 [role="group"] > .current-file::after { 3114 bottom: -4px; 3115 height: 4px; 3116 left: 2px; 3117 } 3118 [role="group"] > li::after { 3119 content: ' '; 3120 position: absolute; 3121 display: block; 3122 border-left: 1px solid #ccc; 3123 left: 2px; 3124 bottom: -4px; 3125 top: 0; 3126 } 3127 [role="group"] > li:last-child::after { 3128 display: none; 3129 } 3044 3130 #theme-plugin-editor-label { 3045 3131 display: inline-block; 3046 3132 margin-bottom: 1em; -
src/wp-admin/includes/file.php
123 123 * 124 124 * @param string $folder Optional. Full path to folder. Default empty. 125 125 * @param int $levels Optional. Levels of folders to follow, Default 100 (PHP Loop limit). 126 * @param array $exclusions Optional. List of folders to skip. 126 127 * @return bool|array False on failure, Else array of files 127 128 */ 128 function list_files( $folder = '', $levels = 100 ) {129 if ( empty( $folder) )129 function list_files( $folder = '', $levels = 100, $exclusions = array() ) { 130 if ( empty( $folder ) ) { 130 131 return false; 132 } 131 133 132 if ( ! $levels ) 134 $folder = trailingslashit( $folder ); 135 136 if ( ! $levels ) { 133 137 return false; 138 } 134 139 135 140 $files = array(); 136 if ( $dir = @opendir( $folder ) ) { 137 while (($file = readdir( $dir ) ) !== false ) { 138 if ( in_array($file, array('.', '..') ) ) 141 142 $dir = @opendir( $folder ); 143 if ( $dir ) { 144 while ( ( $file = readdir( $dir ) ) !== false ) { 145 // Skip current and parent folder links. 146 if ( in_array( $file, array( '.', '..' ), true ) ) { 139 147 continue; 140 if ( is_dir( $folder . '/' . $file ) ) { 141 $files2 = list_files( $folder . '/' . $file, $levels - 1); 142 if ( $files2 ) 148 } 149 150 // Skip hidden and excluded files. 151 if ( '.' === $file[0] || in_array( $file, $exclusions, true ) ) { 152 continue; 153 } 154 155 if ( is_dir( $folder . $file ) ) { 156 $files2 = list_files( $folder . $file, $levels - 1 ); 157 if ( $files2 ) { 143 158 $files = array_merge($files, $files2 ); 144 else 145 $files[] = $folder . '/' . $file . '/'; 159 } else { 160 $files[] = $folder . $file . '/'; 161 } 146 162 } else { 147 $files[] = $folder . '/' .$file;163 $files[] = $folder . $file; 148 164 } 149 165 } 150 166 } 151 167 @closedir( $dir ); 168 152 169 return $files; 153 170 } 154 171 -
src/wp-admin/includes/plugin.php
190 190 * @param string $plugin Path to the main plugin file from plugins directory. 191 191 * @return array List of files relative to the plugin root. 192 192 */ 193 function get_plugin_files( $plugin) {193 function get_plugin_files( $plugin ) { 194 194 $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 } 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 = false; //get_transient( $transient_key ); 204 if ( false !== $plugin_files ) { 205 return $plugin_files; 220 206 } 221 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 216 * 217 * @param array $exclusions Array of excluded directories and files. 218 */ 219 $exclusions = (array) apply_filters( 'get_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 += $list_files; 225 $plugin_files = array_unique( $plugin_files ); 226 } 227 228 set_transient( $transient_key, $plugin_files, HOUR_IN_SECONDS ); 229 222 230 return $plugin_files; 223 231 } 224 232 -
src/wp-admin/plugin-editor.php
14 14 exit(); 15 15 } 16 16 17 if ( !current_user_can('edit_plugins') ) 18 wp_die( __('Sorry, you are not allowed to edit plugins for this site.') ); 17 if ( ! current_user_can( 'edit_plugins' ) ) { 18 wp_die( __( 'Sorry, you are not allowed to edit plugins for this site.' ) ); 19 } 19 20 20 $title = __( "Edit Plugins");21 $title = __( 'Edit Plugins' ); 21 22 $parent_file = 'plugins.php'; 22 23 23 24 $plugins = get_plugins(); … … 66 67 } 67 68 } 68 69 69 $plugin_files = get_plugin_files( $plugin);70 $plugin_files = get_plugin_files( $plugin ); 70 71 71 72 if ( empty( $file ) ) { 72 73 $file = $plugin_files[0]; 73 74 } 74 75 75 $file = validate_file_to_edit( $file, $plugin_files);76 $file = validate_file_to_edit( $file, $plugin_files ); 76 77 $real_file = WP_PLUGIN_DIR . '/' . $file; 77 78 78 79 // Handle fallback editing of file when JavaScript is not available. … … 98 99 } 99 100 } 100 101 101 102 102 // List of allowable extensions 103 $editable_extensions = wp_get_plugin_file_editable_extensions( $plugin ); 103 104 104 if ( ! is_file($real_file) ) {105 wp_die(sprintf('<p>%s</p>', __('No such file exists! Double check the name and try again.')));106 107 108 if ( preg_match('/\.([^.]+)$/', $real_file, $matches) ) {109 $ext = strtolower($matches[1]);110 111 if ( !in_array( $ext, $editable_extensions) )112 wp_die(sprintf('<p>%s</p>', __('Files of this type are not editable.')));105 if ( ! is_file( $real_file ) ) { 106 wp_die( sprintf( '<p>%s</p>', __( 'No such file exists! Double check the name and try again.' ) ) ); 107 } else { 108 // Get the extension of the file 109 if ( preg_match( '/\.([^.]+)$/', $real_file, $matches ) ) { 110 $ext = strtolower( $matches[1] ); 111 // If extension is not in the acceptable list, skip it 112 if ( ! in_array( $ext, $editable_extensions ) ) { 113 wp_die( sprintf( '<p>%s</p>', __( 'Files of this type are not editable.' ) ) ); 113 114 } 114 115 } 116 } 115 117 116 118 get_current_screen()->add_help_tab( array( 117 'id'=> 'overview',118 'title' => __('Overview'),119 'content'=>120 '<p>' . __('You can use the editor to make changes to any of your plugins’ individual PHP files. Be aware that if you make changes, plugins updates will overwrite your customizations.') . '</p>' .121 '<p>' . __('Choose a plugin to edit from the dropdown menu and click the Select button. Click once on any file name to load it in the editor, and make your changes. Don’t forget to save your changes (Update File) when you’re finished.') . '</p>' .122 '<p>' . __('The Documentation menu below the editor lists the PHP functions recognized in the plugin file. Clicking Look Up takes you to a web page about that particular function.') . '</p>' .123 '<p id="editor-keyboard-trap-help-1">' . __( 'When using a keyboard to navigate:' ) . '</p>' .124 '<ul>' .125 '<li id="editor-keyboard-trap-help-2">' . __( 'In the editing area, the Tab key enters a tab character.' ) . '</li>' .126 '<li id="editor-keyboard-trap-help-3">' . __( 'To move away from this area, press the Esc key followed by the Tab key.' ) . '</li>' .127 '<li id="editor-keyboard-trap-help-4">' . __( 'Screen reader users: when in forms mode, you may need to press the Esc key twice.' ) . '</li>' .128 '</ul>' .129 '<p>' . __('If you want to make changes but don’t want them to be overwritten when the plugin is updated, you may be ready to think about writing your own plugin. For information on how to edit plugins, write your own from scratch, or just better understand their anatomy, check out the links below.') . '</p>' .130 ( is_network_admin() ? '<p>' . __('Any edits to files from this screen will be reflected on all sites in the network.') . '</p>' : '' )119 'id' => 'overview', 120 'title' => __( 'Overview' ), 121 'content' => 122 '<p>' . __( 'You can use the editor to make changes to any of your plugins’ individual PHP files. Be aware that if you make changes, plugins updates will overwrite your customizations.' ) . '</p>' . 123 '<p>' . __( 'Choose a plugin to edit from the dropdown menu and click the Select button. Click once on any file name to load it in the editor, and make your changes. Don’t forget to save your changes (Update File) when you’re finished.' ) . '</p>' . 124 '<p>' . __( 'The Documentation menu below the editor lists the PHP functions recognized in the plugin file. Clicking Look Up takes you to a web page about that particular function.' ) . '</p>' . 125 '<p id="editor-keyboard-trap-help-1">' . __( 'When using a keyboard to navigate:' ) . '</p>' . 126 '<ul>' . 127 '<li id="editor-keyboard-trap-help-2">' . __( 'In the editing area, the Tab key enters a tab character.' ) . '</li>' . 128 '<li id="editor-keyboard-trap-help-3">' . __( 'To move away from this area, press the Esc key followed by the Tab key.' ) . '</li>' . 129 '<li id="editor-keyboard-trap-help-4">' . __( 'Screen reader users: when in forms mode, you may need to press the Esc key twice.' ) . '</li>' . 130 '</ul>' . 131 '<p>' . __( 'If you want to make changes but don’t want them to be overwritten when the plugin is updated, you may be ready to think about writing your own plugin. For information on how to edit plugins, write your own from scratch, or just better understand their anatomy, check out the links below.' ) . '</p>' . 132 ( is_network_admin() ? '<p>' . __( 'Any edits to files from this screen will be reflected on all sites in the network.' ) . '</p>' : '' ), 131 133 ) ); 132 134 133 135 get_current_screen()->set_help_sidebar( 134 '<p><strong>' . __( 'For more information:') . '</strong></p>' .135 '<p>' . __( '<a href="https://codex.wordpress.org/Plugins_Editor_Screen">Documentation on Editing Plugins</a>') . '</p>' .136 '<p>' . __( '<a href="https://codex.wordpress.org/Writing_a_Plugin">Documentation on Writing Plugins</a>') . '</p>' .137 '<p>' . __( '<a href="https://wordpress.org/support/">Support Forums</a>') . '</p>'136 '<p><strong>' . __( 'For more information:' ) . '</strong></p>' . 137 '<p>' . __( '<a href="https://codex.wordpress.org/Plugins_Editor_Screen">Documentation on Editing Plugins</a>' ) . '</p>' . 138 '<p>' . __( '<a href="https://codex.wordpress.org/Writing_a_Plugin">Documentation on Writing Plugins</a>' ) . '</p>' . 139 '<p>' . __( '<a href="https://wordpress.org/support/">Support Forums</a>' ) . '</p>' 138 140 ); 139 141 140 142 $settings = array( … … 141 143 'codeEditor' => wp_enqueue_code_editor( array( 'file' => $real_file ) ), 142 144 ); 143 145 wp_enqueue_script( 'wp-theme-plugin-editor' ); 146 wp_enqueue_script( 'tree-links' ); 147 wp_enqueue_script( 'treeitem-links' ); 144 148 wp_add_inline_script( 'wp-theme-plugin-editor', sprintf( 'jQuery( function( $ ) { wp.themePluginEditor.init( $( "#template" ), %s ); } )', wp_json_encode( $settings ) ) ); 145 149 wp_add_inline_script( 'wp-theme-plugin-editor', sprintf( 'wp.themePluginEditor.themeOrPlugin = "plugin";' ) ); 146 150 147 require_once( ABSPATH . 'wp-admin/admin-header.php');151 require_once( ABSPATH . 'wp-admin/admin-header.php' ); 148 152 149 update_recently_edited( WP_PLUGIN_DIR . '/' . $file);153 update_recently_edited( WP_PLUGIN_DIR . '/' . $file ); 150 154 151 155 if ( ! empty( $posted_content ) ) { 152 156 $content = $posted_content; … … 157 161 if ( '.php' == substr( $real_file, strrpos( $real_file, '.' ) ) ) { 158 162 $functions = wp_doc_link_parse( $content ); 159 163 160 if ( ! empty($functions) ) {164 if ( ! empty( $functions ) ) { 161 165 $docs_select = '<select name="docs-list" id="docs-list">'; 162 166 $docs_select .= '<option value="">' . __( 'Function Name…' ) . '</option>'; 163 foreach ( $functions as $function ) {167 foreach ( $functions as $function ) { 164 168 $docs_select .= '<option value="' . esc_attr( $function ) . '">' . esc_html( $function ) . '()</option>'; 165 169 } 166 170 $docs_select .= '</select>'; … … 209 213 </div> 210 214 <div class="alignright"> 211 215 <form action="plugin-editor.php" method="get"> 212 <strong><label for="plugin"><?php _e( 'Select plugin to edit:'); ?> </label></strong>216 <strong><label for="plugin"><?php _e( 'Select plugin to edit:' ); ?> </label></strong> 213 217 <select name="plugin" id="plugin"> 214 218 <?php 215 foreach ( $plugins as $plugin_key => $a_plugin ) { 216 $plugin_name = $a_plugin['Name']; 217 if ( $plugin_key == $plugin ) 218 $selected = " selected='selected'"; 219 else 220 $selected = ''; 221 $plugin_name = esc_attr($plugin_name); 222 $plugin_key = esc_attr($plugin_key); 223 echo "\n\t<option value=\"$plugin_key\" $selected>$plugin_name</option>"; 219 foreach ( $plugins as $plugin_key => $a_plugin ) { 220 $plugin_name = $a_plugin['Name']; 221 if ( $plugin_key == $plugin ) { 222 $selected = " selected='selected'"; 223 } else { 224 $selected = ''; 224 225 } 226 $plugin_name = esc_attr( $plugin_name ); 227 $plugin_key = esc_attr( $plugin_key ); 228 echo "\n\t<option value=\"$plugin_key\" $selected>$plugin_name</option>"; 229 } 225 230 ?> 226 231 </select> 227 232 <?php submit_button( __( 'Select' ), '', 'Submit', false ); ?> … … 230 235 <br class="clear" /> 231 236 </div> 232 237 233 <div id="templateside"> 234 <h2><?php _e( 'Plugin Files' ); ?></h2> 238 <?php 239 $plugin_editable_files = array(); 240 foreach ( $plugin_files as $plugin_file ) { 241 if ( preg_match( '/\.([^.]+)$/', $plugin_file, $matches ) && in_array( $matches[1], $editable_extensions ) ) { 242 $plugin_editable_files[] = $plugin_file; 243 } 244 } 235 245 236 <?php 237 $plugin_editable_files = array(); 238 foreach ( $plugin_files as $plugin_file ) { 239 if ( preg_match('/\.([^.]+)$/', $plugin_file, $matches ) && in_array( $matches[1], $editable_extensions ) ) { 240 $plugin_editable_files[] = $plugin_file; 246 function wp_make_plugin_file_tree( $plugin_editable_files ) { 247 $tree_list = array(); 248 foreach ( $plugin_editable_files as $plugin_file ) { 249 $list = explode( '/', preg_replace( '#^.+?/#', '', $plugin_file ) ); 250 $last_dir = &$tree_list; 251 foreach ( $list as $dir ) { 252 $last_dir =& $last_dir[ $dir ]; 241 253 } 254 $last_dir = $plugin_file; 242 255 } 243 ?> 244 <ul> 245 <?php foreach ( $plugin_editable_files as $plugin_file ) : ?> 246 <li class="<?php echo esc_attr( $file === $plugin_file ? 'notice notice-info' : '' ); ?>"> 247 <a href="plugin-editor.php?file=<?php echo urlencode( $plugin_file ); ?>&plugin=<?php echo urlencode( $plugin ); ?>"><?php echo esc_html( preg_replace( '#^.+?/#', '', $plugin_file ) ); ?></a> 256 return $tree_list; 257 } 258 function wp_print_plugin_file_tree( $tree, $label = false ) { 259 global $file, $plugin; 260 if ( is_array( $tree ) ) { 261 foreach ( $tree as $label => $plugin_file ) : 262 if ( ! is_array( $plugin_file ) ) { 263 wp_print_plugin_file_tree( $plugin_file, $label ); 264 continue; 265 } 266 ?> 267 <li role="treeitem" aria-expanded="true" tabindex="-1"> 268 <span><?php echo esc_html( $label ); ?></span> 269 <ul role="group"><?php wp_print_plugin_file_tree( $plugin_file ); ?></ul> 270 </li> 271 <?php 272 endforeach; 273 } else { 274 ?> 275 <li role="none" class="<?php echo $file === $tree ? 'current-file' : ''; ?>"> 276 <a role="treeitem" tabindex="<?php echo $file === $tree ? '0' : '-1'; ?>" 277 href="plugin-editor.php?file=<?php echo urlencode( $tree ); ?>&plugin=<?php echo urlencode( $plugin ); ?>"> 278 <?php 279 if ( $file === $tree ) { 280 echo '<span class="notice notice-info">' . esc_html( $label ) . '</span>'; 281 } else { 282 echo esc_html( $label ); 283 } 284 ?> 285 </a> 248 286 </li> 249 <?php endforeach; ?> 287 <?php 288 } 289 } 290 ?> 291 <script> 292 jQuery(function($){ 293 // Starts with all expanded for non-js, and for js, collapses all, opens parents of current file. 294 $('#templateside [role="tree"] [aria-expanded]').attr("aria-expanded", false); 295 $('#templateside .notice').parents('[aria-expanded]').attr("aria-expanded", true); 296 }); 297 </script> 298 <div id="templateside"> 299 <h2 id="plugin-files-label"><?php _e( 'Plugin Files' ); ?></h2> 300 <ul role="tree" aria-labelledby="plugin-files-label"> 301 <?php wp_print_plugin_file_tree( wp_make_plugin_file_tree( $plugin_editable_files ) ); ?> 250 302 </ul> 251 303 </div> 252 304 <form name="template" id="template" action="plugin-editor.php" method="post"> … … 258 310 <input type="hidden" name="file" value="<?php echo esc_attr( $file ); ?>" /> 259 311 <input type="hidden" name="plugin" value="<?php echo esc_attr( $plugin ); ?>" /> 260 312 </div> 261 <?php if ( ! empty( $docs_select ) ) : ?>262 <div id="documentation" class="hide-if-no-js"><label for="docs-list"><?php _e( 'Documentation:') ?></label> <?php echo $docs_select ?> <input type="button" class="button" value="<?php esc_attr_e( 'Look Up' ) ?> " onclick="if ( '' != jQuery('#docs-list').val() ) { window.open( 'https://api.wordpress.org/core/handbook/1.0/?function=' + escape( jQuery( '#docs-list' ).val() ) + '&locale=<?php echo urlencode( get_user_locale() ) ?>&version=<?php echo urlencode( get_bloginfo( 'version' ) )?>&redirect=true'); }" /></div>313 <?php if ( ! empty( $docs_select ) ) : ?> 314 <div id="documentation" class="hide-if-no-js"><label for="docs-list"><?php _e( 'Documentation:' ); ?></label> <?php echo $docs_select; ?> <input type="button" class="button" value="<?php esc_attr_e( 'Look Up' ); ?> " onclick="if ( '' != jQuery('#docs-list').val() ) { window.open( 'https://api.wordpress.org/core/handbook/1.0/?function=' + escape( jQuery( '#docs-list' ).val() ) + '&locale=<?php echo urlencode( get_user_locale() ); ?>&version=<?php echo urlencode( get_bloginfo( 'version' ) ); ?>&redirect=true'); }" /></div> 263 315 <?php endif; ?> 264 <?php if ( is_writeable( $real_file) ) : ?>316 <?php if ( is_writeable( $real_file ) ) : ?> 265 317 <div class="editor-notices"> 266 318 <?php if ( in_array( $plugin, (array) get_option( 'active_plugins', array() ) ) ) { ?> 267 319 <div class="notice notice-warning inline active-plugin-edit-warning"> 268 <p><?php _e( '<strong>Warning:</strong> Making changes to active plugins is not recommended.'); ?></p>320 <p><?php _e( '<strong>Warning:</strong> Making changes to active plugins is not recommended.' ); ?></p> 269 321 </div> 270 322 <?php } ?> 271 323 </div> … … 274 326 <span class="spinner"></span> 275 327 </p> 276 328 <?php else : ?> 277 <p><em><?php _e( 'You need to make this file writable before you can save your changes. See <a href="https://codex.wordpress.org/Changing_File_Permissions">the Codex</a> for more information.'); ?></em></p>329 <p><em><?php _e( 'You need to make this file writable before you can save your changes. See <a href="https://codex.wordpress.org/Changing_File_Permissions">the Codex</a> for more information.' ); ?></em></p> 278 330 <?php endif; ?> 279 331 <?php wp_print_file_editor_templates(); ?> 280 332 </form> … … 298 350 <?php 299 351 endif; // editor warning notice 300 352 301 include( ABSPATH . "wp-admin/admin-footer.php");353 include( ABSPATH . 'wp-admin/admin-footer.php' ); -
src/wp-admin/theme-editor.php
14 14 exit(); 15 15 } 16 16 17 if ( !current_user_can('edit_themes') ) 18 wp_die('<p>'.__('Sorry, you are not allowed to edit templates for this site.').'</p>'); 17 if ( ! current_user_can( 'edit_themes' ) ) { 18 wp_die( '<p>' . __( 'Sorry, you are not allowed to edit templates for this site.' ) . '</p>' ); 19 } 19 20 20 $title = __( "Edit Themes");21 $title = __( 'Edit Themes' ); 21 22 $parent_file = 'themes.php'; 22 23 23 24 get_current_screen()->add_help_tab( array( 24 'id'=> 'overview',25 'title' => __('Overview'),26 'content'=>27 '<p>' . __( 'You can use the Theme Editor to edit the individual CSS and PHP files which make up your theme.' ) . '</p>' .28 '<p>' . __( 'Begin by choosing a theme to edit from the dropdown menu and clicking the Select button. A list then appears of the theme’s template files. Clicking once on any file name causes the file to appear in the large Editor box.' ) . '</p>' .29 '<p>' . __( 'For PHP files, you can use the Documentation dropdown to select from functions recognized in that file. Look Up takes you to a web page with reference material about that particular function.' ) . '</p>' .30 '<p id="editor-keyboard-trap-help-1">' . __( 'When using a keyboard to navigate:' ) . '</p>' .31 '<ul>' .32 '<li id="editor-keyboard-trap-help-2">' . __( 'In the editing area, the Tab key enters a tab character.' ) . '</li>' .33 '<li id="editor-keyboard-trap-help-3">' . __( 'To move away from this area, press the Esc key followed by the Tab key.' ) . '</li>' .34 '<li id="editor-keyboard-trap-help-4">' . __( 'Screen reader users: when in forms mode, you may need to press the Esc key twice.' ) . '</li>' .35 '</ul>' .36 '<p>' . __( 'After typing in your edits, click Update File.' ) . '</p>' .37 '<p>' . __( '<strong>Advice:</strong> think very carefully about your site crashing if you are live-editing the theme currently in use.' ) . '</p>' .38 /* translators: %s: link to codex article about child themes */39 '<p>' . sprintf( __( 'Upgrading to a newer version of the same theme will override changes made here. To avoid this, consider creating a <a href="%s">child theme</a> instead.' ), __( 'https://codex.wordpress.org/Child_Themes' ) ) . '</p>' .40 ( is_network_admin() ? '<p>' . __( 'Any edits to files from this screen will be reflected on all sites in the network.' ) . '</p>' : '' ),25 'id' => 'overview', 26 'title' => __( 'Overview' ), 27 'content' => 28 '<p>' . __( 'You can use the Theme Editor to edit the individual CSS and PHP files which make up your theme.' ) . '</p>' . 29 '<p>' . __( 'Begin by choosing a theme to edit from the dropdown menu and clicking the Select button. A list then appears of the theme’s template files. Clicking once on any file name causes the file to appear in the large Editor box.' ) . '</p>' . 30 '<p>' . __( 'For PHP files, you can use the Documentation dropdown to select from functions recognized in that file. Look Up takes you to a web page with reference material about that particular function.' ) . '</p>' . 31 '<p id="editor-keyboard-trap-help-1">' . __( 'When using a keyboard to navigate:' ) . '</p>' . 32 '<ul>' . 33 '<li id="editor-keyboard-trap-help-2">' . __( 'In the editing area, the Tab key enters a tab character.' ) . '</li>' . 34 '<li id="editor-keyboard-trap-help-3">' . __( 'To move away from this area, press the Esc key followed by the Tab key.' ) . '</li>' . 35 '<li id="editor-keyboard-trap-help-4">' . __( 'Screen reader users: when in forms mode, you may need to press the Esc key twice.' ) . '</li>' . 36 '</ul>' . 37 '<p>' . __( 'After typing in your edits, click Update File.' ) . '</p>' . 38 '<p>' . __( '<strong>Advice:</strong> think very carefully about your site crashing if you are live-editing the theme currently in use.' ) . '</p>' . 39 /* translators: %s: link to codex article about child themes */ 40 '<p>' . sprintf( __( 'Upgrading to a newer version of the same theme will override changes made here. To avoid this, consider creating a <a href="%s">child theme</a> instead.' ), __( 'https://codex.wordpress.org/Child_Themes' ) ) . '</p>' . 41 ( is_network_admin() ? '<p>' . __( 'Any edits to files from this screen will be reflected on all sites in the network.' ) . '</p>' : '' ), 41 42 ) ); 42 43 43 44 get_current_screen()->set_help_sidebar( 44 '<p><strong>' . __( 'For more information:') . '</strong></p>' .45 '<p>' . __( '<a href="https://codex.wordpress.org/Theme_Development">Documentation on Theme Development</a>') . '</p>' .46 '<p>' . __( '<a href="https://codex.wordpress.org/Using_Themes">Documentation on Using Themes</a>') . '</p>' .47 '<p>' . __( '<a href="https://codex.wordpress.org/Editing_Files">Documentation on Editing Files</a>') . '</p>' .48 '<p>' . __( '<a href="https://codex.wordpress.org/Template_Tags">Documentation on Template Tags</a>') . '</p>' .49 '<p>' . __( '<a href="https://wordpress.org/support/">Support Forums</a>') . '</p>'45 '<p><strong>' . __( 'For more information:' ) . '</strong></p>' . 46 '<p>' . __( '<a href="https://codex.wordpress.org/Theme_Development">Documentation on Theme Development</a>' ) . '</p>' . 47 '<p>' . __( '<a href="https://codex.wordpress.org/Using_Themes">Documentation on Using Themes</a>' ) . '</p>' . 48 '<p>' . __( '<a href="https://codex.wordpress.org/Editing_Files">Documentation on Editing Files</a>' ) . '</p>' . 49 '<p>' . __( '<a href="https://codex.wordpress.org/Template_Tags">Documentation on Template Tags</a>' ) . '</p>' . 50 '<p>' . __( '<a href="https://wordpress.org/support/">Support Forums</a>' ) . '</p>' 50 51 ); 51 52 52 53 wp_reset_vars( array( 'action', 'error', 'file', 'theme' ) ); … … 67 68 wp_die( __( 'The requested theme does not exist.' ) . ' ' . $theme->errors()->get_error_message() ); 68 69 } 69 70 70 $allowed_files = $style_files = array(); 71 $allowed_files = array(); 72 $style_files = array(); 71 73 $has_templates = false; 72 74 73 75 $file_types = wp_get_theme_file_editable_extensions( $theme ); … … 75 77 foreach ( $file_types as $type ) { 76 78 switch ( $type ) { 77 79 case 'php': 78 $allowed_files += $theme->get_files( 'php', 1 );80 $allowed_files += $theme->get_files( 'php', -1 ); 79 81 $has_templates = ! empty( $allowed_files ); 80 82 break; 81 83 case 'css': 82 $style_files = $theme->get_files( 'css' );84 $style_files = $theme->get_files( 'css', -1 ); 83 85 $allowed_files['style.css'] = $style_files['style.css']; 84 86 $allowed_files += $style_files; 85 87 break; 86 88 default: 87 $allowed_files += $theme->get_files( $type );89 $allowed_files += $theme->get_files( $type, -1 ); 88 90 break; 89 91 } 90 92 } 91 93 94 // Move functions.php and style.css to the top. 95 if ( isset( $allowed_files['functions.php'] ) ) { 96 $allowed_files = array( 'functions.php' => $allowed_files['functions.php'] ) + $allowed_files; 97 } 98 if ( isset( $allowed_files['style.css'] ) ) { 99 $allowed_files = array( 'style.css' => $allowed_files['style.css'] ) + $allowed_files; 100 } 101 92 102 if ( empty( $file ) ) { 93 103 $relative_file = 'style.css'; 94 104 $file = $allowed_files['style.css']; … … 103 113 $edit_error = null; 104 114 $posted_content = null; 105 115 if ( 'POST' === $_SERVER['REQUEST_METHOD'] ) { 106 $r = wp_edit_theme_ plugin_file( wp_unslash( $_POST ) );116 $r = wp_edit_theme_theme_file( wp_unslash( $_POST ) ); 107 117 if ( is_wp_error( $r ) ) { 108 118 $edit_error = $r; 109 119 if ( check_ajax_referer( 'edit-theme_' . $file . $stylesheet, 'nonce', false ) && isset( $_POST['newcontent'] ) ) { … … 122 132 } 123 133 } 124 134 125 126 127 128 129 130 135 $settings = array( 136 'codeEditor' => wp_enqueue_code_editor( compact( 'file' ) ), 137 ); 138 wp_enqueue_script( 'wp-theme-plugin-editor' ); 139 wp_add_inline_script( 'wp-theme-plugin-editor', sprintf( 'jQuery( function( $ ) { wp.themePluginEditor.init( $( "#template" ), %s ); } )', wp_json_encode( $settings ) ) ); 140 wp_add_inline_script( 'wp-theme-plugin-editor', 'wp.themePluginEditor.themeOrPlugin = "theme";' ); 131 141 132 require_once( ABSPATH . 'wp-admin/admin-header.php' ); 142 wp_enqueue_script( 'tree-links' ); 143 wp_enqueue_script( 'treeitem-links' ); 133 144 134 update_recently_edited( $file);145 require_once( ABSPATH . 'wp-admin/admin-header.php' ); 135 146 136 if ( ! is_file( $file ) ) 137 $error = true; 147 update_recently_edited( $file ); 138 148 139 $content = ''; 140 if ( ! empty( $posted_content ) ) { 141 $content = $posted_content; 142 } elseif ( ! $error && filesize( $file ) > 0 ) { 143 $f = fopen($file, 'r'); 144 $content = fread($f, filesize($file)); 149 if ( ! is_file( $file ) ) { 150 $error = true; 151 } 145 152 146 if ( '.php' == substr( $file, strrpos( $file, '.' ) ) ) { 147 $functions = wp_doc_link_parse( $content ); 153 $content = ''; 154 if ( ! empty( $posted_content ) ) { 155 $content = $posted_content; 156 } elseif ( ! $error && filesize( $file ) > 0 ) { 157 $f = fopen( $file, 'r' ); 158 $content = fread( $f, filesize( $file ) ); 148 159 149 $docs_select = '<select name="docs-list" id="docs-list">'; 150 $docs_select .= '<option value="">' . esc_attr__( 'Function Name…' ) . '</option>'; 151 foreach ( $functions as $function ) { 152 $docs_select .= '<option value="' . esc_attr( urlencode( $function ) ) . '">' . htmlspecialchars( $function ) . '()</option>'; 153 } 154 $docs_select .= '</select>'; 160 if ( '.php' == substr( $file, strrpos( $file, '.' ) ) ) { 161 $functions = wp_doc_link_parse( $content ); 162 163 $docs_select = '<select name="docs-list" id="docs-list">'; 164 $docs_select .= '<option value="">' . esc_attr__( 'Function Name…' ) . '</option>'; 165 foreach ( $functions as $function ) { 166 $docs_select .= '<option value="' . esc_attr( urlencode( $function ) ) . '">' . htmlspecialchars( $function ) . '()</option>'; 155 167 } 156 157 $content = esc_textarea( $content ); 168 $docs_select .= '</select>'; 158 169 } 159 170 171 $content = esc_textarea( $content ); 172 } 173 160 174 $file_description = get_file_description( $relative_file ); 161 175 $file_show = array_search( $file, array_filter( $allowed_files ) ); 162 176 $description = esc_html( $file_description ); … … 180 194 181 195 <div class="fileedit-sub"> 182 196 <div class="alignleft"> 183 <h2><?php echo $theme->display( 'Name' ); if ( $description ) echo ': ' . $description; ?></h2> 197 <h2> 198 <?php 199 echo $theme->display( 'Name' ); 200 if ( $description ) { 201 echo ': ' . $description; 202 } 203 ?> 204 </h2> 184 205 </div> 185 206 <div class="alignright"> 186 207 <form action="theme-editor.php" method="get"> 187 <strong><label for="theme"><?php _e( 'Select theme to edit:'); ?> </label></strong>208 <strong><label for="theme"><?php _e( 'Select theme to edit:' ); ?> </label></strong> 188 209 <select name="theme" id="theme"> 189 210 <?php 190 211 foreach ( wp_get_themes( array( 'errors' => null ) ) as $a_stylesheet => $a_theme ) { 191 if ( $a_theme->errors() && 'theme_no_stylesheet' == $a_theme->errors()->get_error_code() ) 212 if ( $a_theme->errors() && 'theme_no_stylesheet' == $a_theme->errors()->get_error_code() ) { 192 213 continue; 214 } 193 215 194 216 $selected = $a_stylesheet == $stylesheet ? ' selected="selected"' : ''; 195 echo "\n\t" . '<option value="' . esc_attr( $a_stylesheet ) . '"' . $selected . '>' . $a_theme->display( 'Name') . '</option>';217 echo "\n\t" . '<option value="' . esc_attr( $a_stylesheet ) . '"' . $selected . '>' . $a_theme->display( 'Name' ) . '</option>'; 196 218 } 197 219 ?> 198 220 </select> … … 202 224 <br class="clear" /> 203 225 </div> 204 226 <?php 205 if ( $theme->errors() ) 227 if ( $theme->errors() ) { 206 228 echo '<div class="error"><p><strong>' . __( 'This theme is broken.' ) . '</strong> ' . $theme->errors()->get_error_message() . '</p></div>'; 229 } 207 230 ?> 208 231 <div id="templateside"> 209 232 <?php 210 if ( $allowed_files ) : 211 $previous_file_type = ''; 212 213 foreach ( $allowed_files as $filename => $absolute_filename ) : 214 $file_type = substr( $filename, strrpos( $filename, '.' ) ); 215 216 if ( $file_type !== $previous_file_type ) { 217 if ( '' !== $previous_file_type ) { 218 echo "\t</ul>\n"; 233 function wp_make_theme_file_tree( $allowed_files ) { 234 $tree_list = array(); 235 foreach ( $allowed_files as $file_name => $absolute_filename ) { 236 $list = explode( '/', $file_name ); 237 $last_dir = &$tree_list; 238 foreach ( $list as $dir ) { 239 $last_dir =& $last_dir[ $dir ]; 240 } 241 $last_dir = $file_name; 242 } 243 return $tree_list; 244 } 245 function wp_print_theme_file_tree( $tree, $label = false ) { 246 global $relative_file, $stylesheet; 247 if ( is_array( $tree ) ) { 248 foreach ( $tree as $label => $theme_file ) : 249 if ( ! is_array( $theme_file ) ) { 250 wp_print_theme_file_tree( $theme_file, $label ); 251 continue; 219 252 } 253 ?> 254 <li role="treeitem" aria-expanded="true" tabindex="-1"> 255 <span><?php echo esc_html( $label ); ?></span> 256 <ul role="group"><?php wp_print_theme_file_tree( $theme_file ); ?></ul> 257 </li> 258 <?php 259 endforeach; 260 } else { 261 $filename = $tree; 262 ?> 263 <li role="none" class="<?php echo $relative_file === $filename ? 'current-file' : ''; ?>"> 264 <a role="treeitem" tabindex="<?php echo $relative_file === $filename ? '0' : '-1'; ?>" 265 href="theme-editor.php?file=<?php echo urlencode( $tree ); ?>&theme=<?php echo urlencode( $stylesheet ); ?>" 266 > 267 <?php 268 $file_description = esc_html( get_file_description( $filename ) ); 269 if ( $file_description !== $filename ) { 270 $file_description .= '<br /><span class="nonessential">(' . esc_html( $filename ) . ')</span>'; 271 } 220 272 221 switch ( $file_type ) { 222 case '.php': 223 if ( $has_templates || $theme->parent() ) : 224 echo "\t<h2>" . __( 'Templates' ) . "</h2>\n"; 225 if ( $theme->parent() ) { 226 echo '<p class="howto">' . sprintf( __( 'This child theme inherits templates from a parent theme, %s.' ), 227 sprintf( '<a href="%s">%s</a>', 228 self_admin_url( 'theme-editor.php?theme=' . urlencode( $theme->get_template() ) ), 229 $theme->parent()->display( 'Name' ) 230 ) 231 ) . "</p>\n"; 232 } 233 endif; 234 break; 235 case '.css': 236 echo "\t<h2>" . _x( 'Styles', 'Theme stylesheets in theme editor' ) . "</h2>\n"; 237 break; 238 default: 239 /* translators: %s: file extension */ 240 echo "\t<h2>" . sprintf( __( '%s files' ), $file_type ) . "</h2>\n"; 241 break; 273 if ( $relative_file === $filename ) { 274 echo '<span class="notice notice-info">' . $file_description . '</span>'; 275 } else { 276 echo $file_description; 277 } 278 ?> 279 </a> 280 </li> 281 <?php 282 } 283 } 284 ?> 285 <h2 id="theme-files-label"><?php _e( 'Theme Files' ); ?></h2> 286 <?php 287 if ( $has_templates || $theme->parent() ) : 288 if ( $theme->parent() ) { 289 /* translators: %s: link to edit parent theme */ 290 echo '<p class="howto">' . sprintf( __( 'This child theme inherits templates from a parent theme, %s.' ), 291 sprintf( '<a href="%s">%s</a>', 292 self_admin_url( 'theme-editor.php?theme=' . urlencode( $theme->get_template() ) ), 293 $theme->parent()->display( 'Name' ) 294 ) 295 ) . "</p>\n"; 242 296 } 243 244 echo "\t<ul>\n"; 245 } 246 247 $file_description = esc_html( get_file_description( $filename ) ); 248 if ( $filename !== basename( $absolute_filename ) || $file_description !== $filename ) { 249 $file_description .= '<br /><span class="nonessential">(' . esc_html( $filename ) . ')</span>'; 250 } 251 252 if ( $absolute_filename === $file ) { 253 $file_description = '<span class="notice notice-info">' . $file_description . '</span>'; 254 } 255 256 $previous_file_type = $file_type; 257 ?> 258 <li><a href="theme-editor.php?file=<?php echo urlencode( $filename ) ?>&theme=<?php echo urlencode( $stylesheet ) ?>"><?php echo $file_description; ?></a></li> 297 endif; 298 ?> 299 <ul role="tree" aria-labelledby="theme-files-label"> 300 <?php wp_print_theme_file_tree( wp_make_theme_file_tree( $allowed_files ) ); ?> 301 </ul> 302 <script> 303 jQuery(function($){ 304 // Starts with all expanded for non-js, and for js, collapses all, opens parents of current file. 305 $('#templateside [role="tree"] [aria-expanded]').attr("aria-expanded", false); 306 $('#templateside .notice').parents('[aria-expanded]').attr("aria-expanded", true); 307 }); 308 </script> 309 </div> 259 310 <?php 260 endforeach; 261 ?> 262 </ul> 263 <?php endif; ?> 264 </div> 265 <?php if ( $error ) : 266 echo '<div class="error"><p>' . __('Oops, no such file exists! Double check the name and try again, merci.') . '</p></div>'; 267 else : ?> 311 if ( $error ) : 312 echo '<div class="error"><p>' . __( 'Oops, no such file exists! Double check the name and try again, merci.' ) . '</p></div>'; 313 else : 314 ?> 268 315 <form name="template" id="template" action="theme-editor.php" method="post"> 269 316 <?php wp_nonce_field( 'edit-theme_' . $file . $stylesheet, 'nonce' ); ?> 270 317 <div> … … 276 323 </div> 277 324 <?php if ( ! empty( $functions ) ) : ?> 278 325 <div id="documentation" class="hide-if-no-js"> 279 <label for="docs-list"><?php _e( 'Documentation:')?></label>326 <label for="docs-list"><?php _e( 'Documentation:' ); ?></label> 280 327 <?php echo $docs_select; ?> 281 <input type="button" class="button" value="<?php esc_attr_e( 'Look Up' ); ?>" onclick="if ( '' != jQuery('#docs-list').val() ) { window.open( 'https://api.wordpress.org/core/handbook/1.0/?function=' + escape( jQuery( '#docs-list' ).val() ) + '&locale=<?php echo urlencode( get_user_locale() ) ?>&version=<?php echo urlencode( get_bloginfo( 'version' ) )?>&redirect=true'); }" />328 <input type="button" class="button" value="<?php esc_attr_e( 'Look Up' ); ?>" onclick="if ( '' != jQuery('#docs-list').val() ) { window.open( 'https://api.wordpress.org/core/handbook/1.0/?function=' + escape( jQuery( '#docs-list' ).val() ) + '&locale=<?php echo urlencode( get_user_locale() ); ?>&version=<?php echo urlencode( get_bloginfo( 'version' ) ); ?>&redirect=true'); }" /> 282 329 </div> 283 330 <?php endif; ?> 284 331 … … 287 334 <?php if ( is_child_theme() && $theme->get_stylesheet() == get_template() ) : ?> 288 335 <div class="notice notice-warning inline"> 289 336 <p> 290 <?php if ( is_writeable( $file ) ) { ?><strong><?php _e( 'Caution:' ); ?></strong><?php } ?> 337 <?php if ( is_writeable( $file ) ) { ?> 338 <strong><?php _e( 'Caution:' ); ?></strong> 339 <?php } ?> 291 340 <?php _e( 'This is a file in your current parent theme.' ); ?> 292 341 </p> 293 342 </div> … … 299 348 <span class="spinner"></span> 300 349 </p> 301 350 <?php else : ?> 302 <p><em><?php _e( 'You need to make this file writable before you can save your changes. See <a href="https://codex.wordpress.org/Changing_File_Permissions">the Codex</a> for more information.'); ?></em></p>351 <p><em><?php _e( 'You need to make this file writable before you can save your changes. See <a href="https://codex.wordpress.org/Changing_File_Permissions">the Codex</a> for more information.' ); ?></em></p> 303 352 <?php endif; ?> 304 353 </div> 305 354 <?php wp_print_file_editor_templates(); ?> … … 335 384 <?php 336 385 endif; // editor warning notice 337 386 338 include( ABSPATH . 'wp-admin/admin-footer.php' );387 include( ABSPATH . 'wp-admin/admin-footer.php' ); -
src/wp-includes/class-wp-theme.php
981 981 * @param int $depth Optional. How deep to search for files. Defaults to a flat scan (0 depth). -1 depth is infinite. 982 982 * @param bool $search_parent Optional. Whether to return parent files. Defaults to false. 983 983 * @return array Array of files, keyed by the path to the file relative to the theme's directory, with the values 984 * 984 * being absolute paths. 985 985 */ 986 986 public function get_files( $type = null, $depth = 0, $search_parent = false ) { 987 $files = (array) self::scandir( $this->get_stylesheet_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 ); 988 990 989 if ( $search_parent && $this->parent() ) 990 $files += (array) self::scandir( $this->get_template_directory(), $type, $depth ); 991 $all_files = get_transient( $transient_key ); 992 if ( false === $all_files ) { 993 $all_files = (array) self::scandir( $this->get_stylesheet_directory(), null, -1 ); 991 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 } 1016 992 1017 return $files; 993 1018 } 994 1019 … … 1107 1132 * with `$relative_path`, with the values being absolute paths. False otherwise. 1108 1133 */ 1109 1134 private static function scandir( $path, $extensions = null, $depth = 0, $relative_path = '' ) { 1110 if ( ! is_dir( $path ) ) 1135 if ( ! is_dir( $path ) ) { 1111 1136 return false; 1137 } 1112 1138 1113 1139 if ( $extensions ) { 1114 1140 $extensions = (array) $extensions; … … 1116 1142 } 1117 1143 1118 1144 $relative_path = trailingslashit( $relative_path ); 1119 if ( '/' == $relative_path ) 1145 if ( '/' == $relative_path ) { 1120 1146 $relative_path = ''; 1147 } 1121 1148 1122 1149 $results = scandir( $path ); 1123 1150 $files = array(); … … 1125 1152 /** 1126 1153 * Filters the array of excluded directories and files while scanning theme folder. 1127 1154 * 1128 1155 * @since 4.7.4 1129 1156 * 1130 1157 * @param array $exclusions Array of excluded directories and files. 1131 1158 */ 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' ) ); 1133 1160 1134 1161 foreach ( $results as $result ) { 1135 1162 if ( '.' == $result[0] || in_array( $result, $exclusions, true ) ) { … … 1136 1163 continue; 1137 1164 } 1138 1165 if ( is_dir( $path . '/' . $result ) ) { 1139 if ( ! $depth ) 1166 if ( ! $depth ) { 1140 1167 continue; 1168 } 1141 1169 $found = self::scandir( $path . '/' . $result, $extensions, $depth - 1 , $relative_path . $result ); 1142 1170 $files = array_merge_recursive( $files, $found ); 1143 1171 } elseif ( ! $extensions || preg_match( '~\.(' . $_extensions . ')$~', $result ) ) { -
src/wp-includes/script-loader.php
628 628 629 629 $scripts->add( 'wp-api', "/wp-includes/js/wp-api$suffix.js", array( 'jquery', 'backbone', 'underscore', 'wp-api-request' ), false, 1 ); 630 630 631 $scripts->add( 'tree-links', "/wp-includes/js/tree-links$suffix.js", array( 'jquery' ), false, 1 ); 632 $scripts->add( 'treeitem-links', "/wp-includes/js/treeitem-links$suffix.js", array( 'jquery', 'tree-links' ), false, 1 ); 633 631 634 if ( is_admin() ) { 632 635 $scripts->add( 'admin-tags', "/wp-admin/js/tags$suffix.js", array( 'jquery', 'wp-ajax-response' ), false, 1 ); 633 636 did_action( 'init' ) && $scripts->localize( 'admin-tags', 'tagsl10n', array( -
tests/phpunit/tests/admin/includesPlugin.php
94 94 } 95 95 96 96 /** 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 /** 97 122 * @covers ::get_mu_plugins 98 123 */ 99 124 public function test_get_mu_plugins_when_mu_plugins_exists_but_is_empty() {