[ Index ]

PHP Cross Reference of WordPress

title

Body

[close]

/wp-admin/includes/ -> misc.php (source)

   1  <?php
   2  /**
   3   * Misc WordPress Administration API.
   4   *
   5   * @package WordPress
   6   * @subpackage Administration
   7   */
   8  
   9  /**
  10   * Returns whether the server is running Apache with the mod_rewrite module loaded.
  11   *
  12   * @since 2.0.0
  13   *
  14   * @return bool Whether the server is running Apache with the mod_rewrite module loaded.
  15   */
  16  function got_mod_rewrite() {
  17      $got_rewrite = apache_mod_loaded( 'mod_rewrite', true );
  18  
  19      /**
  20       * Filters whether Apache and mod_rewrite are present.
  21       *
  22       * This filter was previously used to force URL rewriting for other servers,
  23       * like nginx. Use the {@see 'got_url_rewrite'} filter in got_url_rewrite() instead.
  24       *
  25       * @since 2.5.0
  26       *
  27       * @see got_url_rewrite()
  28       *
  29       * @param bool $got_rewrite Whether Apache and mod_rewrite are present.
  30       */
  31      return apply_filters( 'got_rewrite', $got_rewrite );
  32  }
  33  
  34  /**
  35   * Returns whether the server supports URL rewriting.
  36   *
  37   * Detects Apache's mod_rewrite, IIS 7.0+ permalink support, and nginx.
  38   *
  39   * @since 3.7.0
  40   *
  41   * @global bool $is_nginx
  42   *
  43   * @return bool Whether the server supports URL rewriting.
  44   */
  45  function got_url_rewrite() {
  46      $got_url_rewrite = ( got_mod_rewrite() || $GLOBALS['is_nginx'] || iis7_supports_permalinks() );
  47  
  48      /**
  49       * Filters whether URL rewriting is available.
  50       *
  51       * @since 3.7.0
  52       *
  53       * @param bool $got_url_rewrite Whether URL rewriting is available.
  54       */
  55      return apply_filters( 'got_url_rewrite', $got_url_rewrite );
  56  }
  57  
  58  /**
  59   * Extracts strings from between the BEGIN and END markers in the .htaccess file.
  60   *
  61   * @since 1.5.0
  62   *
  63   * @param string $filename Filename to extract the strings from.
  64   * @param string $marker   The marker to extract the strings from.
  65   * @return string[] An array of strings from a file (.htaccess) from between BEGIN and END markers.
  66   */
  67  function extract_from_markers( $filename, $marker ) {
  68      $result = array();
  69  
  70      if ( ! file_exists( $filename ) ) {
  71          return $result;
  72      }
  73  
  74      $markerdata = explode( "\n", implode( '', file( $filename ) ) );
  75  
  76      $state = false;
  77      foreach ( $markerdata as $markerline ) {
  78          if ( false !== strpos( $markerline, '# END ' . $marker ) ) {
  79              $state = false;
  80          }
  81          if ( $state ) {
  82              if ( '#' === substr( $markerline, 0, 1 ) ) {
  83                  continue;
  84              }
  85              $result[] = $markerline;
  86          }
  87          if ( false !== strpos( $markerline, '# BEGIN ' . $marker ) ) {
  88              $state = true;
  89          }
  90      }
  91  
  92      return $result;
  93  }
  94  
  95  /**
  96   * Inserts an array of strings into a file (.htaccess), placing it between
  97   * BEGIN and END markers.
  98   *
  99   * Replaces existing marked info. Retains surrounding
 100   * data. Creates file if none exists.
 101   *
 102   * @since 1.5.0
 103   *
 104   * @param string       $filename  Filename to alter.
 105   * @param string       $marker    The marker to alter.
 106   * @param array|string $insertion The new content to insert.
 107   * @return bool True on write success, false on failure.
 108   */
 109  function insert_with_markers( $filename, $marker, $insertion ) {
 110      if ( ! file_exists( $filename ) ) {
 111          if ( ! is_writable( dirname( $filename ) ) ) {
 112              return false;
 113          }
 114  
 115          if ( ! touch( $filename ) ) {
 116              return false;
 117          }
 118  
 119          // Make sure the file is created with a minimum set of permissions.
 120          $perms = fileperms( $filename );
 121          if ( $perms ) {
 122              chmod( $filename, $perms | 0644 );
 123          }
 124      } elseif ( ! is_writable( $filename ) ) {
 125          return false;
 126      }
 127  
 128      if ( ! is_array( $insertion ) ) {
 129          $insertion = explode( "\n", $insertion );
 130      }
 131  
 132      $switched_locale = switch_to_locale( get_locale() );
 133  
 134      $instructions = sprintf(
 135          /* translators: 1: Marker. */
 136          __(
 137              'The directives (lines) between "BEGIN %1$s" and "END %1$s" are
 138  dynamically generated, and should only be modified via WordPress filters.
 139  Any changes to the directives between these markers will be overwritten.'
 140          ),
 141          $marker
 142      );
 143  
 144      $instructions = explode( "\n", $instructions );
 145      foreach ( $instructions as $line => $text ) {
 146          $instructions[ $line ] = '# ' . $text;
 147      }
 148  
 149      /**
 150       * Filters the inline instructions inserted before the dynamically generated content.
 151       *
 152       * @since 5.3.0
 153       *
 154       * @param string[] $instructions Array of lines with inline instructions.
 155       * @param string   $marker       The marker being inserted.
 156       */
 157      $instructions = apply_filters( 'insert_with_markers_inline_instructions', $instructions, $marker );
 158  
 159      if ( $switched_locale ) {
 160          restore_previous_locale();
 161      }
 162  
 163      $insertion = array_merge( $instructions, $insertion );
 164  
 165      $start_marker = "# BEGIN {$marker}";
 166      $end_marker   = "# END {$marker}";
 167  
 168      $fp = fopen( $filename, 'r+' );
 169      if ( ! $fp ) {
 170          return false;
 171      }
 172  
 173      // Attempt to get a lock. If the filesystem supports locking, this will block until the lock is acquired.
 174      flock( $fp, LOCK_EX );
 175  
 176      $lines = array();
 177      while ( ! feof( $fp ) ) {
 178          $lines[] = rtrim( fgets( $fp ), "\r\n" );
 179      }
 180  
 181      // Split out the existing file into the preceding lines, and those that appear after the marker.
 182      $pre_lines        = array();
 183      $post_lines       = array();
 184      $existing_lines   = array();
 185      $found_marker     = false;
 186      $found_end_marker = false;
 187      foreach ( $lines as $line ) {
 188          if ( ! $found_marker && false !== strpos( $line, $start_marker ) ) {
 189              $found_marker = true;
 190              continue;
 191          } elseif ( ! $found_end_marker && false !== strpos( $line, $end_marker ) ) {
 192              $found_end_marker = true;
 193              continue;
 194          }
 195          if ( ! $found_marker ) {
 196              $pre_lines[] = $line;
 197          } elseif ( $found_marker && $found_end_marker ) {
 198              $post_lines[] = $line;
 199          } else {
 200              $existing_lines[] = $line;
 201          }
 202      }
 203  
 204      // Check to see if there was a change.
 205      if ( $existing_lines === $insertion ) {
 206          flock( $fp, LOCK_UN );
 207          fclose( $fp );
 208  
 209          return true;
 210      }
 211  
 212      // Generate the new file data.
 213      $new_file_data = implode(
 214          "\n",
 215          array_merge(
 216              $pre_lines,
 217              array( $start_marker ),
 218              $insertion,
 219              array( $end_marker ),
 220              $post_lines
 221          )
 222      );
 223  
 224      // Write to the start of the file, and truncate it to that length.
 225      fseek( $fp, 0 );
 226      $bytes = fwrite( $fp, $new_file_data );
 227      if ( $bytes ) {
 228          ftruncate( $fp, ftell( $fp ) );
 229      }
 230      fflush( $fp );
 231      flock( $fp, LOCK_UN );
 232      fclose( $fp );
 233  
 234      return (bool) $bytes;
 235  }
 236  
 237  /**
 238   * Updates the htaccess file with the current rules if it is writable.
 239   *
 240   * Always writes to the file if it exists and is writable to ensure that we
 241   * blank out old rules.
 242   *
 243   * @since 1.5.0
 244   *
 245   * @global WP_Rewrite $wp_rewrite WordPress rewrite component.
 246   *
 247   * @return bool|null True on write success, false on failure. Null in multisite.
 248   */
 249  function save_mod_rewrite_rules() {
 250      if ( is_multisite() ) {
 251          return;
 252      }
 253  
 254      global $wp_rewrite;
 255  
 256      // Ensure get_home_path() is declared.
 257      require_once ABSPATH . 'wp-admin/includes/file.php';
 258  
 259      $home_path     = get_home_path();
 260      $htaccess_file = $home_path . '.htaccess';
 261  
 262      /*
 263       * If the file doesn't already exist check for write access to the directory
 264       * and whether we have some rules. Else check for write access to the file.
 265       */
 266      if ( ( ! file_exists( $htaccess_file ) && is_writable( $home_path ) && $wp_rewrite->using_mod_rewrite_permalinks() ) || is_writable( $htaccess_file ) ) {
 267          if ( got_mod_rewrite() ) {
 268              $rules = explode( "\n", $wp_rewrite->mod_rewrite_rules() );
 269              return insert_with_markers( $htaccess_file, 'WordPress', $rules );
 270          }
 271      }
 272  
 273      return false;
 274  }
 275  
 276  /**
 277   * Updates the IIS web.config file with the current rules if it is writable.
 278   * If the permalinks do not require rewrite rules then the rules are deleted from the web.config file.
 279   *
 280   * @since 2.8.0
 281   *
 282   * @global WP_Rewrite $wp_rewrite WordPress rewrite component.
 283   *
 284   * @return bool|null True on write success, false on failure. Null in multisite.
 285   */
 286  function iis7_save_url_rewrite_rules() {
 287      if ( is_multisite() ) {
 288          return;
 289      }
 290  
 291      global $wp_rewrite;
 292  
 293      // Ensure get_home_path() is declared.
 294      require_once ABSPATH . 'wp-admin/includes/file.php';
 295  
 296      $home_path       = get_home_path();
 297      $web_config_file = $home_path . 'web.config';
 298  
 299      // Using win_is_writable() instead of is_writable() because of a bug in Windows PHP.
 300      if ( iis7_supports_permalinks() && ( ( ! file_exists( $web_config_file ) && win_is_writable( $home_path ) && $wp_rewrite->using_mod_rewrite_permalinks() ) || win_is_writable( $web_config_file ) ) ) {
 301          $rule = $wp_rewrite->iis7_url_rewrite_rules( false );
 302          if ( ! empty( $rule ) ) {
 303              return iis7_add_rewrite_rule( $web_config_file, $rule );
 304          } else {
 305              return iis7_delete_rewrite_rule( $web_config_file );
 306          }
 307      }
 308      return false;
 309  }
 310  
 311  /**
 312   * Update the "recently-edited" file for the plugin or theme editor.
 313   *
 314   * @since 1.5.0
 315   *
 316   * @param string $file
 317   */
 318  function update_recently_edited( $file ) {
 319      $oldfiles = (array) get_option( 'recently_edited' );
 320      if ( $oldfiles ) {
 321          $oldfiles   = array_reverse( $oldfiles );
 322          $oldfiles[] = $file;
 323          $oldfiles   = array_reverse( $oldfiles );
 324          $oldfiles   = array_unique( $oldfiles );
 325          if ( 5 < count( $oldfiles ) ) {
 326              array_pop( $oldfiles );
 327          }
 328      } else {
 329          $oldfiles[] = $file;
 330      }
 331      update_option( 'recently_edited', $oldfiles );
 332  }
 333  
 334  /**
 335   * Makes a tree structure for the theme editor's file list.
 336   *
 337   * @since 4.9.0
 338   * @access private
 339   *
 340   * @param array $allowed_files List of theme file paths.
 341   * @return array Tree structure for listing theme files.
 342   */
 343  function wp_make_theme_file_tree( $allowed_files ) {
 344      $tree_list = array();
 345      foreach ( $allowed_files as $file_name => $absolute_filename ) {
 346          $list     = explode( '/', $file_name );
 347          $last_dir = &$tree_list;
 348          foreach ( $list as $dir ) {
 349              $last_dir =& $last_dir[ $dir ];
 350          }
 351          $last_dir = $file_name;
 352      }
 353      return $tree_list;
 354  }
 355  
 356  /**
 357   * Outputs the formatted file list for the theme editor.
 358   *
 359   * @since 4.9.0
 360   * @access private
 361   *
 362   * @global string $relative_file Name of the file being edited relative to the
 363   *                               theme directory.
 364   * @global string $stylesheet    The stylesheet name of the theme being edited.
 365   *
 366   * @param array|string $tree  List of file/folder paths, or filename.
 367   * @param int          $level The aria-level for the current iteration.
 368   * @param int          $size  The aria-setsize for the current iteration.
 369   * @param int          $index The aria-posinset for the current iteration.
 370   */
 371  function wp_print_theme_file_tree( $tree, $level = 2, $size = 1, $index = 1 ) {
 372      global $relative_file, $stylesheet;
 373  
 374      if ( is_array( $tree ) ) {
 375          $index = 0;
 376          $size  = count( $tree );
 377          foreach ( $tree as $label => $theme_file ) :
 378              $index++;
 379              if ( ! is_array( $theme_file ) ) {
 380                  wp_print_theme_file_tree( $theme_file, $level, $index, $size );
 381                  continue;
 382              }
 383              ?>
 384              <li role="treeitem" aria-expanded="true" tabindex="-1"
 385                  aria-level="<?php echo esc_attr( $level ); ?>"
 386                  aria-setsize="<?php echo esc_attr( $size ); ?>"
 387                  aria-posinset="<?php echo esc_attr( $index ); ?>">
 388                  <span class="folder-label"><?php echo esc_html( $label ); ?> <span class="screen-reader-text"><?php _e( 'folder' ); ?></span><span aria-hidden="true" class="icon"></span></span>
 389                  <ul role="group" class="tree-folder"><?php wp_print_theme_file_tree( $theme_file, $level + 1, $index, $size ); ?></ul>
 390              </li>
 391              <?php
 392          endforeach;
 393      } else {
 394          $filename = $tree;
 395          $url      = add_query_arg(
 396              array(
 397                  'file'  => rawurlencode( $tree ),
 398                  'theme' => rawurlencode( $stylesheet ),
 399              ),
 400              self_admin_url( 'theme-editor.php' )
 401          );
 402          ?>
 403          <li role="none" class="<?php echo esc_attr( $relative_file === $filename ? 'current-file' : '' ); ?>">
 404              <a role="treeitem" tabindex="<?php echo esc_attr( $relative_file === $filename ? '0' : '-1' ); ?>"
 405                  href="<?php echo esc_url( $url ); ?>"
 406                  aria-level="<?php echo esc_attr( $level ); ?>"
 407                  aria-setsize="<?php echo esc_attr( $size ); ?>"
 408                  aria-posinset="<?php echo esc_attr( $index ); ?>">
 409                  <?php
 410                  $file_description = esc_html( get_file_description( $filename ) );
 411                  if ( $file_description !== $filename && wp_basename( $filename ) !== $file_description ) {
 412                      $file_description .= '<br /><span class="nonessential">(' . esc_html( $filename ) . ')</span>';
 413                  }
 414  
 415                  if ( $relative_file === $filename ) {
 416                      echo '<span class="notice notice-info">' . $file_description . '</span>';
 417                  } else {
 418                      echo $file_description;
 419                  }
 420                  ?>
 421              </a>
 422          </li>
 423          <?php
 424      }
 425  }
 426  
 427  /**
 428   * Makes a tree structure for the plugin editor's file list.
 429   *
 430   * @since 4.9.0
 431   * @access private
 432   *
 433   * @param array $plugin_editable_files List of plugin file paths.
 434   * @return array Tree structure for listing plugin files.
 435   */
 436  function wp_make_plugin_file_tree( $plugin_editable_files ) {
 437      $tree_list = array();
 438      foreach ( $plugin_editable_files as $plugin_file ) {
 439          $list     = explode( '/', preg_replace( '#^.+?/#', '', $plugin_file ) );
 440          $last_dir = &$tree_list;
 441          foreach ( $list as $dir ) {
 442              $last_dir =& $last_dir[ $dir ];
 443          }
 444          $last_dir = $plugin_file;
 445      }
 446      return $tree_list;
 447  }
 448  
 449  /**
 450   * Outputs the formatted file list for the plugin editor.
 451   *
 452   * @since 4.9.0
 453   * @access private
 454   *
 455   * @param array|string $tree  List of file/folder paths, or filename.
 456   * @param string       $label Name of file or folder to print.
 457   * @param int          $level The aria-level for the current iteration.
 458   * @param int          $size  The aria-setsize for the current iteration.
 459   * @param int          $index The aria-posinset for the current iteration.
 460   */
 461  function wp_print_plugin_file_tree( $tree, $label = '', $level = 2, $size = 1, $index = 1 ) {
 462      global $file, $plugin;
 463      if ( is_array( $tree ) ) {
 464          $index = 0;
 465          $size  = count( $tree );
 466          foreach ( $tree as $label => $plugin_file ) :
 467              $index++;
 468              if ( ! is_array( $plugin_file ) ) {
 469                  wp_print_plugin_file_tree( $plugin_file, $label, $level, $index, $size );
 470                  continue;
 471              }
 472              ?>
 473              <li role="treeitem" aria-expanded="true" tabindex="-1"
 474                  aria-level="<?php echo esc_attr( $level ); ?>"
 475                  aria-setsize="<?php echo esc_attr( $size ); ?>"
 476                  aria-posinset="<?php echo esc_attr( $index ); ?>">
 477                  <span class="folder-label"><?php echo esc_html( $label ); ?> <span class="screen-reader-text"><?php _e( 'folder' ); ?></span><span aria-hidden="true" class="icon"></span></span>
 478                  <ul role="group" class="tree-folder"><?php wp_print_plugin_file_tree( $plugin_file, '', $level + 1, $index, $size ); ?></ul>
 479              </li>
 480              <?php
 481          endforeach;
 482      } else {
 483          $url = add_query_arg(
 484              array(
 485                  'file'   => rawurlencode( $tree ),
 486                  'plugin' => rawurlencode( $plugin ),
 487              ),
 488              self_admin_url( 'plugin-editor.php' )
 489          );
 490          ?>
 491          <li role="none" class="<?php echo esc_attr( $file === $tree ? 'current-file' : '' ); ?>">
 492              <a role="treeitem" tabindex="<?php echo esc_attr( $file === $tree ? '0' : '-1' ); ?>"
 493                  href="<?php echo esc_url( $url ); ?>"
 494                  aria-level="<?php echo esc_attr( $level ); ?>"
 495                  aria-setsize="<?php echo esc_attr( $size ); ?>"
 496                  aria-posinset="<?php echo esc_attr( $index ); ?>">
 497                  <?php
 498                  if ( $file === $tree ) {
 499                      echo '<span class="notice notice-info">' . esc_html( $label ) . '</span>';
 500                  } else {
 501                      echo esc_html( $label );
 502                  }
 503                  ?>
 504              </a>
 505          </li>
 506          <?php
 507      }
 508  }
 509  
 510  /**
 511   * Flushes rewrite rules if siteurl, home or page_on_front changed.
 512   *
 513   * @since 2.1.0
 514   *
 515   * @param string $old_value
 516   * @param string $value
 517   */
 518  function update_home_siteurl( $old_value, $value ) {
 519      if ( wp_installing() ) {
 520          return;
 521      }
 522  
 523      if ( is_multisite() && ms_is_switched() ) {
 524          delete_option( 'rewrite_rules' );
 525      } else {
 526          flush_rewrite_rules();
 527      }
 528  }
 529  
 530  
 531  /**
 532   * Resets global variables based on $_GET and $_POST
 533   *
 534   * This function resets global variables based on the names passed
 535   * in the $vars array to the value of $_POST[$var] or $_GET[$var] or ''
 536   * if neither is defined.
 537   *
 538   * @since 2.0.0
 539   *
 540   * @param array $vars An array of globals to reset.
 541   */
 542  function wp_reset_vars( $vars ) {
 543      foreach ( $vars as $var ) {
 544          if ( empty( $_POST[ $var ] ) ) {
 545              if ( empty( $_GET[ $var ] ) ) {
 546                  $GLOBALS[ $var ] = '';
 547              } else {
 548                  $GLOBALS[ $var ] = $_GET[ $var ];
 549              }
 550          } else {
 551              $GLOBALS[ $var ] = $_POST[ $var ];
 552          }
 553      }
 554  }
 555  
 556  /**
 557   * Displays the given administration message.
 558   *
 559   * @since 2.1.0
 560   *
 561   * @param string|WP_Error $message
 562   */
 563  function show_message( $message ) {
 564      if ( is_wp_error( $message ) ) {
 565          if ( $message->get_error_data() && is_string( $message->get_error_data() ) ) {
 566              $message = $message->get_error_message() . ': ' . $message->get_error_data();
 567          } else {
 568              $message = $message->get_error_message();
 569          }
 570      }
 571      echo "<p>$message</p>\n";
 572      wp_ob_end_flush_all();
 573      flush();
 574  }
 575  
 576  /**
 577   * @since 2.8.0
 578   *
 579   * @param string $content
 580   * @return array
 581   */
 582  function wp_doc_link_parse( $content ) {
 583      if ( ! is_string( $content ) || empty( $content ) ) {
 584          return array();
 585      }
 586  
 587      if ( ! function_exists( 'token_get_all' ) ) {
 588          return array();
 589      }
 590  
 591      $tokens           = token_get_all( $content );
 592      $count            = count( $tokens );
 593      $functions        = array();
 594      $ignore_functions = array();
 595      for ( $t = 0; $t < $count - 2; $t++ ) {
 596          if ( ! is_array( $tokens[ $t ] ) ) {
 597              continue;
 598          }
 599  
 600          if ( T_STRING == $tokens[ $t ][0] && ( '(' === $tokens[ $t + 1 ] || '(' === $tokens[ $t + 2 ] ) ) {
 601              // If it's a function or class defined locally, there's not going to be any docs available.
 602              if ( ( isset( $tokens[ $t - 2 ][1] ) && in_array( $tokens[ $t - 2 ][1], array( 'function', 'class' ), true ) )
 603                  || ( isset( $tokens[ $t - 2 ][0] ) && T_OBJECT_OPERATOR == $tokens[ $t - 1 ][0] )
 604              ) {
 605                  $ignore_functions[] = $tokens[ $t ][1];
 606              }
 607              // Add this to our stack of unique references.
 608              $functions[] = $tokens[ $t ][1];
 609          }
 610      }
 611  
 612      $functions = array_unique( $functions );
 613      sort( $functions );
 614  
 615      /**
 616       * Filters the list of functions and classes to be ignored from the documentation lookup.
 617       *
 618       * @since 2.8.0
 619       *
 620       * @param string[] $ignore_functions Array of names of functions and classes to be ignored.
 621       */
 622      $ignore_functions = apply_filters( 'documentation_ignore_functions', $ignore_functions );
 623  
 624      $ignore_functions = array_unique( $ignore_functions );
 625  
 626      $out = array();
 627      foreach ( $functions as $function ) {
 628          if ( in_array( $function, $ignore_functions, true ) ) {
 629              continue;
 630          }
 631          $out[] = $function;
 632      }
 633  
 634      return $out;
 635  }
 636  
 637  /**
 638   * Saves option for number of rows when listing posts, pages, comments, etc.
 639   *
 640   * @since 2.8.0
 641   */
 642  function set_screen_options() {
 643  
 644      if ( isset( $_POST['wp_screen_options'] ) && is_array( $_POST['wp_screen_options'] ) ) {
 645          check_admin_referer( 'screen-options-nonce', 'screenoptionnonce' );
 646  
 647          $user = wp_get_current_user();
 648          if ( ! $user ) {
 649              return;
 650          }
 651          $option = $_POST['wp_screen_options']['option'];
 652          $value  = $_POST['wp_screen_options']['value'];
 653  
 654          if ( sanitize_key( $option ) != $option ) {
 655              return;
 656          }
 657  
 658          $map_option = $option;
 659          $type       = str_replace( 'edit_', '', $map_option );
 660          $type       = str_replace( '_per_page', '', $type );
 661          if ( in_array( $type, get_taxonomies(), true ) ) {
 662              $map_option = 'edit_tags_per_page';
 663          } elseif ( in_array( $type, get_post_types(), true ) ) {
 664              $map_option = 'edit_per_page';
 665          } else {
 666              $option = str_replace( '-', '_', $option );
 667          }
 668  
 669          switch ( $map_option ) {
 670              case 'edit_per_page':
 671              case 'users_per_page':
 672              case 'edit_comments_per_page':
 673              case 'upload_per_page':
 674              case 'edit_tags_per_page':
 675              case 'plugins_per_page':
 676              case 'export_personal_data_requests_per_page':
 677              case 'remove_personal_data_requests_per_page':
 678                  // Network admin.
 679              case 'sites_network_per_page':
 680              case 'users_network_per_page':
 681              case 'site_users_network_per_page':
 682              case 'plugins_network_per_page':
 683              case 'themes_network_per_page':
 684              case 'site_themes_network_per_page':
 685                  $value = (int) $value;
 686                  if ( $value < 1 || $value > 999 ) {
 687                      return;
 688                  }
 689                  break;
 690              default:
 691                  $screen_option = false;
 692  
 693                  if ( '_page' === substr( $option, -5 ) || 'layout_columns' === $option ) {
 694                      /**
 695                       * Filters a screen option value before it is set.
 696                       *
 697                       * The filter can also be used to modify non-standard [items]_per_page
 698                       * settings. See the parent function for a full list of standard options.
 699                       *
 700                       * Returning false from the filter will skip saving the current option.
 701                       *
 702                       * @since 2.8.0
 703                       * @since 5.4.2 Only applied to options ending with '_page',
 704                       *              or the 'layout_columns' option.
 705                       *
 706                       * @see set_screen_options()
 707                       *
 708                       * @param mixed  $screen_option The value to save instead of the option value.
 709                       *                              Default false (to skip saving the current option).
 710                       * @param string $option        The option name.
 711                       * @param int    $value         The option value.
 712                       */
 713                      $screen_option = apply_filters( 'set-screen-option', $screen_option, $option, $value ); // phpcs:ignore WordPress.NamingConventions.ValidHookName.UseUnderscores
 714                  }
 715  
 716                  /**
 717                   * Filters a screen option value before it is set.
 718                   *
 719                   * The dynamic portion of the hook, `$option`, refers to the option name.
 720                   *
 721                   * Returning false from the filter will skip saving the current option.
 722                   *
 723                   * @since 5.4.2
 724                   *
 725                   * @see set_screen_options()
 726                   *
 727                   * @param mixed   $screen_option The value to save instead of the option value.
 728                   *                               Default false (to skip saving the current option).
 729                   * @param string  $option        The option name.
 730                   * @param int     $value         The option value.
 731                   */
 732                  $value = apply_filters( "set_screen_option_{$option}", $screen_option, $option, $value );
 733  
 734                  if ( false === $value ) {
 735                      return;
 736                  }
 737                  break;
 738          }
 739  
 740          update_user_meta( $user->ID, $option, $value );
 741  
 742          $url = remove_query_arg( array( 'pagenum', 'apage', 'paged' ), wp_get_referer() );
 743          if ( isset( $_POST['mode'] ) ) {
 744              $url = add_query_arg( array( 'mode' => $_POST['mode'] ), $url );
 745          }
 746  
 747          wp_safe_redirect( $url );
 748          exit;
 749      }
 750  }
 751  
 752  /**
 753   * Check if rewrite rule for WordPress already exists in the IIS 7+ configuration file
 754   *
 755   * @since 2.8.0
 756   *
 757   * @return bool
 758   * @param string $filename The file path to the configuration file
 759   */
 760  function iis7_rewrite_rule_exists( $filename ) {
 761      if ( ! file_exists( $filename ) ) {
 762          return false;
 763      }
 764      if ( ! class_exists( 'DOMDocument', false ) ) {
 765          return false;
 766      }
 767  
 768      $doc = new DOMDocument();
 769      if ( $doc->load( $filename ) === false ) {
 770          return false;
 771      }
 772      $xpath = new DOMXPath( $doc );
 773      $rules = $xpath->query( '/configuration/system.webServer/rewrite/rules/rule[starts-with(@name,\'wordpress\')] | /configuration/system.webServer/rewrite/rules/rule[starts-with(@name,\'WordPress\')]' );
 774      if ( 0 == $rules->length ) {
 775          return false;
 776      } else {
 777          return true;
 778      }
 779  }
 780  
 781  /**
 782   * Delete WordPress rewrite rule from web.config file if it exists there
 783   *
 784   * @since 2.8.0
 785   *
 786   * @param string $filename Name of the configuration file
 787   * @return bool
 788   */
 789  function iis7_delete_rewrite_rule( $filename ) {
 790      // If configuration file does not exist then rules also do not exist, so there is nothing to delete.
 791      if ( ! file_exists( $filename ) ) {
 792          return true;
 793      }
 794  
 795      if ( ! class_exists( 'DOMDocument', false ) ) {
 796          return false;
 797      }
 798  
 799      $doc                     = new DOMDocument();
 800      $doc->preserveWhiteSpace = false;
 801  
 802      if ( $doc->load( $filename ) === false ) {
 803          return false;
 804      }
 805      $xpath = new DOMXPath( $doc );
 806      $rules = $xpath->query( '/configuration/system.webServer/rewrite/rules/rule[starts-with(@name,\'wordpress\')] | /configuration/system.webServer/rewrite/rules/rule[starts-with(@name,\'WordPress\')]' );
 807      if ( $rules->length > 0 ) {
 808          $child  = $rules->item( 0 );
 809          $parent = $child->parentNode;
 810          $parent->removeChild( $child );
 811          $doc->formatOutput = true;
 812          saveDomDocument( $doc, $filename );
 813      }
 814      return true;
 815  }
 816  
 817  /**
 818   * Add WordPress rewrite rule to the IIS 7+ configuration file.
 819   *
 820   * @since 2.8.0
 821   *
 822   * @param string $filename The file path to the configuration file
 823   * @param string $rewrite_rule The XML fragment with URL Rewrite rule
 824   * @return bool
 825   */
 826  function iis7_add_rewrite_rule( $filename, $rewrite_rule ) {
 827      if ( ! class_exists( 'DOMDocument', false ) ) {
 828          return false;
 829      }
 830  
 831      // If configuration file does not exist then we create one.
 832      if ( ! file_exists( $filename ) ) {
 833          $fp = fopen( $filename, 'w' );
 834          fwrite( $fp, '<configuration/>' );
 835          fclose( $fp );
 836      }
 837  
 838      $doc                     = new DOMDocument();
 839      $doc->preserveWhiteSpace = false;
 840  
 841      if ( $doc->load( $filename ) === false ) {
 842          return false;
 843      }
 844  
 845      $xpath = new DOMXPath( $doc );
 846  
 847      // First check if the rule already exists as in that case there is no need to re-add it.
 848      $wordpress_rules = $xpath->query( '/configuration/system.webServer/rewrite/rules/rule[starts-with(@name,\'wordpress\')] | /configuration/system.webServer/rewrite/rules/rule[starts-with(@name,\'WordPress\')]' );
 849      if ( $wordpress_rules->length > 0 ) {
 850          return true;
 851      }
 852  
 853      // Check the XPath to the rewrite rule and create XML nodes if they do not exist.
 854      $xmlnodes = $xpath->query( '/configuration/system.webServer/rewrite/rules' );
 855      if ( $xmlnodes->length > 0 ) {
 856          $rules_node = $xmlnodes->item( 0 );
 857      } else {
 858          $rules_node = $doc->createElement( 'rules' );
 859  
 860          $xmlnodes = $xpath->query( '/configuration/system.webServer/rewrite' );
 861          if ( $xmlnodes->length > 0 ) {
 862              $rewrite_node = $xmlnodes->item( 0 );
 863              $rewrite_node->appendChild( $rules_node );
 864          } else {
 865              $rewrite_node = $doc->createElement( 'rewrite' );
 866              $rewrite_node->appendChild( $rules_node );
 867  
 868              $xmlnodes = $xpath->query( '/configuration/system.webServer' );
 869              if ( $xmlnodes->length > 0 ) {
 870                  $system_webServer_node = $xmlnodes->item( 0 );
 871                  $system_webServer_node->appendChild( $rewrite_node );
 872              } else {
 873                  $system_webServer_node = $doc->createElement( 'system.webServer' );
 874                  $system_webServer_node->appendChild( $rewrite_node );
 875  
 876                  $xmlnodes = $xpath->query( '/configuration' );
 877                  if ( $xmlnodes->length > 0 ) {
 878                      $config_node = $xmlnodes->item( 0 );
 879                      $config_node->appendChild( $system_webServer_node );
 880                  } else {
 881                      $config_node = $doc->createElement( 'configuration' );
 882                      $doc->appendChild( $config_node );
 883                      $config_node->appendChild( $system_webServer_node );
 884                  }
 885              }
 886          }
 887      }
 888  
 889      $rule_fragment = $doc->createDocumentFragment();
 890      $rule_fragment->appendXML( $rewrite_rule );
 891      $rules_node->appendChild( $rule_fragment );
 892  
 893      $doc->encoding     = 'UTF-8';
 894      $doc->formatOutput = true;
 895      saveDomDocument( $doc, $filename );
 896  
 897      return true;
 898  }
 899  
 900  /**
 901   * Saves the XML document into a file
 902   *
 903   * @since 2.8.0
 904   *
 905   * @param DOMDocument $doc
 906   * @param string      $filename
 907   */
 908  function saveDomDocument( $doc, $filename ) { // phpcs:ignore WordPress.NamingConventions.ValidFunctionName.FunctionNameInvalid
 909      $config = $doc->saveXML();
 910      $config = preg_replace( "/([^\r])\n/", "$1\r\n", $config );
 911      $fp     = fopen( $filename, 'w' );
 912      fwrite( $fp, $config );
 913      fclose( $fp );
 914  }
 915  
 916  /**
 917   * Display the default admin color scheme picker (Used in user-edit.php)
 918   *
 919   * @since 3.0.0
 920   *
 921   * @global array $_wp_admin_css_colors
 922   *
 923   * @param int $user_id User ID.
 924   */
 925  function admin_color_scheme_picker( $user_id ) {
 926      global $_wp_admin_css_colors;
 927  
 928      ksort( $_wp_admin_css_colors );
 929  
 930      if ( isset( $_wp_admin_css_colors['fresh'] ) ) {
 931          // Set Default ('fresh') and Light should go first.
 932          $_wp_admin_css_colors = array_filter(
 933              array_merge(
 934                  array(
 935                      'fresh'  => '',
 936                      'light'  => '',
 937                      'modern' => '',
 938                  ),
 939                  $_wp_admin_css_colors
 940              )
 941          );
 942      }
 943  
 944      $current_color = get_user_option( 'admin_color', $user_id );
 945  
 946      if ( empty( $current_color ) || ! isset( $_wp_admin_css_colors[ $current_color ] ) ) {
 947          $current_color = 'fresh';
 948      }
 949  
 950      ?>
 951      <fieldset id="color-picker" class="scheme-list">
 952          <legend class="screen-reader-text"><span><?php _e( 'Admin Color Scheme' ); ?></span></legend>
 953          <?php
 954          wp_nonce_field( 'save-color-scheme', 'color-nonce', false );
 955          foreach ( $_wp_admin_css_colors as $color => $color_info ) :
 956  
 957              ?>
 958              <div class="color-option <?php echo ( $color == $current_color ) ? 'selected' : ''; ?>">
 959                  <input name="admin_color" id="admin_color_<?php echo esc_attr( $color ); ?>" type="radio" value="<?php echo esc_attr( $color ); ?>" class="tog" <?php checked( $color, $current_color ); ?> />
 960                  <input type="hidden" class="css_url" value="<?php echo esc_url( $color_info->url ); ?>" />
 961                  <input type="hidden" class="icon_colors" value="<?php echo esc_attr( wp_json_encode( array( 'icons' => $color_info->icon_colors ) ) ); ?>" />
 962                  <label for="admin_color_<?php echo esc_attr( $color ); ?>"><?php echo esc_html( $color_info->name ); ?></label>
 963                  <table class="color-palette">
 964                      <tr>
 965                      <?php
 966  
 967                      foreach ( $color_info->colors as $html_color ) {
 968                          ?>
 969                          <td style="background-color: <?php echo esc_attr( $html_color ); ?>">&nbsp;</td>
 970                          <?php
 971                      }
 972  
 973                      ?>
 974                      </tr>
 975                  </table>
 976              </div>
 977              <?php
 978  
 979          endforeach;
 980  
 981          ?>
 982      </fieldset>
 983      <?php
 984  }
 985  
 986  /**
 987   *
 988   * @global array $_wp_admin_css_colors
 989   */
 990  function wp_color_scheme_settings() {
 991      global $_wp_admin_css_colors;
 992  
 993      $color_scheme = get_user_option( 'admin_color' );
 994  
 995      // It's possible to have a color scheme set that is no longer registered.
 996      if ( empty( $_wp_admin_css_colors[ $color_scheme ] ) ) {
 997          $color_scheme = 'fresh';
 998      }
 999  
1000      if ( ! empty( $_wp_admin_css_colors[ $color_scheme ]->icon_colors ) ) {
1001          $icon_colors = $_wp_admin_css_colors[ $color_scheme ]->icon_colors;
1002      } elseif ( ! empty( $_wp_admin_css_colors['fresh']->icon_colors ) ) {
1003          $icon_colors = $_wp_admin_css_colors['fresh']->icon_colors;
1004      } else {
1005          // Fall back to the default set of icon colors if the default scheme is missing.
1006          $icon_colors = array(
1007              'base'    => '#a0a5aa',
1008              'focus'   => '#00a0d2',
1009              'current' => '#fff',
1010          );
1011      }
1012  
1013      echo '<script type="text/javascript">var _wpColorScheme = ' . wp_json_encode( array( 'icons' => $icon_colors ) ) . ";</script>\n";
1014  }
1015  
1016  /**
1017   * Displays the viewport meta in the admin.
1018   *
1019   * @since 5.5.0
1020   */
1021  function wp_admin_viewport_meta() {
1022      /**
1023       * Filters the viewport meta in the admin.
1024       *
1025       * @since 5.5.0
1026       *
1027       * @param string $viewport_meta The viewport meta.
1028       */
1029      $viewport_meta = apply_filters( 'admin_viewport_meta', 'width=device-width,initial-scale=1.0' );
1030  
1031      if ( empty( $viewport_meta ) ) {
1032          return;
1033      }
1034  
1035      echo '<meta name="viewport" content="' . esc_attr( $viewport_meta ) . '">';
1036  }
1037  
1038  /**
1039   * Adds viewport meta for mobile in Customizer.
1040   *
1041   * Hooked to the {@see 'admin_viewport_meta'} filter.
1042   *
1043   * @since 5.5.0
1044   *
1045   * @param string $viewport_meta The viewport meta.
1046   * @return string Filtered viewport meta.
1047   */
1048  function _customizer_mobile_viewport_meta( $viewport_meta ) {
1049      return trim( $viewport_meta, ',' ) . ',minimum-scale=0.5,maximum-scale=1.2';
1050  }
1051  
1052  /**
1053   * Check lock status for posts displayed on the Posts screen
1054   *
1055   * @since 3.6.0
1056   *
1057   * @param array  $response  The Heartbeat response.
1058   * @param array  $data      The $_POST data sent.
1059   * @param string $screen_id The screen ID.
1060   * @return array The Heartbeat response.
1061   */
1062  function wp_check_locked_posts( $response, $data, $screen_id ) {
1063      $checked = array();
1064  
1065      if ( array_key_exists( 'wp-check-locked-posts', $data ) && is_array( $data['wp-check-locked-posts'] ) ) {
1066          foreach ( $data['wp-check-locked-posts'] as $key ) {
1067              $post_id = absint( substr( $key, 5 ) );
1068              if ( ! $post_id ) {
1069                  continue;
1070              }
1071  
1072              $user_id = wp_check_post_lock( $post_id );
1073              if ( $user_id ) {
1074                  $user = get_userdata( $user_id );
1075                  if ( $user && current_user_can( 'edit_post', $post_id ) ) {
1076                      $send = array(
1077                          /* translators: %s: User's display name. */
1078                          'text' => sprintf( __( '%s is currently editing' ), $user->display_name ),
1079                      );
1080  
1081                      if ( get_option( 'show_avatars' ) ) {
1082                          $send['avatar_src']    = get_avatar_url( $user->ID, array( 'size' => 18 ) );
1083                          $send['avatar_src_2x'] = get_avatar_url( $user->ID, array( 'size' => 36 ) );
1084                      }
1085  
1086                      $checked[ $key ] = $send;
1087                  }
1088              }
1089          }
1090      }
1091  
1092      if ( ! empty( $checked ) ) {
1093          $response['wp-check-locked-posts'] = $checked;
1094      }
1095  
1096      return $response;
1097  }
1098  
1099  /**
1100   * Check lock status on the New/Edit Post screen and refresh the lock
1101   *
1102   * @since 3.6.0
1103   *
1104   * @param array  $response  The Heartbeat response.
1105   * @param array  $data      The $_POST data sent.
1106   * @param string $screen_id The screen ID.
1107   * @return array The Heartbeat response.
1108   */
1109  function wp_refresh_post_lock( $response, $data, $screen_id ) {
1110      if ( array_key_exists( 'wp-refresh-post-lock', $data ) ) {
1111          $received = $data['wp-refresh-post-lock'];
1112          $send     = array();
1113  
1114          $post_id = absint( $received['post_id'] );
1115          if ( ! $post_id ) {
1116              return $response;
1117          }
1118  
1119          if ( ! current_user_can( 'edit_post', $post_id ) ) {
1120              return $response;
1121          }
1122  
1123          $user_id = wp_check_post_lock( $post_id );
1124          $user    = get_userdata( $user_id );
1125          if ( $user ) {
1126              $error = array(
1127                  /* translators: %s: User's display name. */
1128                  'text' => sprintf( __( '%s has taken over and is currently editing.' ), $user->display_name ),
1129              );
1130  
1131              if ( get_option( 'show_avatars' ) ) {
1132                  $error['avatar_src']    = get_avatar_url( $user->ID, array( 'size' => 64 ) );
1133                  $error['avatar_src_2x'] = get_avatar_url( $user->ID, array( 'size' => 128 ) );
1134              }
1135  
1136              $send['lock_error'] = $error;
1137          } else {
1138              $new_lock = wp_set_post_lock( $post_id );
1139              if ( $new_lock ) {
1140                  $send['new_lock'] = implode( ':', $new_lock );
1141              }
1142          }
1143  
1144          $response['wp-refresh-post-lock'] = $send;
1145      }
1146  
1147      return $response;
1148  }
1149  
1150  /**
1151   * Check nonce expiration on the New/Edit Post screen and refresh if needed
1152   *
1153   * @since 3.6.0
1154   *
1155   * @param array  $response  The Heartbeat response.
1156   * @param array  $data      The $_POST data sent.
1157   * @param string $screen_id The screen ID.
1158   * @return array The Heartbeat response.
1159   */
1160  function wp_refresh_post_nonces( $response, $data, $screen_id ) {
1161      if ( array_key_exists( 'wp-refresh-post-nonces', $data ) ) {
1162          $received                           = $data['wp-refresh-post-nonces'];
1163          $response['wp-refresh-post-nonces'] = array( 'check' => 1 );
1164  
1165          $post_id = absint( $received['post_id'] );
1166          if ( ! $post_id ) {
1167              return $response;
1168          }
1169  
1170          if ( ! current_user_can( 'edit_post', $post_id ) ) {
1171              return $response;
1172          }
1173  
1174          $response['wp-refresh-post-nonces'] = array(
1175              'replace' => array(
1176                  'getpermalinknonce'    => wp_create_nonce( 'getpermalink' ),
1177                  'samplepermalinknonce' => wp_create_nonce( 'samplepermalink' ),
1178                  'closedpostboxesnonce' => wp_create_nonce( 'closedpostboxes' ),
1179                  '_ajax_linking_nonce'  => wp_create_nonce( 'internal-linking' ),
1180                  '_wpnonce'             => wp_create_nonce( 'update-post_' . $post_id ),
1181              ),
1182          );
1183      }
1184  
1185      return $response;
1186  }
1187  
1188  /**
1189   * Add the latest Heartbeat and REST-API nonce to the Heartbeat response.
1190   *
1191   * @since 5.0.0
1192   *
1193   * @param array $response The Heartbeat response.
1194   * @return array The Heartbeat response.
1195   */
1196  function wp_refresh_heartbeat_nonces( $response ) {
1197      // Refresh the Rest API nonce.
1198      $response['rest_nonce'] = wp_create_nonce( 'wp_rest' );
1199  
1200      // Refresh the Heartbeat nonce.
1201      $response['heartbeat_nonce'] = wp_create_nonce( 'heartbeat-nonce' );
1202      return $response;
1203  }
1204  
1205  /**
1206   * Disable suspension of Heartbeat on the Add/Edit Post screens.
1207   *
1208   * @since 3.8.0
1209   *
1210   * @global string $pagenow
1211   *
1212   * @param array $settings An array of Heartbeat settings.
1213   * @return array Filtered Heartbeat settings.
1214   */
1215  function wp_heartbeat_set_suspension( $settings ) {
1216      global $pagenow;
1217  
1218      if ( 'post.php' === $pagenow || 'post-new.php' === $pagenow ) {
1219          $settings['suspension'] = 'disable';
1220      }
1221  
1222      return $settings;
1223  }
1224  
1225  /**
1226   * Autosave with heartbeat
1227   *
1228   * @since 3.9.0
1229   *
1230   * @param array $response The Heartbeat response.
1231   * @param array $data     The $_POST data sent.
1232   * @return array The Heartbeat response.
1233   */
1234  function heartbeat_autosave( $response, $data ) {
1235      if ( ! empty( $data['wp_autosave'] ) ) {
1236          $saved = wp_autosave( $data['wp_autosave'] );
1237  
1238          if ( is_wp_error( $saved ) ) {
1239              $response['wp_autosave'] = array(
1240                  'success' => false,
1241                  'message' => $saved->get_error_message(),
1242              );
1243          } elseif ( empty( $saved ) ) {
1244              $response['wp_autosave'] = array(
1245                  'success' => false,
1246                  'message' => __( 'Error while saving.' ),
1247              );
1248          } else {
1249              /* translators: Draft saved date format, see https://www.php.net/manual/datetime.format.php */
1250              $draft_saved_date_format = __( 'g:i:s a' );
1251              $response['wp_autosave'] = array(
1252                  'success' => true,
1253                  /* translators: %s: Date and time. */
1254                  'message' => sprintf( __( 'Draft saved at %s.' ), date_i18n( $draft_saved_date_format ) ),
1255              );
1256          }
1257      }
1258  
1259      return $response;
1260  }
1261  
1262  /**
1263   * Remove single-use URL parameters and create canonical link based on new URL.
1264   *
1265   * Remove specific query string parameters from a URL, create the canonical link,
1266   * put it in the admin header, and change the current URL to match.
1267   *
1268   * @since 4.2.0
1269   */
1270  function wp_admin_canonical_url() {
1271      $removable_query_args = wp_removable_query_args();
1272  
1273      if ( empty( $removable_query_args ) ) {
1274          return;
1275      }
1276  
1277      // Ensure we're using an absolute URL.
1278      $current_url  = set_url_scheme( 'http://' . $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI'] );
1279      $filtered_url = remove_query_arg( $removable_query_args, $current_url );
1280      ?>
1281      <link id="wp-admin-canonical" rel="canonical" href="<?php echo esc_url( $filtered_url ); ?>" />
1282      <script>
1283          if ( window.history.replaceState ) {
1284              window.history.replaceState( null, null, document.getElementById( 'wp-admin-canonical' ).href + window.location.hash );
1285          }
1286      </script>
1287      <?php
1288  }
1289  
1290  /**
1291   * Send a referrer policy header so referrers are not sent externally from administration screens.
1292   *
1293   * @since 4.9.0
1294   */
1295  function wp_admin_headers() {
1296      $policy = 'strict-origin-when-cross-origin';
1297  
1298      /**
1299       * Filters the admin referrer policy header value.
1300       *
1301       * @since 4.9.0
1302       * @since 4.9.5 The default value was changed to 'strict-origin-when-cross-origin'.
1303       *
1304       * @link https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Referrer-Policy
1305       *
1306       * @param string $policy The admin referrer policy header value. Default 'strict-origin-when-cross-origin'.
1307       */
1308      $policy = apply_filters( 'admin_referrer_policy', $policy );
1309  
1310      header( sprintf( 'Referrer-Policy: %s', $policy ) );
1311  }
1312  
1313  /**
1314   * Outputs JS that reloads the page if the user navigated to it with the Back or Forward button.
1315   *
1316   * Used on the Edit Post and Add New Post screens. Needed to ensure the page is not loaded from browser cache,
1317   * so the post title and editor content are the last saved versions. Ideally this script should run first in the head.
1318   *
1319   * @since 4.6.0
1320   */
1321  function wp_page_reload_on_back_button_js() {
1322      ?>
1323      <script>
1324          if ( typeof performance !== 'undefined' && performance.navigation && performance.navigation.type === 2 ) {
1325              document.location.reload( true );
1326          }
1327      </script>
1328      <?php
1329  }
1330  
1331  /**
1332   * Send a confirmation request email when a change of site admin email address is attempted.
1333   *
1334   * The new site admin address will not become active until confirmed.
1335   *
1336   * @since 3.0.0
1337   * @since 4.9.0 This function was moved from wp-admin/includes/ms.php so it's no longer Multisite specific.
1338   *
1339   * @param string $old_value The old site admin email address.
1340   * @param string $value     The proposed new site admin email address.
1341   */
1342  function update_option_new_admin_email( $old_value, $value ) {
1343      if ( get_option( 'admin_email' ) === $value || ! is_email( $value ) ) {
1344          return;
1345      }
1346  
1347      $hash            = md5( $value . time() . wp_rand() );
1348      $new_admin_email = array(
1349          'hash'     => $hash,
1350          'newemail' => $value,
1351      );
1352      update_option( 'adminhash', $new_admin_email );
1353  
1354      $switched_locale = switch_to_locale( get_user_locale() );
1355  
1356      /* translators: Do not translate USERNAME, ADMIN_URL, EMAIL, SITENAME, SITEURL: those are placeholders. */
1357      $email_text = __(
1358          'Howdy ###USERNAME###,
1359  
1360  You recently requested to have the administration email address on
1361  your site changed.
1362  
1363  If this is correct, please click on the following link to change it:
1364  ###ADMIN_URL###
1365  
1366  You can safely ignore and delete this email if you do not want to
1367  take this action.
1368  
1369  This email has been sent to ###EMAIL###
1370  
1371  Regards,
1372  All at ###SITENAME###
1373  ###SITEURL###'
1374      );
1375  
1376      /**
1377       * Filters the text of the email sent when a change of site admin email address is attempted.
1378       *
1379       * The following strings have a special meaning and will get replaced dynamically:
1380       * ###USERNAME###  The current user's username.
1381       * ###ADMIN_URL### The link to click on to confirm the email change.
1382       * ###EMAIL###     The proposed new site admin email address.
1383       * ###SITENAME###  The name of the site.
1384       * ###SITEURL###   The URL to the site.
1385       *
1386       * @since MU (3.0.0)
1387       * @since 4.9.0 This filter is no longer Multisite specific.
1388       *
1389       * @param string $email_text      Text in the email.
1390       * @param array  $new_admin_email {
1391       *     Data relating to the new site admin email address.
1392       *
1393       *     @type string $hash     The secure hash used in the confirmation link URL.
1394       *     @type string $newemail The proposed new site admin email address.
1395       * }
1396       */
1397      $content = apply_filters( 'new_admin_email_content', $email_text, $new_admin_email );
1398  
1399      $current_user = wp_get_current_user();
1400      $content      = str_replace( '###USERNAME###', $current_user->user_login, $content );
1401      $content      = str_replace( '###ADMIN_URL###', esc_url( self_admin_url( 'options.php?adminhash=' . $hash ) ), $content );
1402      $content      = str_replace( '###EMAIL###', $value, $content );
1403      $content      = str_replace( '###SITENAME###', wp_specialchars_decode( get_option( 'blogname' ), ENT_QUOTES ), $content );
1404      $content      = str_replace( '###SITEURL###', home_url(), $content );
1405  
1406      wp_mail(
1407          $value,
1408          sprintf(
1409              /* translators: New admin email address notification email subject. %s: Site title. */
1410              __( '[%s] New Admin Email Address' ),
1411              wp_specialchars_decode( get_option( 'blogname' ), ENT_QUOTES )
1412          ),
1413          $content
1414      );
1415  
1416      if ( $switched_locale ) {
1417          restore_previous_locale();
1418      }
1419  }
1420  
1421  /**
1422   * Appends '(Draft)' to draft page titles in the privacy page dropdown
1423   * so that unpublished content is obvious.
1424   *
1425   * @since 4.9.8
1426   * @access private
1427   *
1428   * @param string  $title Page title.
1429   * @param WP_Post $page  Page data object.
1430   * @return string Page title.
1431   */
1432  function _wp_privacy_settings_filter_draft_page_titles( $title, $page ) {
1433      if ( 'draft' === $page->post_status && 'privacy' === get_current_screen()->id ) {
1434          /* translators: %s: Page title. */
1435          $title = sprintf( __( '%s (Draft)' ), $title );
1436      }
1437  
1438      return $title;
1439  }
1440  
1441  /**
1442   * Checks if the user needs to update PHP.
1443   *
1444   * @since 5.1.0
1445   * @since 5.1.1 Added the {@see 'wp_is_php_version_acceptable'} filter.
1446   *
1447   * @return array|false Array of PHP version data. False on failure.
1448   */
1449  function wp_check_php_version() {
1450      $version = phpversion();
1451      $key     = md5( $version );
1452  
1453      $response = get_site_transient( 'php_check_' . $key );
1454      if ( false === $response ) {
1455          $url = 'http://api.wordpress.org/core/serve-happy/1.0/';
1456          if ( wp_http_supports( array( 'ssl' ) ) ) {
1457              $url = set_url_scheme( $url, 'https' );
1458          }
1459  
1460          $url = add_query_arg( 'php_version', $version, $url );
1461  
1462          $response = wp_remote_get( $url );
1463  
1464          if ( is_wp_error( $response ) || 200 !== wp_remote_retrieve_response_code( $response ) ) {
1465              return false;
1466          }
1467  
1468          /**
1469           * Response should be an array with:
1470           *  'recommended_version' - string - The PHP version recommended by WordPress.
1471           *  'is_supported' - boolean - Whether the PHP version is actively supported.
1472           *  'is_secure' - boolean - Whether the PHP version receives security updates.
1473           *  'is_acceptable' - boolean - Whether the PHP version is still acceptable for WordPress.
1474           */
1475          $response = json_decode( wp_remote_retrieve_body( $response ), true );
1476  
1477          if ( ! is_array( $response ) ) {
1478              return false;
1479          }
1480  
1481          set_site_transient( 'php_check_' . $key, $response, WEEK_IN_SECONDS );
1482      }
1483  
1484      if ( isset( $response['is_acceptable'] ) && $response['is_acceptable'] ) {
1485          /**
1486           * Filters whether the active PHP version is considered acceptable by WordPress.
1487           *
1488           * Returning false will trigger a PHP version warning to show up in the admin dashboard to administrators.
1489           *
1490           * This filter is only run if the wordpress.org Serve Happy API considers the PHP version acceptable, ensuring
1491           * that this filter can only make this check stricter, but not loosen it.
1492           *
1493           * @since 5.1.1
1494           *
1495           * @param bool   $is_acceptable Whether the PHP version is considered acceptable. Default true.
1496           * @param string $version       PHP version checked.
1497           */
1498          $response['is_acceptable'] = (bool) apply_filters( 'wp_is_php_version_acceptable', true, $version );
1499      }
1500  
1501      return $response;
1502  }


Generated: Fri Oct 30 01:00:03 2020 Cross-referenced by PHPXref 0.7.1