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