web/wp-admin/theme-editor.php
changeset 194 32102edaa81b
parent 136 bde1974c263b
child 204 09a1c134465b
equal deleted inserted replaced
193:2f6f6f7551ca 194:32102edaa81b
     5  * @package WordPress
     5  * @package WordPress
     6  * @subpackage Administration
     6  * @subpackage Administration
     7  */
     7  */
     8 
     8 
     9 /** WordPress Administration Bootstrap */
     9 /** WordPress Administration Bootstrap */
    10 require_once('admin.php');
    10 require_once('./admin.php');
       
    11 
       
    12 if ( is_multisite() && ! is_network_admin() ) {
       
    13 	wp_redirect( network_admin_url( 'theme-editor.php' ) );
       
    14 	exit();
       
    15 }
    11 
    16 
    12 if ( !current_user_can('edit_themes') )
    17 if ( !current_user_can('edit_themes') )
    13 	wp_die('<p>'.__('You do not have sufficient permissions to edit templates for this blog.').'</p>');
    18 	wp_die('<p>'.__('You do not have sufficient permissions to edit templates for this site.').'</p>');
    14 
    19 
    15 $title = __("Edit Themes");
    20 $title = __("Edit Themes");
    16 $parent_file = 'themes.php';
    21 $parent_file = 'themes.php';
    17 
    22 
    18 wp_reset_vars(array('action', 'redirect', 'profile', 'error', 'warning', 'a', 'file', 'theme', 'dir'));
    23 get_current_screen()->add_help_tab( array(
    19 
    24 'id'		=> 'overview',
    20 wp_admin_css( 'theme-editor' );
    25 'title'		=> __('Overview'),
    21 
    26 'content'	=>
    22 $themes = get_themes();
    27 	'<p>' . __('You can use the Theme Editor to edit the individual CSS and PHP files which make up your theme.') . '</p>
    23 
    28 	<p>' . __('Begin by choosing a theme to edit from the dropdown menu and clicking Select. A list then appears of all the template files. Clicking once on any file name causes the file to appear in the large Editor box.') . '</p>
    24 if (empty($theme)) {
    29 	<p>' . __('For PHP files, you can use the Documentation dropdown to select from functions recognized in that file. Lookup takes you to a web page with reference material about that particular function.') . '</p>
    25 	$theme = get_current_theme();
    30 	<p>' . __('After typing in your edits, click Update File.') . '</p>
       
    31 	<p>' . __('<strong>Advice:</strong> think very carefully about your site crashing if you are live-editing the theme currently in use.') . '</p>
       
    32 	<p>' . __('Upgrading to a newer version of the same theme will override changes made here. To avoid this, consider creating a <a href="http://codex.wordpress.org/Child_Themes" target="_blank">child theme</a> instead.') . '</p>' .
       
    33 	( is_network_admin() ? '<p>' . __('Any edits to files from this screen will be reflected on all sites in the network.') . '</p>' : '' )
       
    34 ) );
       
    35 
       
    36 get_current_screen()->set_help_sidebar(
       
    37 	'<p><strong>' . __('For more information:') . '</strong></p>' .
       
    38 	'<p>' . __('<a href="http://codex.wordpress.org/Theme_Development" target="_blank">Documentation on Theme Development</a>') . '</p>' .
       
    39 	'<p>' . __('<a href="http://codex.wordpress.org/Using_Themes" target="_blank">Documentation on Using Themes</a>') . '</p>' .
       
    40 	'<p>' . __('<a href="http://codex.wordpress.org/Editing_Files" target="_blank">Documentation on Editing Files</a>') . '</p>' .
       
    41 	'<p>' . __('<a href="http://codex.wordpress.org/Template_Tags" target="_blank">Documentation on Template Tags</a>') . '</p>' .
       
    42 	'<p>' . __('<a href="http://wordpress.org/support/" target="_blank">Support Forums</a>') . '</p>'
       
    43 );
       
    44 
       
    45 wp_reset_vars( array( 'action', 'error', 'file', 'theme' ) );
       
    46 
       
    47 if ( $theme )
       
    48 	$stylesheet = urldecode( $theme );
       
    49 else
       
    50 	$stylesheet = get_stylesheet();
       
    51 
       
    52 $theme = wp_get_theme( $stylesheet );
       
    53 
       
    54 if ( ! $theme->exists() )
       
    55 	wp_die( __( 'The requested theme does not exist.' ) );
       
    56 
       
    57 if ( $theme->errors() && 'theme_no_stylesheet' == $theme->errors()->get_error_code() )
       
    58 	wp_die( __( 'The requested theme does not exist.' ) . ' ' . $theme->errors()->get_error_message() );
       
    59 
       
    60 $allowed_files = $theme->get_files( 'php', 1 );
       
    61 $has_templates = ! empty( $allowed_files );
       
    62 $style_files = $theme->get_files( 'css' );
       
    63 $allowed_files['style.css'] = $style_files['style.css'];
       
    64 $allowed_files += $style_files;
       
    65 
       
    66 if ( empty( $file ) ) {
       
    67 	$relative_file = 'style.css';
       
    68 	$file = $allowed_files['style.css'];
    26 } else {
    69 } else {
    27 	$theme = stripslashes($theme);
    70 	$relative_file = urldecode( stripslashes( $file ) );
    28 }
    71 	$file = $theme->get_stylesheet_directory() . '/' . $relative_file;
    29 
    72 }
    30 if ( ! isset($themes[$theme]) )
    73 
    31 	wp_die(__('The requested theme does not exist.'));
    74 validate_file_to_edit( $file, $allowed_files );
    32 
    75 $scrollto = isset( $_REQUEST['scrollto'] ) ? (int) $_REQUEST['scrollto'] : 0;
    33 $allowed_files = array_merge($themes[$theme]['Stylesheet Files'], $themes[$theme]['Template Files']);
    76 
    34 
    77 switch( $action ) {
    35 if (empty($file)) {
    78 case 'update':
    36 	$file = $allowed_files[0];
    79 	check_admin_referer( 'edit-theme_' . $file . $stylesheet );
    37 } else {
    80 	$newcontent = stripslashes( $_POST['newcontent'] );
    38 	$file = stripslashes($file);
    81 	$location = 'theme-editor.php?file=' . urlencode( $relative_file ) . '&theme=' . urlencode( $stylesheet ) . '&scrollto=' . $scrollto;
    39 	if ( 'theme' == $dir ) {
    82 	if ( is_writeable( $file ) ) {
    40 		$file = dirname(dirname($themes[$theme]['Template Dir'])) . $file ; 
    83 		//is_writable() not always reliable, check return value. see comments @ http://uk.php.net/is_writable
    41 	} else if ( 'style' == $dir) {
    84 		$f = fopen( $file, 'w+' );
    42 		$file = dirname(dirname($themes[$theme]['Stylesheet Dir'])) . $file ; 
    85 		if ( $f !== false ) {
       
    86 			fwrite( $f, $newcontent );
       
    87 			fclose( $f );
       
    88 			$location .= '&updated=true';
       
    89 			$theme->cache_delete();
       
    90 		}
    43 	}
    91 	}
    44 }
    92 	wp_redirect( $location );
    45 
    93 	exit;
    46 validate_file_to_edit($file, $allowed_files);
       
    47 $scrollto = isset($_REQUEST['scrollto']) ? (int) $_REQUEST['scrollto'] : 0;
       
    48 $file_show = basename( $file );
       
    49 
       
    50 switch($action) {
       
    51 
       
    52 case 'update':
       
    53 
       
    54 	check_admin_referer('edit-theme_' . $file . $theme);
       
    55 
       
    56 	$newcontent = stripslashes($_POST['newcontent']);
       
    57 	$theme = urlencode($theme);
       
    58 	if (is_writeable($file)) {
       
    59 		//is_writable() not always reliable, check return value. see comments @ http://uk.php.net/is_writable
       
    60 		$f = fopen($file, 'w+');
       
    61 		if ($f !== FALSE) {
       
    62 			fwrite($f, $newcontent);
       
    63 			fclose($f);
       
    64 			$location = "theme-editor.php?file=$file&theme=$theme&a=te&scrollto=$scrollto";
       
    65 		} else {
       
    66 			$location = "theme-editor.php?file=$file&theme=$theme&scrollto=$scrollto";
       
    67 		}
       
    68 	} else {
       
    69 		$location = "theme-editor.php?file=$file&theme=$theme&scrollto=$scrollto";
       
    70 	}
       
    71 
       
    72 	$location = wp_kses_no_null($location);
       
    73 	$strip = array('%0d', '%0a', '%0D', '%0A');
       
    74 	$location = _deep_replace($strip, $location);
       
    75 	header("Location: $location");
       
    76 	exit();
       
    77 
       
    78 break;
    94 break;
    79 
    95 
    80 default:
    96 default:
    81 
    97 
    82 	require_once('admin-header.php');
    98 	require_once( ABSPATH . 'wp-admin/admin-header.php' );
    83 
    99 
    84 	update_recently_edited($file);
   100 	update_recently_edited( $file );
    85 
   101 
    86 	if ( !is_file($file) )
   102 	if ( ! is_file( $file ) )
    87 		$error = 1;
   103 		$error = true;
    88 
   104 
    89 	if ( !$error && filesize($file) > 0 ) {
   105 	$content = '';
       
   106 	if ( ! $error && filesize( $file ) > 0 ) {
    90 		$f = fopen($file, 'r');
   107 		$f = fopen($file, 'r');
    91 		$content = fread($f, filesize($file));
   108 		$content = fread($f, filesize($file));
    92 
   109 
    93 		if ( '.php' == substr( $file, strrpos( $file, '.' ) ) ) {
   110 		if ( '.php' == substr( $file, strrpos( $file, '.' ) ) ) {
    94 			$functions = wp_doc_link_parse( $content );
   111 			$functions = wp_doc_link_parse( $content );
    99 				$docs_select .= '<option value="' . esc_attr( urlencode( $function ) ) . '">' . htmlspecialchars( $function ) . '()</option>';
   116 				$docs_select .= '<option value="' . esc_attr( urlencode( $function ) ) . '">' . htmlspecialchars( $function ) . '()</option>';
   100 			}
   117 			}
   101 			$docs_select .= '</select>';
   118 			$docs_select .= '</select>';
   102 		}
   119 		}
   103 
   120 
   104 		$content = htmlspecialchars( $content );
   121 		$content = esc_textarea( $content );
   105 		$codepress_lang = codepress_get_lang($file);
       
   106 	}
   122 	}
   107 
   123 
   108 	?>
   124 	?>
   109 <?php if (isset($_GET['a'])) : ?>
   125 <?php if ( isset( $_GET['updated'] ) ) : ?>
   110  <div id="message" class="updated fade"><p><?php _e('File edited successfully.') ?></p></div>
   126  <div id="message" class="updated"><p><?php _e( 'File edited successfully.' ) ?></p></div>
   111 <?php endif;
   127 <?php endif;
   112 
   128 
   113 $description = get_file_description($file);
   129 $description = get_file_description( $file );
   114 $desc_header = ( $description != $file_show ) ? "<strong>$description</strong> (%s)" : "%s";
   130 $file_show = array_search( $file, array_filter( $allowed_files ) );
       
   131 if ( $description != $file_show )
       
   132 	$description .= ' <span>(' . $file_show . ')</span>';
   115 ?>
   133 ?>
   116 <div class="wrap">
   134 <div class="wrap">
   117 <?php screen_icon(); ?>
   135 <?php screen_icon(); ?>
   118 <h2><?php echo esc_html( $title ); ?></h2>
   136 <h2><?php echo esc_html( $title ); ?></h2>
   119 
   137 
   120 <div class="fileedit-sub">
   138 <div class="fileedit-sub">
   121 <div class="alignleft">
   139 <div class="alignleft">
   122 <big><?php echo sprintf($desc_header, $file_show); ?></big>
   140 <h3><?php echo $theme->display('Name'); if ( $description ) echo ': ' . $description; ?></h3>
   123 </div>
   141 </div>
   124 <div class="alignright">
   142 <div class="alignright">
   125 	<form action="theme-editor.php" method="post">
   143 	<form action="theme-editor.php" method="post">
   126 		<strong><label for="theme"><?php _e('Select theme to edit:'); ?> </label></strong>
   144 		<strong><label for="theme"><?php _e('Select theme to edit:'); ?> </label></strong>
   127 		<select name="theme" id="theme">
   145 		<select name="theme" id="theme">
   128 <?php
   146 <?php
   129 	foreach ($themes as $a_theme) {
   147 foreach ( wp_get_themes( array( 'errors' => null ) ) as $a_stylesheet => $a_theme ) {
   130 	$theme_name = $a_theme['Name'];
   148 	if ( $a_theme->errors() && 'theme_no_stylesheet' == $a_theme->errors()->get_error_code() )
   131 	if ($theme_name == $theme) $selected = " selected='selected'";
   149 		continue;
   132 	else $selected = '';
   150 
   133 	$theme_name = esc_attr($theme_name);
   151 	$selected = $a_stylesheet == $stylesheet ? ' selected="selected"' : '';
   134 	echo "\n\t<option value=\"$theme_name\" $selected>$theme_name</option>";
   152 	echo "\n\t" . '<option value="' . esc_attr( $a_stylesheet ) . '"' . $selected . '>' . $a_theme->display('Name') . '</option>';
   135 }
   153 }
   136 ?>
   154 ?>
   137 		</select>
   155 		</select>
   138 		<input type="submit" name="Submit" value="<?php esc_attr_e('Select') ?>" class="button" />
   156 		<?php submit_button( __( 'Select' ), 'button', 'Submit', false ); ?>
   139 	</form>
   157 	</form>
   140 </div>
   158 </div>
   141 <br class="clear" />
   159 <br class="clear" />
   142 </div>
   160 </div>
       
   161 <?php
       
   162 if ( $theme->errors() )
       
   163 	echo '<div class="error"><p><strong>' . __( 'This theme is broken.' ) . '</strong> ' . $theme->errors()->get_error_message() . '</p></div>';
       
   164 ?>
   143 	<div id="templateside">
   165 	<div id="templateside">
   144 	<h3><?php _e("Theme Files"); ?></h3>
   166 <?php
   145 
   167 if ( $allowed_files ) :
   146 <?php
   168 	if ( $has_templates || $theme->parent() ) :
   147 if ($allowed_files) :
   169 ?>
   148 ?>
   170 	<h3><?php _e('Templates'); ?></h3>
   149 	<h4><?php _e('Templates'); ?></h4>
   171 	<?php if ( $theme->parent() ) : ?>
       
   172 	<p class="howto"><?php printf( __( 'This child theme inherits templates from a parent theme, %s.' ), '<a href="' . self_admin_url('theme-editor.php?theme=' . urlencode( $theme->get_template() ) ) . '">' . $theme->parent()->display('Name') . '</a>' ); ?></p>
       
   173 	<?php endif; ?>
   150 	<ul>
   174 	<ul>
   151 <?php
   175 <?php
   152 	$template_mapping = array();
   176 	endif;
   153 	$template_dir = $themes[$theme]['Template Dir'];
   177 
   154 	foreach ( $themes[$theme]['Template Files'] as $template_file ) {
   178 	foreach ( $allowed_files as $filename => $absolute_filename ) :
   155 		$description = trim( get_file_description($template_file) );
   179 		if ( 'style.css' == $filename )
   156 		$template_show = basename($template_file);
   180 			echo "\t</ul>\n\t<h3>" . _x( 'Styles', 'Theme stylesheets in theme editor' ) . "</h3>\n\t<ul>\n";
   157 		$filedesc = ( $description != $template_file ) ? "$description <span class='nonessential'>($template_show)</span>" : "$description";
   181 
   158 		$filedesc = ( $template_file == $file ) ? "<span class='highlight'>$description <span class='nonessential'>($template_show)</span></span>" : $filedesc;
   182 		$file_description = get_file_description( $absolute_filename );
   159 
   183 		if ( $file_description != basename( $filename ) )
   160 		// If we have two files of the same name prefer the one in the Template Directory
   184 			$file_description .= '<br /><span class="nonessential">(' . $filename . ')</span>';
   161 		// This means that we display the correct files for child themes which overload Templates as well as Styles
   185 
   162 		if( array_key_exists($description, $template_mapping ) ) {
   186 		if ( $absolute_filename == $file )
   163 			if ( false !== strpos( $template_file, $template_dir ) )  {
   187 			$file_description = '<span class="highlight">' . $file_description . '</span>';
   164 				$template_mapping[ $description ] = array( _get_template_edit_filename($template_file, $template_dir), $filedesc );
   188 ?>
   165 			}
   189 		<li><a href="theme-editor.php?file=<?php echo urlencode( $filename ) ?>&amp;theme=<?php echo urlencode( $stylesheet ) ?>"><?php echo $file_description; ?></a></li>
   166 		} else {
   190 <?php
   167 			$template_mapping[ $description ] = array( _get_template_edit_filename($template_file, $template_dir), $filedesc );
   191 	endforeach;
   168 		}
   192 ?>
   169 	}
   193 </ul>
   170 	ksort( $template_mapping );
       
   171 	while ( list( $template_sorted_key, list( $template_file, $filedesc ) ) = each( $template_mapping ) ) :
       
   172 	?>
       
   173 		<li><a href="theme-editor.php?file=<?php echo "$template_file"; ?>&amp;theme=<?php echo urlencode($theme) ?>&amp;dir=theme"><?php echo $filedesc ?></a></li>
       
   174 <?php endwhile; ?>
       
   175 	</ul>
       
   176 	<h4><?php /* translators: Theme stylesheets in theme editor */ echo _x('Styles', 'Theme stylesheets in theme editor'); ?></h4>
       
   177 	<ul>
       
   178 <?php
       
   179 	$template_mapping = array();
       
   180 	$stylesheet_dir = $themes[$theme]['Stylesheet Dir'];
       
   181 	foreach ( $themes[$theme]['Stylesheet Files'] as $style_file ) {
       
   182 		$description = trim( get_file_description($style_file) );
       
   183 		$style_show = basename($style_file);
       
   184 		$filedesc = ( $description != $style_file ) ? "$description <span class='nonessential'>($style_show)</span>" : "$description";
       
   185 		$filedesc = ( $style_file == $file ) ? "<span class='highlight'>$description <span class='nonessential'>($style_show)</span></span>" : $filedesc;
       
   186 		$template_mapping[ $description ] = array( _get_template_edit_filename($style_file, $stylesheet_dir), $filedesc );
       
   187 	}
       
   188 	ksort( $template_mapping );
       
   189 	while ( list( $template_sorted_key, list( $style_file, $filedesc ) ) = each( $template_mapping ) ) :
       
   190 		?>
       
   191 		<li><a href="theme-editor.php?file=<?php echo "$style_file"; ?>&amp;theme=<?php echo urlencode($theme) ?>&amp;dir=style"><?php echo $filedesc ?></a></li>
       
   192 <?php endwhile; ?>
       
   193 	</ul>
       
   194 <?php endif; ?>
   194 <?php endif; ?>
   195 </div>
   195 </div>
   196 <?php if (!$error) { ?>
   196 <?php if ( $error ) :
       
   197 	echo '<div class="error"><p>' . __('Oops, no such file exists! Double check the name and try again, merci.') . '</p></div>';
       
   198 else : ?>
   197 	<form name="template" id="template" action="theme-editor.php" method="post">
   199 	<form name="template" id="template" action="theme-editor.php" method="post">
   198 	<?php wp_nonce_field('edit-theme_' . $file . $theme) ?>
   200 	<?php wp_nonce_field( 'edit-theme_' . $file . $stylesheet ); ?>
   199 		 <div><textarea cols="70" rows="25" name="newcontent" id="newcontent" tabindex="1" class="codepress <?php echo $codepress_lang ?>"><?php echo $content ?></textarea>
   201 		 <div><textarea cols="70" rows="30" name="newcontent" id="newcontent" tabindex="1"><?php echo $content ?></textarea>
   200 		 <input type="hidden" name="action" value="update" />
   202 		 <input type="hidden" name="action" value="update" />
   201 		 <input type="hidden" name="file" value="<?php echo esc_attr($file) ?>" />
   203 		 <input type="hidden" name="file" value="<?php echo esc_attr( $relative_file ); ?>" />
   202 		 <input type="hidden" name="theme" value="<?php echo esc_attr($theme) ?>" />
   204 		 <input type="hidden" name="theme" value="<?php echo esc_attr( $theme->get_stylesheet() ); ?>" />
   203 		 <input type="hidden" name="scrollto" id="scrollto" value="<?php echo $scrollto; ?>" />
   205 		 <input type="hidden" name="scrollto" id="scrollto" value="<?php echo $scrollto; ?>" />
   204 		 </div>
   206 		 </div>
   205 	<?php if ( isset($functions ) && count($functions) ) { ?>
   207 	<?php if ( ! empty( $functions ) ) : ?>
   206 		<div id="documentation">
   208 		<div id="documentation" class="hide-if-no-js">
   207 		<label for="docs-list"><?php _e('Documentation:') ?></label>
   209 		<label for="docs-list"><?php _e('Documentation:') ?></label>
   208 		<?php echo $docs_select; ?>
   210 		<?php echo $docs_select; ?>
   209 		<input type="button" class="button" value=" <?php esc_attr_e( 'Lookup' ); ?> " onclick="if ( '' != jQuery('#docs-list').val() ) { window.open( 'http://api.wordpress.org/core/handbook/1.0/?function=' + escape( jQuery( '#docs-list' ).val() ) + '&locale=<?php echo urlencode( get_locale() ) ?>&version=<?php echo urlencode( $wp_version ) ?>&redirect=true'); }" />
   211 		<input type="button" class="button" value=" <?php esc_attr_e( 'Lookup' ); ?> " onclick="if ( '' != jQuery('#docs-list').val() ) { window.open( 'http://api.wordpress.org/core/handbook/1.0/?function=' + escape( jQuery( '#docs-list' ).val() ) + '&amp;locale=<?php echo urlencode( get_locale() ) ?>&amp;version=<?php echo urlencode( $wp_version ) ?>&amp;redirect=true'); }" />
   210 		</div>
   212 		</div>
   211 	<?php } ?>
   213 	<?php endif; ?>
   212 
   214 
   213 		<div>
   215 		<div>
   214 <?php if ( is_writeable($file) ) : ?>
   216 		<?php if ( is_child_theme() && $theme->get_stylesheet() == get_template() ) : ?>
   215 			<p class="submit">
   217 			<p><?php if ( is_writeable( $file ) ) { ?><strong><?php _e( 'Caution:' ); ?></strong><?php } ?>
   216 <?php
   218 			<?php _e( 'This is a file in your current parent theme.' ); ?></p>
   217 	echo "<input type='submit' name='submit' class='button-primary' value='" . esc_attr__('Update File') . "' tabindex='2' />";
   219 		<?php endif; ?>
   218 ?>
   220 <?php
   219 </p>
   221 	if ( is_writeable( $file ) ) :
   220 <?php else : ?>
   222 		submit_button( __( 'Update File' ), 'primary', 'submit', true, array( 'tabindex' => '2' ) );
       
   223 	else : ?>
   221 <p><em><?php _e('You need to make this file writable before you can save your changes. See <a href="http://codex.wordpress.org/Changing_File_Permissions">the Codex</a> for more information.'); ?></em></p>
   224 <p><em><?php _e('You need to make this file writable before you can save your changes. See <a href="http://codex.wordpress.org/Changing_File_Permissions">the Codex</a> for more information.'); ?></em></p>
   222 <?php endif; ?>
   225 <?php endif; ?>
   223 		</div>
   226 		</div>
   224 	</form>
   227 	</form>
   225 <?php
   228 <?php
   226 	} else {
   229 endif; // $error
   227 		echo '<div class="error"><p>' . __('Oops, no such file exists! Double check the name and try again, merci.') . '</p></div>';
       
   228 	}
       
   229 ?>
   230 ?>
   230 <br class="clear" />
   231 <br class="clear" />
   231 </div>
   232 </div>
   232 <script type="text/javascript">
   233 <script type="text/javascript">
   233 /* <![CDATA[ */
   234 /* <![CDATA[ */
   239 </script>
   240 </script>
   240 <?php
   241 <?php
   241 break;
   242 break;
   242 }
   243 }
   243 
   244 
   244 include("admin-footer.php");
   245 include(ABSPATH . 'wp-admin/admin-footer.php' );