[ Index ]

PHP Cross Reference of WordPress Trunk (Updated Daily)

Search

title

Body

[close]

/wp-admin/ -> theme-editor.php (source)

   1  <?php
   2  /**
   3   * Theme file editor administration panel.
   4   *
   5   * @package WordPress
   6   * @subpackage Administration
   7   */
   8  
   9  /** WordPress Administration Bootstrap */
  10  require_once  __DIR__ . '/admin.php';
  11  
  12  if ( is_multisite() && ! is_network_admin() ) {
  13      wp_redirect( network_admin_url( 'theme-editor.php' ) );
  14      exit;
  15  }
  16  
  17  if ( ! current_user_can( 'edit_themes' ) ) {
  18      wp_die( '<p>' . __( 'Sorry, you are not allowed to edit templates for this site.' ) . '</p>' );
  19  }
  20  
  21  // Used in the HTML title tag.
  22  $title       = __( 'Edit Themes' );
  23  $parent_file = 'themes.php';
  24  
  25  get_current_screen()->add_help_tab(
  26      array(
  27          'id'      => 'overview',
  28          'title'   => __( 'Overview' ),
  29          'content' =>
  30                  '<p>' . __( 'You can use the theme file editor to edit the individual CSS and PHP files which make up your theme.' ) . '</p>' .
  31                  '<p>' . __( 'Begin by choosing a theme to edit from the dropdown menu and clicking the Select button. A list then appears of the theme&#8217;s template files. Clicking once on any file name causes the file to appear in the large Editor box.' ) . '</p>' .
  32                  '<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>' .
  33                  '<p id="editor-keyboard-trap-help-1">' . __( 'When using a keyboard to navigate:' ) . '</p>' .
  34                  '<ul>' .
  35                  '<li id="editor-keyboard-trap-help-2">' . __( 'In the editing area, the Tab key enters a tab character.' ) . '</li>' .
  36                  '<li id="editor-keyboard-trap-help-3">' . __( 'To move away from this area, press the Esc key followed by the Tab key.' ) . '</li>' .
  37                  '<li id="editor-keyboard-trap-help-4">' . __( 'Screen reader users: when in forms mode, you may need to press the Esc key twice.' ) . '</li>' .
  38                  '</ul>' .
  39                  '<p>' . __( 'After typing in your edits, click Update File.' ) . '</p>' .
  40                  '<p>' . __( '<strong>Advice:</strong> Think very carefully about your site crashing if you are live-editing the theme currently in use.' ) . '</p>' .
  41                  '<p>' . sprintf(
  42                      /* translators: %s: Link to documentation on child themes. */
  43                      __( '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.' ),
  44                      __( 'https://developer.wordpress.org/themes/advanced-topics/child-themes/' )
  45                  ) . '</p>' .
  46                  ( is_network_admin() ? '<p>' . __( 'Any edits to files from this screen will be reflected on all sites in the network.' ) . '</p>' : '' ),
  47      )
  48  );
  49  
  50  get_current_screen()->set_help_sidebar(
  51      '<p><strong>' . __( 'For more information:' ) . '</strong></p>' .
  52      '<p>' . __( '<a href="https://developer.wordpress.org/themes/">Documentation on Theme Development</a>' ) . '</p>' .
  53      '<p>' . __( '<a href="https://wordpress.org/documentation/article/appearance-theme-file-editor-screen/">Documentation on Editing Themes</a>' ) . '</p>' .
  54      '<p>' . __( '<a href="https://developer.wordpress.org/advanced-administration/wordpress/edit-files/">Documentation on Editing Files</a>' ) . '</p>' .
  55      '<p>' . __( '<a href="https://developer.wordpress.org/themes/basics/template-tags/">Documentation on Template Tags</a>' ) . '</p>' .
  56      '<p>' . __( '<a href="https://wordpress.org/support/forums/">Support forums</a>' ) . '</p>'
  57  );
  58  
  59  $action = ! empty( $_REQUEST['action'] ) ? sanitize_text_field( $_REQUEST['action'] ) : '';
  60  $theme  = ! empty( $_REQUEST['theme'] ) ? sanitize_text_field( $_REQUEST['theme'] ) : '';
  61  $file   = ! empty( $_REQUEST['file'] ) ? sanitize_text_field( $_REQUEST['file'] ) : '';
  62  $error  = ! empty( $_REQUEST['error'] );
  63  
  64  if ( $theme ) {
  65      $stylesheet = $theme;
  66  } else {
  67      $stylesheet = get_stylesheet();
  68  }
  69  
  70  $theme = wp_get_theme( $stylesheet );
  71  
  72  if ( ! $theme->exists() ) {
  73      wp_die( __( 'The requested theme does not exist.' ) );
  74  }
  75  
  76  if ( $theme->errors() && 'theme_no_stylesheet' === $theme->errors()->get_error_code() ) {
  77      wp_die( __( 'The requested theme does not exist.' ) . ' ' . $theme->errors()->get_error_message() );
  78  }
  79  
  80  $allowed_files = array();
  81  $style_files   = array();
  82  
  83  $file_types = wp_get_theme_file_editable_extensions( $theme );
  84  
  85  foreach ( $file_types as $type ) {
  86      switch ( $type ) {
  87          case 'php':
  88              $allowed_files += $theme->get_files( 'php', -1 );
  89              break;
  90          case 'css':
  91              $style_files                = $theme->get_files( 'css', -1 );
  92              $allowed_files['style.css'] = $style_files['style.css'];
  93              $allowed_files             += $style_files;
  94              break;
  95          default:
  96              $allowed_files += $theme->get_files( $type, -1 );
  97              break;
  98      }
  99  }
 100  
 101  // Move functions.php and style.css to the top.
 102  if ( isset( $allowed_files['functions.php'] ) ) {
 103      $allowed_files = array( 'functions.php' => $allowed_files['functions.php'] ) + $allowed_files;
 104  }
 105  if ( isset( $allowed_files['style.css'] ) ) {
 106      $allowed_files = array( 'style.css' => $allowed_files['style.css'] ) + $allowed_files;
 107  }
 108  
 109  if ( empty( $file ) ) {
 110      $relative_file = 'style.css';
 111      $file          = $allowed_files['style.css'];
 112  } else {
 113      $relative_file = wp_unslash( $file );
 114      $file          = $theme->get_stylesheet_directory() . '/' . $relative_file;
 115  }
 116  
 117  validate_file_to_edit( $file, $allowed_files );
 118  
 119  // Handle fallback editing of file when JavaScript is not available.
 120  $edit_error     = null;
 121  $posted_content = null;
 122  
 123  if ( 'POST' === $_SERVER['REQUEST_METHOD'] ) {
 124      $r = wp_edit_theme_plugin_file( wp_unslash( $_POST ) );
 125      if ( is_wp_error( $r ) ) {
 126          $edit_error = $r;
 127          if ( check_ajax_referer( 'edit-theme_' . $stylesheet . '_' . $relative_file, 'nonce', false ) && isset( $_POST['newcontent'] ) ) {
 128              $posted_content = wp_unslash( $_POST['newcontent'] );
 129          }
 130      } else {
 131          wp_redirect(
 132              add_query_arg(
 133                  array(
 134                      'a'     => 1, // This means "success" for some reason.
 135                      'theme' => $stylesheet,
 136                      'file'  => $relative_file,
 137                  ),
 138                  admin_url( 'theme-editor.php' )
 139              )
 140          );
 141          exit;
 142      }
 143  }
 144  
 145  $settings = array(
 146      'codeEditor' => wp_enqueue_code_editor( compact( 'file' ) ),
 147  );
 148  wp_enqueue_script( 'wp-theme-plugin-editor' );
 149  wp_add_inline_script( 'wp-theme-plugin-editor', sprintf( 'jQuery( function( $ ) { wp.themePluginEditor.init( $( "#template" ), %s ); } )', wp_json_encode( $settings ) ) );
 150  wp_add_inline_script( 'wp-theme-plugin-editor', 'wp.themePluginEditor.themeOrPlugin = "theme";' );
 151  
 152  require_once  ABSPATH . 'wp-admin/admin-header.php';
 153  
 154  update_recently_edited( $file );
 155  
 156  if ( ! is_file( $file ) ) {
 157      $error = true;
 158  }
 159  
 160  $content = '';
 161  if ( ! empty( $posted_content ) ) {
 162      $content = $posted_content;
 163  } elseif ( ! $error && filesize( $file ) > 0 ) {
 164      $f       = fopen( $file, 'r' );
 165      $content = fread( $f, filesize( $file ) );
 166  
 167      if ( str_ends_with( $file, '.php' ) ) {
 168          $functions = wp_doc_link_parse( $content );
 169  
 170          if ( ! empty( $functions ) ) {
 171              $docs_select  = '<select name="docs-list" id="docs-list">';
 172              $docs_select .= '<option value="">' . esc_html__( 'Function Name&hellip;' ) . '</option>';
 173  
 174              foreach ( $functions as $function ) {
 175                  $docs_select .= '<option value="' . esc_attr( $function ) . '">' . esc_html( $function ) . '()</option>';
 176              }
 177  
 178              $docs_select .= '</select>';
 179          }
 180      }
 181  
 182      $content = esc_textarea( $content );
 183  }
 184  
 185  $file_description = get_file_description( $relative_file );
 186  $file_show        = array_search( $file, array_filter( $allowed_files ), true );
 187  $description      = esc_html( $file_description );
 188  if ( $file_description !== $file_show ) {
 189      $description .= ' <span>(' . esc_html( $file_show ) . ')</span>';
 190  }
 191  ?>
 192  <div class="wrap">
 193  <h1><?php echo esc_html( $title ); ?></h1>
 194  
 195  <?php
 196  if ( isset( $_GET['a'] ) ) {
 197      wp_admin_notice(
 198          __( 'File edited successfully.' ),
 199          array(
 200              'id'                 => 'message',
 201              'dismissible'        => true,
 202              'additional_classes' => array( 'updated' ),
 203          )
 204      );
 205  } elseif ( is_wp_error( $edit_error ) ) {
 206      $error_code = esc_html( $edit_error->get_error_message() ? $edit_error->get_error_message() : $edit_error->get_error_code() );
 207      $message    = '<p>' . __( 'There was an error while trying to update the file. You may need to fix something and try updating again.' ) . '</p>
 208      <pre>' . $error_code . '</pre>';
 209      wp_admin_notice(
 210          $message,
 211          array(
 212              'type' => 'error',
 213              'id'   => 'message',
 214          )
 215      );
 216  }
 217  
 218  if ( preg_match( '/\.css$/', $file ) && ! wp_is_block_theme() && current_user_can( 'customize' ) ) {
 219      $message = '<p><strong>' . __( 'Did you know?' ) . '</strong></p><p>' . sprintf(
 220          /* translators: %s: Link to Custom CSS section in the Customizer. */
 221          __( 'There is no need to change your CSS here &mdash; you can edit and live preview CSS changes in the <a href="%s">built-in CSS editor</a>.' ),
 222          esc_url( add_query_arg( 'autofocus[section]', 'custom_css', admin_url( 'customize.php' ) ) )
 223      ) . '</p>';
 224      wp_admin_notice(
 225          $message,
 226          array(
 227              'type' => 'info',
 228              'id'   => 'message',
 229          )
 230      );
 231  }
 232  ?>
 233  
 234  <div class="fileedit-sub">
 235  <div class="alignleft">
 236  <h2>
 237      <?php
 238      echo $theme->display( 'Name' );
 239      if ( $description ) {
 240          echo ': ' . $description;
 241      }
 242      ?>
 243  </h2>
 244  </div>
 245  <div class="alignright">
 246      <form action="theme-editor.php" method="get">
 247          <label for="theme" id="theme-plugin-editor-selector"><?php _e( 'Select theme to edit:' ); ?> </label>
 248          <select name="theme" id="theme">
 249          <?php
 250          foreach ( wp_get_themes( array( 'errors' => null ) ) as $a_stylesheet => $a_theme ) {
 251              if ( $a_theme->errors() && 'theme_no_stylesheet' === $a_theme->errors()->get_error_code() ) {
 252                  continue;
 253              }
 254  
 255              $selected = ( $a_stylesheet === $stylesheet ) ? ' selected="selected"' : '';
 256              echo "\n\t" . '<option value="' . esc_attr( $a_stylesheet ) . '"' . $selected . '>' . $a_theme->display( 'Name' ) . '</option>';
 257          }
 258          ?>
 259          </select>
 260          <?php submit_button( __( 'Select' ), '', 'Submit', false ); ?>
 261      </form>
 262  </div>
 263  <br class="clear" />
 264  </div>
 265  
 266  <?php
 267  if ( $theme->errors() ) {
 268      wp_admin_notice(
 269          '<strong>' . __( 'This theme is broken.' ) . '</strong> ' . $theme->errors()->get_error_message(),
 270          array(
 271              'additional_classes' => array( 'error' ),
 272          )
 273      );
 274  }
 275  ?>
 276  
 277  <div id="templateside">
 278      <h2 id="theme-files-label"><?php _e( 'Theme Files' ); ?></h2>
 279      <ul role="tree" aria-labelledby="theme-files-label">
 280          <?php if ( $theme->parent() ) : ?>
 281              <li class="howto">
 282                  <?php
 283                  printf(
 284                      /* translators: %s: Link to edit parent theme. */
 285                      __( 'This child theme inherits templates from a parent theme, %s.' ),
 286                      sprintf(
 287                          '<a href="%s">%s</a>',
 288                          self_admin_url( 'theme-editor.php?theme=' . urlencode( $theme->get_template() ) ),
 289                          $theme->parent()->display( 'Name' )
 290                      )
 291                  );
 292                  ?>
 293              </li>
 294          <?php endif; ?>
 295          <li role="treeitem" tabindex="-1" aria-expanded="true" aria-level="1" aria-posinset="1" aria-setsize="1">
 296              <ul role="group">
 297                  <?php wp_print_theme_file_tree( wp_make_theme_file_tree( $allowed_files ) ); ?>
 298              </ul>
 299          </li>
 300      </ul>
 301  </div>
 302  
 303  <?php
 304  if ( $error ) :
 305      wp_admin_notice(
 306          __( 'File does not exist! Please double check the name and try again.' ),
 307          array(
 308              'additional_classes' => array( 'error' ),
 309          )
 310      );
 311  else :
 312      ?>
 313      <form name="template" id="template" action="theme-editor.php" method="post">
 314          <?php wp_nonce_field( 'edit-theme_' . $stylesheet . '_' . $relative_file, 'nonce' ); ?>
 315          <div>
 316              <label for="newcontent" id="theme-plugin-editor-label"><?php _e( 'Selected file content:' ); ?></label>
 317              <textarea cols="70" rows="30" name="newcontent" id="newcontent" aria-describedby="editor-keyboard-trap-help-1 editor-keyboard-trap-help-2 editor-keyboard-trap-help-3 editor-keyboard-trap-help-4"><?php echo $content; ?></textarea>
 318              <input type="hidden" name="action" value="update" />
 319              <input type="hidden" name="file" value="<?php echo esc_attr( $relative_file ); ?>" />
 320              <input type="hidden" name="theme" value="<?php echo esc_attr( $theme->get_stylesheet() ); ?>" />
 321          </div>
 322  
 323          <?php if ( ! empty( $functions ) ) : ?>
 324              <div id="documentation" class="hide-if-no-js">
 325                  <label for="docs-list"><?php _e( 'Documentation:' ); ?></label>
 326                  <?php echo $docs_select; ?>
 327                  <input disabled id="docs-lookup" 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() ) + '&amp;locale=<?php echo urlencode( get_user_locale() ); ?>&amp;version=<?php echo urlencode( get_bloginfo( 'version' ) ); ?>&amp;redirect=true'); }" />
 328              </div>
 329          <?php endif; ?>
 330  
 331          <div>
 332              <div class="editor-notices">
 333                  <?php
 334                  if ( is_child_theme() && $theme->get_stylesheet() === get_template() ) :
 335                      $message  = ( is_writable( $file ) ) ? '<strong>' . __( 'Caution:' ) . '</strong> ' : '';
 336                      $message .= __( 'This is a file in your current parent theme.' );
 337                      wp_admin_notice(
 338                          $message,
 339                          array(
 340                              'type'               => 'warning',
 341                              'additional_classes' => array( 'inline' ),
 342                          )
 343                      );
 344                  endif;
 345                  ?>
 346              </div>
 347              <?php
 348              if ( is_writable( $file ) ) {
 349                  ?>
 350                  <p class="submit">
 351                      <?php submit_button( __( 'Update File' ), 'primary', 'submit', false ); ?>
 352                      <span class="spinner"></span>
 353                  </p>
 354                  <?php
 355              } else {
 356                  ?>
 357                  <p>
 358                      <?php
 359                      printf(
 360                          /* translators: %s: Documentation URL. */
 361                          __( 'You need to make this file writable before you can save your changes. See <a href="%s">Changing File Permissions</a> for more information.' ),
 362                          __( 'https://developer.wordpress.org/advanced-administration/server/file-permissions/' )
 363                      );
 364                      ?>
 365                  </p>
 366                  <?php
 367              }
 368              ?>
 369          </div>
 370  
 371          <?php wp_print_file_editor_templates(); ?>
 372      </form>
 373      <?php
 374  endif; // End if $error.
 375  ?>
 376  <br class="clear" />
 377  </div>
 378  <?php
 379  $dismissed_pointers = explode( ',', (string) get_user_meta( get_current_user_id(), 'dismissed_wp_pointers', true ) );
 380  if ( ! in_array( 'theme_editor_notice', $dismissed_pointers, true ) ) {
 381      // Get a back URL.
 382      $referer = wp_get_referer();
 383  
 384      $excluded_referer_basenames = array( 'theme-editor.php', 'wp-login.php' );
 385  
 386      $return_url = admin_url( '/' );
 387      if ( $referer ) {
 388          $referer_path = parse_url( $referer, PHP_URL_PATH );
 389          if ( is_string( $referer_path ) && ! in_array( basename( $referer_path ), $excluded_referer_basenames, true ) ) {
 390              $return_url = $referer;
 391          }
 392      }
 393      ?>
 394      <div id="file-editor-warning" class="notification-dialog-wrap file-editor-warning hide-if-no-js hidden">
 395          <div class="notification-dialog-background"></div>
 396          <div class="notification-dialog">
 397              <div class="file-editor-warning-content">
 398                  <div class="file-editor-warning-message">
 399                      <h1><?php _e( 'Heads up!' ); ?></h1>
 400                      <p>
 401                          <?php
 402                          _e( 'You appear to be making direct edits to your theme in the WordPress dashboard. It is not recommended! Editing your theme directly could break your site and your changes may be lost in future updates.' );
 403                          ?>
 404                      </p>
 405                          <?php
 406                          if ( ! $theme->parent() ) {
 407                              echo '<p>';
 408                              printf(
 409                                  /* translators: %s: Link to documentation on child themes. */
 410                                  __( 'If you need to tweak more than your theme&#8217;s CSS, you might want to try <a href="%s">making a child theme</a>.' ),
 411                                  esc_url( __( 'https://developer.wordpress.org/themes/advanced-topics/child-themes/' ) )
 412                              );
 413                              echo '</p>';
 414                          }
 415                          ?>
 416                      <p><?php _e( 'If you decide to go ahead with direct edits anyway, use a file manager to create a copy with a new name and hang on to the original. That way, you can re-enable a functional version if something goes wrong.' ); ?></p>
 417                  </div>
 418                  <p>
 419                      <a class="button file-editor-warning-go-back" href="<?php echo esc_url( $return_url ); ?>"><?php _e( 'Go back' ); ?></a>
 420                      <button type="button" class="file-editor-warning-dismiss button button-primary"><?php _e( 'I understand' ); ?></button>
 421                  </p>
 422              </div>
 423          </div>
 424      </div>
 425      <?php
 426  } // Editor warning notice.
 427  
 428  require_once  ABSPATH . 'wp-admin/admin-footer.php';


Generated : Sun Oct 13 08:20:01 2024 Cross-referenced by PHPXref