| [ Index ] |
PHP Cross Reference of WordPress Trunk (Updated Daily) |
[Summary view] [Print] [Text view]
1 <?php 2 /** 3 * Class for providing debug data based on a users WordPress environment. 4 * 5 * @package WordPress 6 * @subpackage Site_Health 7 * @since 5.2.0 8 */ 9 10 #[AllowDynamicProperties] 11 class WP_Debug_Data { 12 /** 13 * Calls all core functions to check for updates. 14 * 15 * @since 5.2.0 16 */ 17 public static function check_for_updates() { 18 wp_version_check(); 19 wp_update_plugins(); 20 wp_update_themes(); 21 } 22 23 /** 24 * Static function for generating site debug data when required. 25 * 26 * @since 5.2.0 27 * @since 5.3.0 Added database charset, database collation, 28 * and timezone information. 29 * @since 5.5.0 Added pretty permalinks support information. 30 * @since 6.7.0 Modularized into separate theme-oriented methods. 31 * 32 * @throws ImagickException 33 * 34 * @return array The debug data for the site. 35 */ 36 public static function debug_data() { 37 /* 38 * Set up the array that holds all debug information. 39 * 40 * When iterating through the debug data, the ordering of the sections 41 * occurs in insertion-order of the assignments into this array. 42 * 43 * This is the single assignment of the sections before filtering. Null-entries will 44 * be automatically be removed. 45 */ 46 $info = array( 47 'wp-core' => self::get_wp_core(), 48 'wp-paths-sizes' => self::get_wp_paths_sizes(), 49 'wp-dropins' => self::get_wp_dropins(), 50 'wp-active-theme' => self::get_wp_active_theme(), 51 'wp-parent-theme' => self::get_wp_parent_theme(), 52 'wp-themes-inactive' => self::get_wp_themes_inactive(), 53 'wp-mu-plugins' => self::get_wp_mu_plugins(), 54 'wp-plugins-active' => self::get_wp_plugins_active(), 55 'wp-plugins-inactive' => self::get_wp_plugins_inactive(), 56 'wp-media' => self::get_wp_media(), 57 'wp-server' => self::get_wp_server(), 58 'wp-database' => self::get_wp_database(), 59 'wp-constants' => self::get_wp_constants(), 60 'wp-filesystem' => self::get_wp_filesystem(), 61 ); 62 63 /* 64 * Remove null elements from the array. The individual methods are 65 * allowed to return `null`, which communicates that the category 66 * of debug data isn't relevant and shouldn't be passed through. 67 */ 68 $info = array_filter( 69 $info, 70 static function ( $section ) { 71 return isset( $section ); 72 } 73 ); 74 75 /** 76 * Filters the debug information shown on the Tools -> Site Health -> Info screen. 77 * 78 * Plugin or themes may wish to introduce their own debug information without creating 79 * additional admin pages. They can utilize this filter to introduce their own sections 80 * or add more data to existing sections. 81 * 82 * Array keys for sections added by core are all prefixed with `wp-`. Plugins and themes 83 * should use their own slug as a prefix, both for consistency as well as avoiding 84 * key collisions. Note that the array keys are used as labels for the copied data. 85 * 86 * All strings are expected to be plain text except `$description` that can contain 87 * inline HTML tags (see below). 88 * 89 * @since 5.2.0 90 * 91 * @param array $args { 92 * The debug information to be added to the core information page. 93 * 94 * This is an associative multi-dimensional array, up to three levels deep. 95 * The topmost array holds the sections, keyed by section ID. 96 * 97 * @type array ...$0 { 98 * Each section has a `$fields` associative array (see below), and each `$value` in `$fields` 99 * can be another associative array of name/value pairs when there is more structured data 100 * to display. 101 * 102 * @type string $label Required. The title for this section of the debug output. 103 * @type string $description Optional. A description for your information section which 104 * may contain basic HTML markup, inline tags only as it is 105 * outputted in a paragraph. 106 * @type bool $show_count Optional. If set to `true`, the amount of fields will be included 107 * in the title for this section. Default false. 108 * @type bool $private Optional. If set to `true`, the section and all associated fields 109 * will be excluded from the copied data. Default false. 110 * @type array $fields { 111 * Required. An associative array containing the fields to be displayed in the section, 112 * keyed by field ID. 113 * 114 * @type array ...$0 { 115 * An associative array containing the data to be displayed for the field. 116 * 117 * @type string $label Required. The label for this piece of information. 118 * @type mixed $value Required. The output that is displayed for this field. 119 * Text should be translated. Can be an associative array 120 * that is displayed as name/value pairs. 121 * Accepted types: `string|int|float|(string|int|float)[]`. 122 * @type string $debug Optional. The output that is used for this field when 123 * the user copies the data. It should be more concise and 124 * not translated. If not set, the content of `$value` 125 * is used. Note that the array keys are used as labels 126 * for the copied data. 127 * @type bool $private Optional. If set to `true`, the field will be excluded 128 * from the copied data, allowing you to show, for example, 129 * API keys here. Default false. 130 * } 131 * } 132 * } 133 * } 134 */ 135 $info = apply_filters( 'debug_information', $info ); 136 137 return $info; 138 } 139 140 /** 141 * Gets the WordPress core section of the debug data. 142 * 143 * @since 6.7.0 144 * 145 * @return array<string, string|array> The debug data for the Info screen. 146 */ 147 private static function get_wp_core(): array { 148 // Save few function calls. 149 $permalink_structure = get_option( 'permalink_structure' ); 150 $is_ssl = is_ssl(); 151 $users_can_register = get_option( 'users_can_register' ); 152 $blog_public = get_option( 'blog_public' ); 153 $default_comment_status = get_option( 'default_comment_status' ); 154 $environment_type = wp_get_environment_type(); 155 $core_version = wp_get_wp_version(); 156 $core_updates = get_core_updates(); 157 $core_update_needed = ''; 158 159 if ( is_array( $core_updates ) ) { 160 foreach ( $core_updates as $core => $update ) { 161 if ( 'upgrade' === $update->response ) { 162 /* translators: %s: Latest WordPress version number. */ 163 $core_update_needed = ' ' . sprintf( __( '(Latest version: %s)' ), $update->version ); 164 } else { 165 $core_update_needed = ''; 166 } 167 } 168 } 169 170 $fields = array( 171 'version' => array( 172 'label' => __( 'Version' ), 173 'value' => $core_version . $core_update_needed, 174 'debug' => $core_version, 175 ), 176 'site_language' => array( 177 'label' => __( 'Site Language' ), 178 'value' => get_locale(), 179 ), 180 'user_language' => array( 181 'label' => __( 'User Language' ), 182 'value' => get_user_locale(), 183 ), 184 'timezone' => array( 185 'label' => __( 'Timezone' ), 186 'value' => wp_timezone_string(), 187 ), 188 'home_url' => array( 189 'label' => __( 'Home URL' ), 190 'value' => get_bloginfo( 'url' ), 191 'private' => true, 192 ), 193 'site_url' => array( 194 'label' => __( 'Site URL' ), 195 'value' => get_bloginfo( 'wpurl' ), 196 'private' => true, 197 ), 198 'permalink' => array( 199 'label' => __( 'Permalink structure' ), 200 'value' => $permalink_structure ? $permalink_structure : __( 'No permalink structure set' ), 201 'debug' => $permalink_structure, 202 ), 203 'https_status' => array( 204 'label' => __( 'Is this site using HTTPS?' ), 205 'value' => $is_ssl ? __( 'Yes' ) : __( 'No' ), 206 'debug' => $is_ssl, 207 ), 208 'multisite' => array( 209 'label' => __( 'Is this a multisite?' ), 210 'value' => is_multisite() ? __( 'Yes' ) : __( 'No' ), 211 'debug' => is_multisite(), 212 ), 213 'user_registration' => array( 214 'label' => __( 'Can anyone register on this site?' ), 215 'value' => $users_can_register ? __( 'Yes' ) : __( 'No' ), 216 'debug' => $users_can_register, 217 ), 218 'blog_public' => array( 219 'label' => __( 'Is this site discouraging search engines?' ), 220 'value' => $blog_public ? __( 'No' ) : __( 'Yes' ), 221 'debug' => $blog_public, 222 ), 223 'default_comment_status' => array( 224 'label' => __( 'Default comment status' ), 225 'value' => 'open' === $default_comment_status ? _x( 'Open', 'comment status' ) : _x( 'Closed', 'comment status' ), 226 'debug' => $default_comment_status, 227 ), 228 'environment_type' => array( 229 'label' => __( 'Environment type' ), 230 'value' => $environment_type, 231 'debug' => $environment_type, 232 ), 233 ); 234 235 // Conditionally add debug information for multisite setups. 236 if ( is_multisite() ) { 237 $site_id = get_current_blog_id(); 238 239 $fields['site_id'] = array( 240 'label' => __( 'Site ID' ), 241 'value' => $site_id, 242 'debug' => $site_id, 243 ); 244 245 $network_query = new WP_Network_Query(); 246 $network_ids = $network_query->query( 247 array( 248 'fields' => 'ids', 249 'number' => 100, 250 'no_found_rows' => false, 251 ) 252 ); 253 254 $site_count = 0; 255 foreach ( $network_ids as $network_id ) { 256 $site_count += get_blog_count( $network_id ); 257 } 258 259 $fields['site_count'] = array( 260 'label' => __( 'Site count' ), 261 'value' => $site_count, 262 ); 263 264 $fields['network_count'] = array( 265 'label' => __( 'Network count' ), 266 'value' => $network_query->found_networks, 267 ); 268 } 269 270 $fields['user_count'] = array( 271 'label' => __( 'User count' ), 272 'value' => get_user_count(), 273 ); 274 275 // WordPress features requiring processing. 276 $wp_dotorg = wp_remote_get( 'https://wordpress.org', array( 'timeout' => 10 ) ); 277 278 if ( ! is_wp_error( $wp_dotorg ) ) { 279 $fields['dotorg_communication'] = array( 280 'label' => __( 'Communication with WordPress.org' ), 281 'value' => __( 'WordPress.org is reachable' ), 282 'debug' => 'true', 283 ); 284 } else { 285 $fields['dotorg_communication'] = array( 286 'label' => __( 'Communication with WordPress.org' ), 287 'value' => sprintf( 288 /* translators: 1: The IP address WordPress.org resolves to. 2: The error returned by the lookup. */ 289 __( 'Unable to reach WordPress.org at %1$s: %2$s' ), 290 gethostbyname( 'wordpress.org' ), 291 $wp_dotorg->get_error_message() 292 ), 293 'debug' => $wp_dotorg->get_error_message(), 294 ); 295 } 296 297 return array( 298 'label' => __( 'WordPress' ), 299 'fields' => $fields, 300 ); 301 } 302 303 /** 304 * Gets the WordPress drop-in section of the debug data. 305 * 306 * @since 6.7.0 307 * 308 * @return array<string, string|bool|array> The drop-ins debug data. 309 */ 310 private static function get_wp_dropins(): array { 311 // Get a list of all drop-in replacements. 312 $dropins = get_dropins(); 313 314 // Get drop-ins descriptions. 315 $dropin_descriptions = _get_dropins(); 316 317 $fields = array(); 318 foreach ( $dropins as $dropin_key => $dropin ) { 319 $fields[ sanitize_text_field( $dropin_key ) ] = array( 320 'label' => $dropin_key, 321 'value' => $dropin_descriptions[ $dropin_key ][0], 322 'debug' => 'true', 323 ); 324 } 325 326 return array( 327 'label' => __( 'Drop-ins' ), 328 'show_count' => true, 329 'description' => sprintf( 330 /* translators: %s: wp-content directory name. */ 331 __( 'Drop-ins are single files, found in the %s directory, that replace or enhance WordPress features in ways that are not possible for traditional plugins.' ), 332 '<code>' . str_replace( ABSPATH, '', WP_CONTENT_DIR ) . '</code>' 333 ), 334 'fields' => $fields, 335 ); 336 } 337 338 /** 339 * Gets the WordPress server section of the debug data. 340 * 341 * @since 6.7.0 342 * 343 * @return array<string, string|array> The server-related debug data. 344 */ 345 private static function get_wp_server(): array { 346 // Populate the server debug fields. 347 if ( function_exists( 'php_uname' ) ) { 348 $server_architecture = sprintf( '%s %s %s', php_uname( 's' ), php_uname( 'r' ), php_uname( 'm' ) ); 349 } else { 350 $server_architecture = 'unknown'; 351 } 352 353 $php_version_debug = PHP_VERSION; 354 // Whether PHP supports 64-bit. 355 $php64bit = ( PHP_INT_SIZE * 8 === 64 ); 356 357 $php_version = sprintf( 358 '%s %s', 359 $php_version_debug, 360 ( $php64bit ? __( '(Supports 64bit values)' ) : __( '(Does not support 64bit values)' ) ) 361 ); 362 363 if ( $php64bit ) { 364 $php_version_debug .= ' 64bit'; 365 } 366 367 $fields = array(); 368 369 $fields['server_architecture'] = array( 370 'label' => __( 'Server architecture' ), 371 'value' => ( 'unknown' !== $server_architecture ? $server_architecture : __( 'Unable to determine server architecture' ) ), 372 'debug' => $server_architecture, 373 ); 374 $fields['httpd_software'] = array( 375 'label' => __( 'Web server' ), 376 'value' => ! empty( $_SERVER['SERVER_SOFTWARE'] ) ? wp_unslash( $_SERVER['SERVER_SOFTWARE'] ) : __( 'Unable to determine what web server software is used' ), 377 'debug' => ! empty( $_SERVER['SERVER_SOFTWARE'] ) ? wp_unslash( $_SERVER['SERVER_SOFTWARE'] ) : 'unknown', 378 ); 379 $fields['php_version'] = array( 380 'label' => __( 'PHP version' ), 381 'value' => $php_version, 382 'debug' => $php_version_debug, 383 ); 384 $fields['php_sapi'] = array( 385 'label' => __( 'PHP SAPI' ), 386 'value' => PHP_SAPI, 387 'debug' => PHP_SAPI, 388 ); 389 390 // Some servers disable `ini_set()` and `ini_get()`, we check this before trying to get configuration values. 391 if ( ! function_exists( 'ini_get' ) ) { 392 $fields['ini_get'] = array( 393 'label' => __( 'Server settings' ), 394 'value' => sprintf( 395 /* translators: %s: ini_get() */ 396 __( 'Unable to determine some settings, as the %s function has been disabled.' ), 397 'ini_get()' 398 ), 399 'debug' => 'ini_get() is disabled', 400 ); 401 } else { 402 $fields['max_input_variables'] = array( 403 'label' => __( 'PHP max input variables' ), 404 'value' => ini_get( 'max_input_vars' ), 405 ); 406 $fields['time_limit'] = array( 407 'label' => __( 'PHP time limit' ), 408 'value' => ini_get( 'max_execution_time' ), 409 ); 410 411 if ( WP_Site_Health::get_instance()->php_memory_limit !== ini_get( 'memory_limit' ) ) { 412 $fields['memory_limit'] = array( 413 'label' => __( 'PHP memory limit' ), 414 'value' => WP_Site_Health::get_instance()->php_memory_limit, 415 ); 416 $fields['admin_memory_limit'] = array( 417 'label' => __( 'PHP memory limit (only for admin screens)' ), 418 'value' => ini_get( 'memory_limit' ), 419 ); 420 } else { 421 $fields['memory_limit'] = array( 422 'label' => __( 'PHP memory limit' ), 423 'value' => ini_get( 'memory_limit' ), 424 ); 425 } 426 427 $fields['max_input_time'] = array( 428 'label' => __( 'Max input time' ), 429 'value' => ini_get( 'max_input_time' ), 430 ); 431 $fields['upload_max_filesize'] = array( 432 'label' => __( 'Upload max filesize' ), 433 'value' => ini_get( 'upload_max_filesize' ), 434 ); 435 $fields['php_post_max_size'] = array( 436 'label' => __( 'PHP post max size' ), 437 'value' => ini_get( 'post_max_size' ), 438 ); 439 } 440 441 if ( function_exists( 'curl_version' ) ) { 442 $curl = curl_version(); 443 444 $fields['curl_version'] = array( 445 'label' => __( 'cURL version' ), 446 'value' => sprintf( '%s %s', $curl['version'], $curl['ssl_version'] ), 447 ); 448 } else { 449 $fields['curl_version'] = array( 450 'label' => __( 'cURL version' ), 451 'value' => __( 'Not available' ), 452 'debug' => 'not available', 453 ); 454 } 455 456 // SUHOSIN. 457 $suhosin_loaded = ( extension_loaded( 'suhosin' ) || ( defined( 'SUHOSIN_PATCH' ) && constant( 'SUHOSIN_PATCH' ) ) ); 458 459 $fields['suhosin'] = array( 460 'label' => __( 'Is SUHOSIN installed?' ), 461 'value' => ( $suhosin_loaded ? __( 'Yes' ) : __( 'No' ) ), 462 'debug' => $suhosin_loaded, 463 ); 464 465 // Imagick. 466 $imagick_loaded = extension_loaded( 'imagick' ); 467 468 $fields['imagick_availability'] = array( 469 'label' => __( 'Is the Imagick library available?' ), 470 'value' => ( $imagick_loaded ? __( 'Yes' ) : __( 'No' ) ), 471 'debug' => $imagick_loaded, 472 ); 473 474 // Opcode Cache. 475 if ( function_exists( 'opcache_get_status' ) ) { 476 $opcache_status = @opcache_get_status( false ); // phpcs:ignore WordPress.PHP.NoSilencedErrors.Discouraged -- Warning emitted in failure case. 477 478 if ( false === $opcache_status ) { 479 $fields['opcode_cache'] = array( 480 'label' => __( 'Opcode cache' ), 481 'value' => __( 'Disabled by configuration' ), 482 'debug' => 'not available', 483 ); 484 } else { 485 $fields['opcode_cache'] = array( 486 'label' => __( 'Opcode cache' ), 487 'value' => $opcache_status['opcache_enabled'] ? __( 'Enabled' ) : __( 'Disabled' ), 488 'debug' => $opcache_status['opcache_enabled'], 489 ); 490 491 if ( true === $opcache_status['opcache_enabled'] ) { 492 $fields['opcode_cache_memory_usage'] = array( 493 'label' => __( 'Opcode cache memory usage' ), 494 'value' => sprintf( 495 /* translators: 1: Used memory, 2: Total memory */ 496 __( '%1$s of %2$s' ), 497 size_format( $opcache_status['memory_usage']['used_memory'] ), 498 size_format( $opcache_status['memory_usage']['free_memory'] + $opcache_status['memory_usage']['used_memory'] ) 499 ), 500 'debug' => sprintf( 501 '%s of %s', 502 $opcache_status['memory_usage']['used_memory'], 503 $opcache_status['memory_usage']['free_memory'] + $opcache_status['memory_usage']['used_memory'] 504 ), 505 ); 506 507 if ( 0 !== $opcache_status['interned_strings_usage']['buffer_size'] ) { 508 $fields['opcode_cache_interned_strings_usage'] = array( 509 'label' => __( 'Opcode cache interned strings usage' ), 510 'value' => sprintf( 511 /* translators: 1: Percentage used, 2: Total memory, 3: Free memory */ 512 __( '%1$s%% of %2$s (%3$s free)' ), 513 number_format_i18n( ( $opcache_status['interned_strings_usage']['used_memory'] / $opcache_status['interned_strings_usage']['buffer_size'] ) * 100, 2 ), 514 size_format( $opcache_status['interned_strings_usage']['buffer_size'] ), 515 size_format( $opcache_status['interned_strings_usage']['free_memory'] ) 516 ), 517 'debug' => sprintf( 518 '%s%% of %s (%s free)', 519 round( ( $opcache_status['interned_strings_usage']['used_memory'] / $opcache_status['interned_strings_usage']['buffer_size'] ) * 100, 2 ), 520 $opcache_status['interned_strings_usage']['buffer_size'], 521 $opcache_status['interned_strings_usage']['free_memory'] 522 ), 523 ); 524 } 525 526 $fields['opcode_cache_hit_rate'] = array( 527 'label' => __( 'Opcode cache hit rate' ), 528 'value' => sprintf( 529 /* translators: %s: Hit rate percentage */ 530 __( '%s%%' ), 531 number_format_i18n( $opcache_status['opcache_statistics']['opcache_hit_rate'], 2 ) 532 ), 533 'debug' => round( $opcache_status['opcache_statistics']['opcache_hit_rate'], 2 ), 534 ); 535 536 $fields['opcode_cache_full'] = array( 537 'label' => __( 'Is the Opcode cache full?' ), 538 'value' => $opcache_status['cache_full'] ? __( 'Yes' ) : __( 'No' ), 539 'debug' => $opcache_status['cache_full'], 540 ); 541 } 542 } 543 } else { 544 $fields['opcode_cache'] = array( 545 'label' => __( 'Opcode cache' ), 546 'value' => __( 'Disabled' ), 547 'debug' => 'not available', 548 ); 549 } 550 551 // Pretty permalinks. 552 $pretty_permalinks_supported = got_url_rewrite(); 553 554 $fields['pretty_permalinks'] = array( 555 'label' => __( 'Are pretty permalinks supported?' ), 556 'value' => ( $pretty_permalinks_supported ? __( 'Yes' ) : __( 'No' ) ), 557 'debug' => $pretty_permalinks_supported, 558 ); 559 560 // Check if a .htaccess file exists. 561 if ( is_file( ABSPATH . '.htaccess' ) ) { 562 // If the file exists, grab the content of it. 563 $htaccess_content = file_get_contents( ABSPATH . '.htaccess' ); 564 565 // Filter away the core WordPress rules. 566 $filtered_htaccess_content = trim( preg_replace( '/\# BEGIN WordPress[\s\S]+?# END WordPress/si', '', $htaccess_content ) ); 567 $filtered_htaccess_content = ! empty( $filtered_htaccess_content ); 568 569 if ( $filtered_htaccess_content ) { 570 /* translators: %s: .htaccess */ 571 $htaccess_rules_string = sprintf( __( 'Custom rules have been added to your %s file.' ), '.htaccess' ); 572 } else { 573 /* translators: %s: .htaccess */ 574 $htaccess_rules_string = sprintf( __( 'Your %s file contains only core WordPress features.' ), '.htaccess' ); 575 } 576 577 $fields['htaccess_extra_rules'] = array( 578 'label' => __( '.htaccess rules' ), 579 'value' => $htaccess_rules_string, 580 'debug' => $filtered_htaccess_content, 581 ); 582 } 583 584 // Check if a robots.txt file exists. 585 if ( is_file( get_home_path() . 'robots.txt' ) ) { 586 // If the file exists, turn debug info to true. 587 $robotstxt_debug = true; 588 589 /* translators: %s: robots.txt */ 590 $robotstxt_string = sprintf( __( 'Your site is using a static %s file. WordPress cannot dynamically serve one.' ), 'robots.txt' ); 591 } elseif ( got_url_rewrite() ) { 592 // No robots.txt file available and rewrite rules in place, turn debug info to false. 593 $robotstxt_debug = false; 594 595 /* translators: %s: robots.txt */ 596 $robotstxt_string = sprintf( __( 'Your site is using the dynamic %s file which is generated by WordPress.' ), 'robots.txt' ); 597 } else { 598 // No robots.txt file, but without rewrite rules WP can't serve one. 599 $robotstxt_debug = true; 600 601 /* translators: %s: robots.txt */ 602 $robotstxt_string = sprintf( __( 'WordPress cannot dynamically serve a %s file due to a lack of rewrite rule support.' ), 'robots.txt' ); 603 604 } 605 606 $fields['static_robotstxt_file'] = array( 607 'label' => __( 'robots.txt' ), 608 'value' => $robotstxt_string, 609 'debug' => $robotstxt_debug, 610 ); 611 612 // Server time. 613 $date = new DateTime( 'now', new DateTimeZone( 'UTC' ) ); 614 615 $fields['current'] = array( 616 'label' => __( 'Current time' ), 617 'value' => $date->format( DateTime::ATOM ), 618 ); 619 $fields['utc-time'] = array( 620 'label' => __( 'Current UTC time' ), 621 'value' => $date->format( DateTime::RFC850 ), 622 ); 623 $fields['server-time'] = array( 624 'label' => __( 'Current Server time' ), 625 'value' => isset( $_SERVER['REQUEST_TIME'] ) ? wp_date( 'c', (int) $_SERVER['REQUEST_TIME'] ) : __( 'Unable to determine server time' ), 626 ); 627 628 return array( 629 'label' => __( 'Server' ), 630 'description' => __( 'The options shown below relate to your server setup. If changes are required, you may need your web host’s assistance.' ), 631 'fields' => $fields, 632 ); 633 } 634 635 /** 636 * Gets the WordPress media section of the debug data. 637 * 638 * @since 6.7.0 639 * 640 * @throws ImagickException 641 * @return array<string, string|array> The media handling debug data. 642 */ 643 private static function get_wp_media(): array { 644 // Spare few function calls. 645 $not_available = __( 'Not available' ); 646 647 // Populate the media fields. 648 $fields['image_editor'] = array( 649 'label' => __( 'Active editor' ), 650 'value' => _wp_image_editor_choose(), 651 ); 652 653 // Get ImageMagic information, if available. 654 if ( class_exists( 'Imagick' ) ) { 655 // Save the Imagick instance for later use. 656 $imagick = new Imagick(); 657 $imagemagick_version = $imagick->getVersion(); 658 } else { 659 $imagemagick_version = __( 'Not available' ); 660 } 661 662 $fields['imagick_module_version'] = array( 663 'label' => __( 'ImageMagick version number' ), 664 'value' => ( is_array( $imagemagick_version ) ? $imagemagick_version['versionNumber'] : $imagemagick_version ), 665 ); 666 667 $fields['imagemagick_version'] = array( 668 'label' => __( 'ImageMagick version string' ), 669 'value' => ( is_array( $imagemagick_version ) ? $imagemagick_version['versionString'] : $imagemagick_version ), 670 ); 671 672 $imagick_version = phpversion( 'imagick' ); 673 674 $fields['imagick_version'] = array( 675 'label' => __( 'Imagick version' ), 676 'value' => ( $imagick_version ) ? $imagick_version : __( 'Not available' ), 677 ); 678 679 if ( ! function_exists( 'ini_get' ) ) { 680 $fields['ini_get'] = array( 681 'label' => __( 'File upload settings' ), 682 'value' => sprintf( 683 /* translators: %s: ini_get() */ 684 __( 'Unable to determine some settings, as the %s function has been disabled.' ), 685 'ini_get()' 686 ), 687 'debug' => 'ini_get() is disabled', 688 ); 689 } else { 690 // Get the PHP ini directive values. 691 $file_uploads = ini_get( 'file_uploads' ); 692 $post_max_size = ini_get( 'post_max_size' ); 693 $upload_max_filesize = ini_get( 'upload_max_filesize' ); 694 $max_file_uploads = ini_get( 'max_file_uploads' ); 695 $effective = min( wp_convert_hr_to_bytes( $post_max_size ), wp_convert_hr_to_bytes( $upload_max_filesize ) ); 696 697 // Add info in Media section. 698 $fields['file_uploads'] = array( 699 'label' => __( 'File uploads' ), 700 'value' => $file_uploads ? __( 'Enabled' ) : __( 'Disabled' ), 701 'debug' => $file_uploads, 702 ); 703 $fields['post_max_size'] = array( 704 'label' => __( 'Max size of post data allowed' ), 705 'value' => $post_max_size, 706 ); 707 $fields['upload_max_filesize'] = array( 708 'label' => __( 'Max size of an uploaded file' ), 709 'value' => $upload_max_filesize, 710 ); 711 $fields['max_effective_size'] = array( 712 'label' => __( 'Max effective file size' ), 713 'value' => size_format( $effective ), 714 ); 715 $fields['max_file_uploads'] = array( 716 'label' => __( 'Max simultaneous file uploads' ), 717 'value' => $max_file_uploads, 718 ); 719 } 720 721 // If Imagick is used as our editor, provide some more information about its limitations. 722 if ( 'WP_Image_Editor_Imagick' === _wp_image_editor_choose() && isset( $imagick ) && $imagick instanceof Imagick ) { 723 $limits = array( 724 'area' => ( defined( 'imagick::RESOURCETYPE_AREA' ) ? size_format( $imagick->getResourceLimit( imagick::RESOURCETYPE_AREA ) ) : $not_available ), 725 'disk' => ( defined( 'imagick::RESOURCETYPE_DISK' ) ? $imagick->getResourceLimit( imagick::RESOURCETYPE_DISK ) : $not_available ), 726 'file' => ( defined( 'imagick::RESOURCETYPE_FILE' ) ? $imagick->getResourceLimit( imagick::RESOURCETYPE_FILE ) : $not_available ), 727 'map' => ( defined( 'imagick::RESOURCETYPE_MAP' ) ? size_format( $imagick->getResourceLimit( imagick::RESOURCETYPE_MAP ) ) : $not_available ), 728 'memory' => ( defined( 'imagick::RESOURCETYPE_MEMORY' ) ? size_format( $imagick->getResourceLimit( imagick::RESOURCETYPE_MEMORY ) ) : $not_available ), 729 'thread' => ( defined( 'imagick::RESOURCETYPE_THREAD' ) ? $imagick->getResourceLimit( imagick::RESOURCETYPE_THREAD ) : $not_available ), 730 'time' => ( defined( 'imagick::RESOURCETYPE_TIME' ) ? $imagick->getResourceLimit( imagick::RESOURCETYPE_TIME ) : $not_available ), 731 ); 732 733 $limits_debug = array( 734 'imagick::RESOURCETYPE_AREA' => ( defined( 'imagick::RESOURCETYPE_AREA' ) ? size_format( $imagick->getResourceLimit( imagick::RESOURCETYPE_AREA ) ) : 'not available' ), 735 'imagick::RESOURCETYPE_DISK' => ( defined( 'imagick::RESOURCETYPE_DISK' ) ? $imagick->getResourceLimit( imagick::RESOURCETYPE_DISK ) : 'not available' ), 736 'imagick::RESOURCETYPE_FILE' => ( defined( 'imagick::RESOURCETYPE_FILE' ) ? $imagick->getResourceLimit( imagick::RESOURCETYPE_FILE ) : 'not available' ), 737 'imagick::RESOURCETYPE_MAP' => ( defined( 'imagick::RESOURCETYPE_MAP' ) ? size_format( $imagick->getResourceLimit( imagick::RESOURCETYPE_MAP ) ) : 'not available' ), 738 'imagick::RESOURCETYPE_MEMORY' => ( defined( 'imagick::RESOURCETYPE_MEMORY' ) ? size_format( $imagick->getResourceLimit( imagick::RESOURCETYPE_MEMORY ) ) : 'not available' ), 739 'imagick::RESOURCETYPE_THREAD' => ( defined( 'imagick::RESOURCETYPE_THREAD' ) ? $imagick->getResourceLimit( imagick::RESOURCETYPE_THREAD ) : 'not available' ), 740 'imagick::RESOURCETYPE_TIME' => ( defined( 'imagick::RESOURCETYPE_TIME' ) ? $imagick->getResourceLimit( imagick::RESOURCETYPE_TIME ) : 'not available' ), 741 ); 742 743 $fields['imagick_limits'] = array( 744 'label' => __( 'Imagick Resource Limits' ), 745 'value' => $limits, 746 'debug' => $limits_debug, 747 ); 748 749 try { 750 $formats = Imagick::queryFormats( '*' ); 751 } catch ( Exception $e ) { 752 $formats = array(); 753 } 754 755 $fields['imagemagick_file_formats'] = array( 756 'label' => __( 'ImageMagick supported file formats' ), 757 'value' => ( empty( $formats ) ) ? __( 'Unable to determine' ) : implode( ', ', $formats ), 758 'debug' => ( empty( $formats ) ) ? 'Unable to determine' : implode( ', ', $formats ), 759 ); 760 } 761 762 // Get the image format transforms. 763 $mappings = wp_get_image_editor_output_format( '', '' ); 764 $formatted_mappings = array(); 765 766 if ( ! empty( $mappings ) ) { 767 foreach ( $mappings as $format => $mime_type ) { 768 $formatted_mappings[] = sprintf( '%s → %s', $format, $mime_type ); 769 } 770 $mappings_display = implode( ', ', $formatted_mappings ); 771 } else { 772 $mappings_display = __( 'No format transforms defined' ); 773 } 774 775 $fields['image_format_transforms'] = array( 776 'label' => __( 'Image format transforms' ), 777 'value' => $mappings_display, 778 'debug' => ( empty( $mappings ) ) ? 'No format transforms defined' : $mappings_display, 779 ); 780 781 // Get GD information, if available. 782 if ( function_exists( 'gd_info' ) ) { 783 $gd = gd_info(); 784 } else { 785 $gd = false; 786 } 787 788 $fields['gd_version'] = array( 789 'label' => __( 'GD version' ), 790 'value' => ( is_array( $gd ) ? $gd['GD Version'] : $not_available ), 791 'debug' => ( is_array( $gd ) ? $gd['GD Version'] : 'not available' ), 792 ); 793 794 $gd_image_formats = array(); 795 $gd_supported_formats = array( 796 'GIF Create' => 'GIF', 797 'JPEG' => 'JPEG', 798 'PNG' => 'PNG', 799 'WebP' => 'WebP', 800 'BMP' => 'BMP', 801 'AVIF' => 'AVIF', 802 'HEIF' => 'HEIF', 803 'TIFF' => 'TIFF', 804 'XPM' => 'XPM', 805 ); 806 807 foreach ( $gd_supported_formats as $format_key => $format ) { 808 $index = $format_key . ' Support'; 809 if ( isset( $gd[ $index ] ) && $gd[ $index ] ) { 810 array_push( $gd_image_formats, $format ); 811 } 812 } 813 814 if ( ! empty( $gd_image_formats ) ) { 815 $fields['gd_formats'] = array( 816 'label' => __( 'GD supported file formats' ), 817 'value' => implode( ', ', $gd_image_formats ), 818 ); 819 } 820 821 // Get Ghostscript information, if available. 822 if ( function_exists( 'exec' ) ) { 823 $gs = exec( 'gs --version' ); 824 825 if ( empty( $gs ) ) { 826 $gs = $not_available; 827 $gs_debug = 'not available'; 828 } else { 829 $gs_debug = $gs; 830 } 831 } else { 832 $gs = __( 'Unable to determine if Ghostscript is installed' ); 833 $gs_debug = 'unknown'; 834 } 835 836 $fields['ghostscript_version'] = array( 837 'label' => __( 'Ghostscript version' ), 838 'value' => $gs, 839 'debug' => $gs_debug, 840 ); 841 842 return array( 843 'label' => __( 'Media Handling' ), 844 'fields' => $fields, 845 ); 846 } 847 848 /** 849 * Gets the WordPress MU plugins section of the debug data. 850 * 851 * @since 6.7.0 852 * 853 * @return array<string, string|bool|array> The must-use plugins debug data. 854 */ 855 private static function get_wp_mu_plugins(): array { 856 // List must use plugins if there are any. 857 $mu_plugins = get_mu_plugins(); 858 $fields = array(); 859 860 foreach ( $mu_plugins as $plugin_path => $plugin ) { 861 $plugin_version = $plugin['Version']; 862 $plugin_author = $plugin['Author']; 863 864 $plugin_version_string = __( 'No version or author information is available.' ); 865 $plugin_version_string_debug = 'author: (undefined), version: (undefined)'; 866 867 if ( ! empty( $plugin_version ) && ! empty( $plugin_author ) ) { 868 /* translators: 1: Plugin version number. 2: Plugin author name. */ 869 $plugin_version_string = sprintf( __( 'Version %1$s by %2$s' ), $plugin_version, $plugin_author ); 870 $plugin_version_string_debug = sprintf( 'version: %s, author: %s', $plugin_version, $plugin_author ); 871 } else { 872 if ( ! empty( $plugin_author ) ) { 873 /* translators: %s: Plugin author name. */ 874 $plugin_version_string = sprintf( __( 'By %s' ), $plugin_author ); 875 $plugin_version_string_debug = sprintf( 'author: %s, version: (undefined)', $plugin_author ); 876 } 877 878 if ( ! empty( $plugin_version ) ) { 879 /* translators: %s: Plugin version number. */ 880 $plugin_version_string = sprintf( __( 'Version %s' ), $plugin_version ); 881 $plugin_version_string_debug = sprintf( 'author: (undefined), version: %s', $plugin_version ); 882 } 883 } 884 885 $fields[ sanitize_text_field( $plugin['Name'] ) ] = array( 886 'label' => $plugin['Name'], 887 'value' => $plugin_version_string, 888 'debug' => $plugin_version_string_debug, 889 ); 890 } 891 892 return array( 893 'label' => __( 'Must Use Plugins' ), 894 'show_count' => true, 895 'fields' => $fields, 896 ); 897 } 898 899 /** 900 * Gets the WordPress paths and sizes section of the debug data. 901 * 902 * @since 6.7.0 903 * 904 * @return array|null Paths and sizes debug data for single sites, 905 * otherwise `null` for multi-site installs. 906 */ 907 private static function get_wp_paths_sizes(): ?array { 908 if ( is_multisite() ) { 909 return null; 910 } 911 912 $loading = __( 'Loading…' ); 913 914 $fields = array( 915 'wordpress_path' => array( 916 'label' => __( 'WordPress directory location' ), 917 'value' => untrailingslashit( ABSPATH ), 918 ), 919 'wordpress_size' => array( 920 'label' => __( 'WordPress directory size' ), 921 'value' => $loading, 922 'debug' => 'loading...', 923 ), 924 'uploads_path' => array( 925 'label' => __( 'Uploads directory location' ), 926 'value' => wp_upload_dir()['basedir'], 927 ), 928 'uploads_size' => array( 929 'label' => __( 'Uploads directory size' ), 930 'value' => $loading, 931 'debug' => 'loading...', 932 ), 933 'themes_path' => array( 934 'label' => __( 'Themes directory location' ), 935 'value' => get_theme_root(), 936 ), 937 'themes_size' => array( 938 'label' => __( 'Themes directory size' ), 939 'value' => $loading, 940 'debug' => 'loading...', 941 ), 942 'plugins_path' => array( 943 'label' => __( 'Plugins directory location' ), 944 'value' => WP_PLUGIN_DIR, 945 ), 946 'plugins_size' => array( 947 'label' => __( 'Plugins directory size' ), 948 'value' => $loading, 949 'debug' => 'loading...', 950 ), 951 'fonts_path' => array( 952 'label' => __( 'Fonts directory location' ), 953 'value' => wp_get_font_dir()['basedir'], 954 ), 955 'fonts_size' => array( 956 'label' => __( 'Fonts directory size' ), 957 'value' => $loading, 958 'debug' => 'loading...', 959 ), 960 'database_size' => array( 961 'label' => __( 'Database size' ), 962 'value' => $loading, 963 'debug' => 'loading...', 964 ), 965 'total_size' => array( 966 'label' => __( 'Total installation size' ), 967 'value' => $loading, 968 'debug' => 'loading...', 969 ), 970 ); 971 972 return array( 973 /* translators: Filesystem directory paths and storage sizes. */ 974 'label' => __( 'Directories and Sizes' ), 975 'fields' => $fields, 976 ); 977 } 978 979 /** 980 * Gets the WordPress active plugins section of the debug data. 981 * 982 * @since 6.7.0 983 * 984 * @return array<string, string|bool|array> The active plugins debug data. 985 */ 986 private static function get_wp_plugins_active(): array { 987 return array( 988 'label' => __( 'Active Plugins' ), 989 'show_count' => true, 990 'fields' => self::get_wp_plugins_raw_data()['wp-plugins-active'], 991 ); 992 } 993 994 /** 995 * Gets the WordPress inactive plugins section of the debug data. 996 * 997 * @since 6.7.0 998 * 999 * @return array<string, string|bool|array> The inactive plugins debug data. 1000 */ 1001 private static function get_wp_plugins_inactive(): array { 1002 return array( 1003 'label' => __( 'Inactive Plugins' ), 1004 'show_count' => true, 1005 'fields' => self::get_wp_plugins_raw_data()['wp-plugins-inactive'], 1006 ); 1007 } 1008 1009 /** 1010 * Gets the raw plugin data for the WordPress active and inactive sections of the debug data. 1011 * 1012 * @since 6.7.0 1013 * 1014 * @return array<string, array<string, array<string, string>>> The raw plugin debug data for active and inactive plugins. 1015 */ 1016 private static function get_wp_plugins_raw_data(): array { 1017 // List all available plugins. 1018 $plugins = get_plugins(); 1019 $plugin_updates = get_plugin_updates(); 1020 $transient = get_site_transient( 'update_plugins' ); 1021 1022 $auto_updates = array(); 1023 $fields = array( 1024 'wp-plugins-active' => array(), 1025 'wp-plugins-inactive' => array(), 1026 ); 1027 1028 $auto_updates_enabled = wp_is_auto_update_enabled_for_type( 'plugin' ); 1029 1030 if ( $auto_updates_enabled ) { 1031 $auto_updates = (array) get_site_option( 'auto_update_plugins', array() ); 1032 } 1033 1034 foreach ( $plugins as $plugin_path => $plugin ) { 1035 $plugin_part = ( is_plugin_active( $plugin_path ) ) ? 'wp-plugins-active' : 'wp-plugins-inactive'; 1036 1037 $plugin_version = $plugin['Version']; 1038 $plugin_author = $plugin['Author']; 1039 1040 $plugin_version_string = __( 'No version or author information is available.' ); 1041 $plugin_version_string_debug = 'author: (undefined), version: (undefined)'; 1042 1043 if ( ! empty( $plugin_version ) && ! empty( $plugin_author ) ) { 1044 /* translators: 1: Plugin version number. 2: Plugin author name. */ 1045 $plugin_version_string = sprintf( __( 'Version %1$s by %2$s' ), $plugin_version, $plugin_author ); 1046 $plugin_version_string_debug = sprintf( 'version: %s, author: %s', $plugin_version, $plugin_author ); 1047 } else { 1048 if ( ! empty( $plugin_author ) ) { 1049 /* translators: %s: Plugin author name. */ 1050 $plugin_version_string = sprintf( __( 'By %s' ), $plugin_author ); 1051 $plugin_version_string_debug = sprintf( 'author: %s, version: (undefined)', $plugin_author ); 1052 } 1053 1054 if ( ! empty( $plugin_version ) ) { 1055 /* translators: %s: Plugin version number. */ 1056 $plugin_version_string = sprintf( __( 'Version %s' ), $plugin_version ); 1057 $plugin_version_string_debug = sprintf( 'author: (undefined), version: %s', $plugin_version ); 1058 } 1059 } 1060 1061 if ( array_key_exists( $plugin_path, $plugin_updates ) ) { 1062 /* translators: %s: Latest plugin version number. */ 1063 $plugin_version_string .= ' ' . sprintf( __( '(Latest version: %s)' ), $plugin_updates[ $plugin_path ]->update->new_version ); 1064 $plugin_version_string_debug .= sprintf( ' (latest version: %s)', $plugin_updates[ $plugin_path ]->update->new_version ); 1065 } 1066 1067 if ( $auto_updates_enabled ) { 1068 if ( isset( $transient->response[ $plugin_path ] ) ) { 1069 $item = $transient->response[ $plugin_path ]; 1070 } elseif ( isset( $transient->no_update[ $plugin_path ] ) ) { 1071 $item = $transient->no_update[ $plugin_path ]; 1072 } else { 1073 $item = array( 1074 'id' => $plugin_path, 1075 'slug' => '', 1076 'plugin' => $plugin_path, 1077 'new_version' => '', 1078 'url' => '', 1079 'package' => '', 1080 'icons' => array(), 1081 'banners' => array(), 1082 'banners_rtl' => array(), 1083 'tested' => '', 1084 'requires_php' => '', 1085 'compatibility' => new stdClass(), 1086 ); 1087 $item = wp_parse_args( $plugin, $item ); 1088 } 1089 1090 $auto_update_forced = wp_is_auto_update_forced_for_item( 'plugin', null, (object) $item ); 1091 1092 if ( ! is_null( $auto_update_forced ) ) { 1093 $enabled = $auto_update_forced; 1094 } else { 1095 $enabled = in_array( $plugin_path, $auto_updates, true ); 1096 } 1097 1098 if ( $enabled ) { 1099 $auto_updates_string = __( 'Auto-updates enabled' ); 1100 } else { 1101 $auto_updates_string = __( 'Auto-updates disabled' ); 1102 } 1103 1104 /** 1105 * Filters the text string of the auto-updates setting for each plugin in the Site Health debug data. 1106 * 1107 * @since 5.5.0 1108 * 1109 * @param string $auto_updates_string The string output for the auto-updates column. 1110 * @param string $plugin_path The path to the plugin file. 1111 * @param array $plugin An array of plugin data. 1112 * @param bool $enabled Whether auto-updates are enabled for this item. 1113 */ 1114 $auto_updates_string = apply_filters( 'plugin_auto_update_debug_string', $auto_updates_string, $plugin_path, $plugin, $enabled ); 1115 1116 $plugin_version_string .= ' | ' . $auto_updates_string; 1117 $plugin_version_string_debug .= ', ' . $auto_updates_string; 1118 } 1119 1120 $fields[ $plugin_part ][ sanitize_text_field( $plugin['Name'] ) ] = array( 1121 'label' => $plugin['Name'], 1122 'value' => $plugin_version_string, 1123 'debug' => $plugin_version_string_debug, 1124 ); 1125 } 1126 1127 return $fields; 1128 } 1129 1130 /** 1131 * Gets the WordPress active theme section of the debug data. 1132 * 1133 * @since 6.7.0 1134 * 1135 * @global array<string, bool|array> $_wp_theme_features The theme features for the active theme. 1136 * 1137 * @return array<string, string|array> The active theme debug data. 1138 */ 1139 private static function get_wp_active_theme(): array { 1140 global $_wp_theme_features; 1141 1142 // Populate the section for the currently active theme. 1143 $theme_features = array(); 1144 1145 if ( ! empty( $_wp_theme_features ) ) { 1146 foreach ( $_wp_theme_features as $feature => $options ) { 1147 $theme_features[] = $feature; 1148 } 1149 } 1150 1151 $active_theme = wp_get_theme(); 1152 $theme_updates = get_theme_updates(); 1153 $transient = get_site_transient( 'update_themes' ); 1154 1155 $active_theme_version = $active_theme->version; 1156 $active_theme_version_debug = $active_theme_version; 1157 1158 $auto_updates = array(); 1159 $auto_updates_enabled = wp_is_auto_update_enabled_for_type( 'theme' ); 1160 if ( $auto_updates_enabled ) { 1161 $auto_updates = (array) get_site_option( 'auto_update_themes', array() ); 1162 } 1163 1164 if ( array_key_exists( $active_theme->stylesheet, $theme_updates ) ) { 1165 $theme_update_new_version = $theme_updates[ $active_theme->stylesheet ]->update['new_version']; 1166 1167 /* translators: %s: Latest theme version number. */ 1168 $active_theme_version .= ' ' . sprintf( __( '(Latest version: %s)' ), $theme_update_new_version ); 1169 $active_theme_version_debug .= sprintf( ' (latest version: %s)', $theme_update_new_version ); 1170 } 1171 1172 $active_theme_author_uri = $active_theme->display( 'AuthorURI' ); 1173 1174 if ( $active_theme->parent_theme ) { 1175 $active_theme_parent_theme = sprintf( 1176 /* translators: 1: Theme name. 2: Theme slug. */ 1177 __( '%1$s (%2$s)' ), 1178 $active_theme->parent_theme, 1179 $active_theme->template 1180 ); 1181 $active_theme_parent_theme_debug = sprintf( 1182 '%s (%s)', 1183 $active_theme->parent_theme, 1184 $active_theme->template 1185 ); 1186 } else { 1187 $active_theme_parent_theme = __( 'None' ); 1188 $active_theme_parent_theme_debug = 'none'; 1189 } 1190 1191 $fields = array( 1192 'name' => array( 1193 'label' => __( 'Name' ), 1194 'value' => sprintf( 1195 /* translators: 1: Theme name. 2: Theme slug. */ 1196 __( '%1$s (%2$s)' ), 1197 $active_theme->name, 1198 $active_theme->stylesheet 1199 ), 1200 ), 1201 'version' => array( 1202 'label' => __( 'Version' ), 1203 'value' => $active_theme_version, 1204 'debug' => $active_theme_version_debug, 1205 ), 1206 'author' => array( 1207 'label' => __( 'Author' ), 1208 'value' => wp_kses( $active_theme->author, array() ), 1209 ), 1210 'author_website' => array( 1211 'label' => __( 'Author website' ), 1212 'value' => ( $active_theme_author_uri ? $active_theme_author_uri : __( 'Undefined' ) ), 1213 'debug' => ( $active_theme_author_uri ? $active_theme_author_uri : '(undefined)' ), 1214 ), 1215 'parent_theme' => array( 1216 'label' => __( 'Parent theme' ), 1217 'value' => $active_theme_parent_theme, 1218 'debug' => $active_theme_parent_theme_debug, 1219 ), 1220 'theme_features' => array( 1221 'label' => __( 'Theme features' ), 1222 'value' => implode( ', ', $theme_features ), 1223 ), 1224 'theme_path' => array( 1225 'label' => __( 'Theme directory location' ), 1226 'value' => get_stylesheet_directory(), 1227 ), 1228 ); 1229 1230 if ( $auto_updates_enabled ) { 1231 if ( isset( $transient->response[ $active_theme->stylesheet ] ) ) { 1232 $item = $transient->response[ $active_theme->stylesheet ]; 1233 } elseif ( isset( $transient->no_update[ $active_theme->stylesheet ] ) ) { 1234 $item = $transient->no_update[ $active_theme->stylesheet ]; 1235 } else { 1236 $item = array( 1237 'theme' => $active_theme->stylesheet, 1238 'new_version' => $active_theme->version, 1239 'url' => '', 1240 'package' => '', 1241 'requires' => '', 1242 'requires_php' => '', 1243 ); 1244 } 1245 1246 $auto_update_forced = wp_is_auto_update_forced_for_item( 'theme', null, (object) $item ); 1247 1248 if ( ! is_null( $auto_update_forced ) ) { 1249 $enabled = $auto_update_forced; 1250 } else { 1251 $enabled = in_array( $active_theme->stylesheet, $auto_updates, true ); 1252 } 1253 1254 if ( $enabled ) { 1255 $auto_updates_string = __( 'Enabled' ); 1256 } else { 1257 $auto_updates_string = __( 'Disabled' ); 1258 } 1259 1260 /** This filter is documented in wp-admin/includes/class-wp-debug-data.php */ 1261 $auto_updates_string = apply_filters( 'theme_auto_update_debug_string', $auto_updates_string, $active_theme, $enabled ); 1262 1263 $fields['auto_update'] = array( 1264 'label' => __( 'Auto-updates' ), 1265 'value' => $auto_updates_string, 1266 'debug' => $auto_updates_string, 1267 ); 1268 } 1269 1270 return array( 1271 'label' => __( 'Active Theme' ), 1272 'fields' => $fields, 1273 ); 1274 } 1275 1276 /** 1277 * Gets the WordPress parent theme section of the debug data. 1278 * 1279 * @since 6.7.0 1280 * 1281 * @return array<string, string|array> The parent theme debug data. 1282 */ 1283 private static function get_wp_parent_theme(): array { 1284 $theme_updates = get_theme_updates(); 1285 $transient = get_site_transient( 'update_themes' ); 1286 1287 $auto_updates = array(); 1288 $auto_updates_enabled = wp_is_auto_update_enabled_for_type( 'theme' ); 1289 if ( $auto_updates_enabled ) { 1290 $auto_updates = (array) get_site_option( 'auto_update_themes', array() ); 1291 } 1292 1293 $active_theme = wp_get_theme(); 1294 $parent_theme = $active_theme->parent(); 1295 $fields = array(); 1296 1297 if ( $parent_theme ) { 1298 $parent_theme_version = $parent_theme->version; 1299 $parent_theme_version_debug = $parent_theme_version; 1300 1301 if ( array_key_exists( $parent_theme->stylesheet, $theme_updates ) ) { 1302 $parent_theme_update_new_version = $theme_updates[ $parent_theme->stylesheet ]->update['new_version']; 1303 1304 /* translators: %s: Latest theme version number. */ 1305 $parent_theme_version .= ' ' . sprintf( __( '(Latest version: %s)' ), $parent_theme_update_new_version ); 1306 $parent_theme_version_debug .= sprintf( ' (latest version: %s)', $parent_theme_update_new_version ); 1307 } 1308 1309 $parent_theme_author_uri = $parent_theme->display( 'AuthorURI' ); 1310 1311 $fields = array( 1312 'name' => array( 1313 'label' => __( 'Name' ), 1314 'value' => sprintf( 1315 /* translators: 1: Theme name. 2: Theme slug. */ 1316 __( '%1$s (%2$s)' ), 1317 $parent_theme->name, 1318 $parent_theme->stylesheet 1319 ), 1320 ), 1321 'version' => array( 1322 'label' => __( 'Version' ), 1323 'value' => $parent_theme_version, 1324 'debug' => $parent_theme_version_debug, 1325 ), 1326 'author' => array( 1327 'label' => __( 'Author' ), 1328 'value' => wp_kses( $parent_theme->author, array() ), 1329 ), 1330 'author_website' => array( 1331 'label' => __( 'Author website' ), 1332 'value' => ( $parent_theme_author_uri ? $parent_theme_author_uri : __( 'Undefined' ) ), 1333 'debug' => ( $parent_theme_author_uri ? $parent_theme_author_uri : '(undefined)' ), 1334 ), 1335 'theme_path' => array( 1336 'label' => __( 'Theme directory location' ), 1337 'value' => get_template_directory(), 1338 ), 1339 ); 1340 1341 if ( $auto_updates_enabled ) { 1342 if ( isset( $transient->response[ $parent_theme->stylesheet ] ) ) { 1343 $item = $transient->response[ $parent_theme->stylesheet ]; 1344 } elseif ( isset( $transient->no_update[ $parent_theme->stylesheet ] ) ) { 1345 $item = $transient->no_update[ $parent_theme->stylesheet ]; 1346 } else { 1347 $item = array( 1348 'theme' => $parent_theme->stylesheet, 1349 'new_version' => $parent_theme->version, 1350 'url' => '', 1351 'package' => '', 1352 'requires' => '', 1353 'requires_php' => '', 1354 ); 1355 } 1356 1357 $auto_update_forced = wp_is_auto_update_forced_for_item( 'theme', null, (object) $item ); 1358 1359 if ( ! is_null( $auto_update_forced ) ) { 1360 $enabled = $auto_update_forced; 1361 } else { 1362 $enabled = in_array( $parent_theme->stylesheet, $auto_updates, true ); 1363 } 1364 1365 if ( $enabled ) { 1366 $parent_theme_auto_update_string = __( 'Enabled' ); 1367 } else { 1368 $parent_theme_auto_update_string = __( 'Disabled' ); 1369 } 1370 1371 /** This filter is documented in wp-admin/includes/class-wp-debug-data.php */ 1372 $parent_theme_auto_update_string = apply_filters( 'theme_auto_update_debug_string', $parent_theme_auto_update_string, $parent_theme, $enabled ); 1373 1374 $fields['auto_update'] = array( 1375 'label' => __( 'Auto-update' ), 1376 'value' => $parent_theme_auto_update_string, 1377 'debug' => $parent_theme_auto_update_string, 1378 ); 1379 } 1380 } 1381 1382 return array( 1383 'label' => __( 'Parent Theme' ), 1384 'fields' => $fields, 1385 ); 1386 } 1387 1388 /** 1389 * Gets the WordPress inactive themes section of the debug data. 1390 * 1391 * @since 6.7.0 1392 * 1393 * @return array<string, string|bool|array> The inactive themes debug data. 1394 */ 1395 private static function get_wp_themes_inactive(): array { 1396 $active_theme = wp_get_theme(); 1397 $parent_theme = $active_theme->parent(); 1398 $theme_updates = get_theme_updates(); 1399 $transient = get_site_transient( 'update_themes' ); 1400 1401 $auto_updates = array(); 1402 $auto_updates_enabled = wp_is_auto_update_enabled_for_type( 'theme' ); 1403 if ( $auto_updates_enabled ) { 1404 $auto_updates = (array) get_site_option( 'auto_update_themes', array() ); 1405 } 1406 1407 // Populate a list of all themes available in the installation. 1408 $all_themes = wp_get_themes(); 1409 $fields = array(); 1410 1411 foreach ( $all_themes as $theme_slug => $theme ) { 1412 // Exclude the currently active theme from the list of all themes. 1413 if ( $active_theme->stylesheet === $theme_slug ) { 1414 continue; 1415 } 1416 1417 // Exclude the currently active parent theme from the list of all themes. 1418 if ( ! empty( $parent_theme ) && $parent_theme->stylesheet === $theme_slug ) { 1419 continue; 1420 } 1421 1422 $theme_version = $theme->version; 1423 $theme_author = $theme->author; 1424 1425 // Sanitize. 1426 $theme_author = wp_kses( $theme_author, array() ); 1427 1428 $theme_version_string = __( 'No version or author information is available.' ); 1429 $theme_version_string_debug = 'undefined'; 1430 1431 if ( ! empty( $theme_version ) && ! empty( $theme_author ) ) { 1432 /* translators: 1: Theme version number. 2: Theme author name. */ 1433 $theme_version_string = sprintf( __( 'Version %1$s by %2$s' ), $theme_version, $theme_author ); 1434 $theme_version_string_debug = sprintf( 'version: %s, author: %s', $theme_version, $theme_author ); 1435 } else { 1436 if ( ! empty( $theme_author ) ) { 1437 /* translators: %s: Theme author name. */ 1438 $theme_version_string = sprintf( __( 'By %s' ), $theme_author ); 1439 $theme_version_string_debug = sprintf( 'author: %s, version: (undefined)', $theme_author ); 1440 } 1441 1442 if ( ! empty( $theme_version ) ) { 1443 /* translators: %s: Theme version number. */ 1444 $theme_version_string = sprintf( __( 'Version %s' ), $theme_version ); 1445 $theme_version_string_debug = sprintf( 'author: (undefined), version: %s', $theme_version ); 1446 } 1447 } 1448 1449 if ( array_key_exists( $theme_slug, $theme_updates ) ) { 1450 /* translators: %s: Latest theme version number. */ 1451 $theme_version_string .= ' ' . sprintf( __( '(Latest version: %s)' ), $theme_updates[ $theme_slug ]->update['new_version'] ); 1452 $theme_version_string_debug .= sprintf( ' (latest version: %s)', $theme_updates[ $theme_slug ]->update['new_version'] ); 1453 } 1454 1455 if ( $auto_updates_enabled ) { 1456 if ( isset( $transient->response[ $theme_slug ] ) ) { 1457 $item = $transient->response[ $theme_slug ]; 1458 } elseif ( isset( $transient->no_update[ $theme_slug ] ) ) { 1459 $item = $transient->no_update[ $theme_slug ]; 1460 } else { 1461 $item = array( 1462 'theme' => $theme_slug, 1463 'new_version' => $theme->version, 1464 'url' => '', 1465 'package' => '', 1466 'requires' => '', 1467 'requires_php' => '', 1468 ); 1469 } 1470 1471 $auto_update_forced = wp_is_auto_update_forced_for_item( 'theme', null, (object) $item ); 1472 1473 if ( ! is_null( $auto_update_forced ) ) { 1474 $enabled = $auto_update_forced; 1475 } else { 1476 $enabled = in_array( $theme_slug, $auto_updates, true ); 1477 } 1478 1479 if ( $enabled ) { 1480 $auto_updates_string = __( 'Auto-updates enabled' ); 1481 } else { 1482 $auto_updates_string = __( 'Auto-updates disabled' ); 1483 } 1484 1485 /** 1486 * Filters the text string of the auto-updates setting for each theme in the Site Health debug data. 1487 * 1488 * @since 5.5.0 1489 * 1490 * @param string $auto_updates_string The string output for the auto-updates column. 1491 * @param WP_Theme $theme An object of theme data. 1492 * @param bool $enabled Whether auto-updates are enabled for this item. 1493 */ 1494 $auto_updates_string = apply_filters( 'theme_auto_update_debug_string', $auto_updates_string, $theme, $enabled ); 1495 1496 $theme_version_string .= ' | ' . $auto_updates_string; 1497 $theme_version_string_debug .= ', ' . $auto_updates_string; 1498 } 1499 1500 $fields[ sanitize_text_field( $theme->name ) ] = array( 1501 'label' => sprintf( 1502 /* translators: 1: Theme name. 2: Theme slug. */ 1503 __( '%1$s (%2$s)' ), 1504 $theme->name, 1505 $theme_slug 1506 ), 1507 'value' => $theme_version_string, 1508 'debug' => $theme_version_string_debug, 1509 ); 1510 } 1511 1512 return array( 1513 'label' => __( 'Inactive Themes' ), 1514 'show_count' => true, 1515 'fields' => $fields, 1516 ); 1517 } 1518 1519 /** 1520 * Gets the WordPress constants section of the debug data. 1521 * 1522 * @since 6.7.0 1523 * 1524 * @return array<string, string|array> The WordPress constants debug data. 1525 */ 1526 private static function get_wp_constants(): array { 1527 // Check if WP_DEBUG_LOG is set. 1528 $wp_debug_log_value = __( 'Disabled' ); 1529 if ( is_string( WP_DEBUG_LOG ) ) { 1530 $wp_debug_log_value = WP_DEBUG_LOG; 1531 } elseif ( WP_DEBUG_LOG ) { 1532 $wp_debug_log_value = __( 'Enabled' ); 1533 } 1534 1535 // Check CONCATENATE_SCRIPTS. 1536 if ( defined( 'CONCATENATE_SCRIPTS' ) ) { 1537 $concatenate_scripts = CONCATENATE_SCRIPTS ? __( 'Enabled' ) : __( 'Disabled' ); 1538 $concatenate_scripts_debug = CONCATENATE_SCRIPTS ? 'true' : 'false'; 1539 } else { 1540 $concatenate_scripts = __( 'Undefined' ); 1541 $concatenate_scripts_debug = 'undefined'; 1542 } 1543 1544 // Check COMPRESS_SCRIPTS. 1545 if ( defined( 'COMPRESS_SCRIPTS' ) ) { 1546 $compress_scripts = COMPRESS_SCRIPTS ? __( 'Enabled' ) : __( 'Disabled' ); 1547 $compress_scripts_debug = COMPRESS_SCRIPTS ? 'true' : 'false'; 1548 } else { 1549 $compress_scripts = __( 'Undefined' ); 1550 $compress_scripts_debug = 'undefined'; 1551 } 1552 1553 // Check COMPRESS_CSS. 1554 if ( defined( 'COMPRESS_CSS' ) ) { 1555 $compress_css = COMPRESS_CSS ? __( 'Enabled' ) : __( 'Disabled' ); 1556 $compress_css_debug = COMPRESS_CSS ? 'true' : 'false'; 1557 } else { 1558 $compress_css = __( 'Undefined' ); 1559 $compress_css_debug = 'undefined'; 1560 } 1561 1562 // Check WP_ENVIRONMENT_TYPE. 1563 if ( defined( 'WP_ENVIRONMENT_TYPE' ) ) { 1564 $wp_environment_type = WP_ENVIRONMENT_TYPE ? WP_ENVIRONMENT_TYPE : __( 'Empty value' ); 1565 $wp_environment_type_debug = WP_ENVIRONMENT_TYPE; 1566 } else { 1567 $wp_environment_type = __( 'Undefined' ); 1568 $wp_environment_type_debug = 'undefined'; 1569 } 1570 1571 // Check DB_COLLATE. 1572 if ( defined( 'DB_COLLATE' ) ) { 1573 $db_collate = DB_COLLATE ? DB_COLLATE : __( 'Empty value' ); 1574 $db_collate_debug = DB_COLLATE; 1575 } else { 1576 $db_collate = __( 'Undefined' ); 1577 $db_collate_debug = 'undefined'; 1578 } 1579 1580 $fields = array( 1581 'ABSPATH' => array( 1582 'label' => 'ABSPATH', 1583 'value' => ABSPATH, 1584 'private' => true, 1585 ), 1586 'WP_HOME' => array( 1587 'label' => 'WP_HOME', 1588 'value' => ( defined( 'WP_HOME' ) ? WP_HOME : __( 'Undefined' ) ), 1589 'debug' => ( defined( 'WP_HOME' ) ? WP_HOME : 'undefined' ), 1590 ), 1591 'WP_SITEURL' => array( 1592 'label' => 'WP_SITEURL', 1593 'value' => ( defined( 'WP_SITEURL' ) ? WP_SITEURL : __( 'Undefined' ) ), 1594 'debug' => ( defined( 'WP_SITEURL' ) ? WP_SITEURL : 'undefined' ), 1595 ), 1596 'WP_CONTENT_DIR' => array( 1597 'label' => 'WP_CONTENT_DIR', 1598 'value' => WP_CONTENT_DIR, 1599 ), 1600 'WP_PLUGIN_DIR' => array( 1601 'label' => 'WP_PLUGIN_DIR', 1602 'value' => WP_PLUGIN_DIR, 1603 ), 1604 'WP_MEMORY_LIMIT' => array( 1605 'label' => 'WP_MEMORY_LIMIT', 1606 'value' => WP_MEMORY_LIMIT, 1607 ), 1608 'WP_MAX_MEMORY_LIMIT' => array( 1609 'label' => 'WP_MAX_MEMORY_LIMIT', 1610 'value' => WP_MAX_MEMORY_LIMIT, 1611 ), 1612 'WP_DEBUG' => array( 1613 'label' => 'WP_DEBUG', 1614 'value' => WP_DEBUG ? __( 'Enabled' ) : __( 'Disabled' ), 1615 'debug' => WP_DEBUG, 1616 ), 1617 'WP_DEBUG_DISPLAY' => array( 1618 'label' => 'WP_DEBUG_DISPLAY', 1619 'value' => WP_DEBUG_DISPLAY ? __( 'Enabled' ) : __( 'Disabled' ), 1620 'debug' => WP_DEBUG_DISPLAY, 1621 ), 1622 'WP_DEBUG_LOG' => array( 1623 'label' => 'WP_DEBUG_LOG', 1624 'value' => $wp_debug_log_value, 1625 'debug' => WP_DEBUG_LOG, 1626 ), 1627 'SCRIPT_DEBUG' => array( 1628 'label' => 'SCRIPT_DEBUG', 1629 'value' => SCRIPT_DEBUG ? __( 'Enabled' ) : __( 'Disabled' ), 1630 'debug' => SCRIPT_DEBUG, 1631 ), 1632 'WP_CACHE' => array( 1633 'label' => 'WP_CACHE', 1634 'value' => WP_CACHE ? __( 'Enabled' ) : __( 'Disabled' ), 1635 'debug' => WP_CACHE, 1636 ), 1637 'CONCATENATE_SCRIPTS' => array( 1638 'label' => 'CONCATENATE_SCRIPTS', 1639 'value' => $concatenate_scripts, 1640 'debug' => $concatenate_scripts_debug, 1641 ), 1642 'COMPRESS_SCRIPTS' => array( 1643 'label' => 'COMPRESS_SCRIPTS', 1644 'value' => $compress_scripts, 1645 'debug' => $compress_scripts_debug, 1646 ), 1647 'COMPRESS_CSS' => array( 1648 'label' => 'COMPRESS_CSS', 1649 'value' => $compress_css, 1650 'debug' => $compress_css_debug, 1651 ), 1652 'WP_ENVIRONMENT_TYPE' => array( 1653 'label' => 'WP_ENVIRONMENT_TYPE', 1654 'value' => $wp_environment_type, 1655 'debug' => $wp_environment_type_debug, 1656 ), 1657 'WP_DEVELOPMENT_MODE' => array( 1658 'label' => 'WP_DEVELOPMENT_MODE', 1659 'value' => WP_DEVELOPMENT_MODE ? WP_DEVELOPMENT_MODE : __( 'Disabled' ), 1660 'debug' => WP_DEVELOPMENT_MODE, 1661 ), 1662 'DB_CHARSET' => array( 1663 'label' => 'DB_CHARSET', 1664 'value' => ( defined( 'DB_CHARSET' ) ? DB_CHARSET : __( 'Undefined' ) ), 1665 'debug' => ( defined( 'DB_CHARSET' ) ? DB_CHARSET : 'undefined' ), 1666 ), 1667 'DB_COLLATE' => array( 1668 'label' => 'DB_COLLATE', 1669 'value' => $db_collate, 1670 'debug' => $db_collate_debug, 1671 ), 1672 'EMPTY_TRASH_DAYS' => array( 1673 'label' => 'EMPTY_TRASH_DAYS', 1674 'value' => EMPTY_TRASH_DAYS ? EMPTY_TRASH_DAYS : __( 'Empty value' ), 1675 'debug' => EMPTY_TRASH_DAYS, 1676 ), 1677 ); 1678 1679 return array( 1680 'label' => __( 'WordPress Constants' ), 1681 'description' => __( 'These settings alter where and how parts of WordPress are loaded.' ), 1682 'fields' => $fields, 1683 ); 1684 } 1685 1686 /** 1687 * Gets the WordPress database section of the debug data. 1688 * 1689 * @since 6.7.0 1690 * 1691 * @global wpdb $wpdb WordPress database abstraction object. 1692 * 1693 * @return array<string, string|array> The database debug data. 1694 */ 1695 private static function get_wp_database(): array { 1696 global $wpdb; 1697 1698 // Populate the database debug fields. 1699 if ( is_object( $wpdb->dbh ) ) { 1700 // mysqli or PDO. 1701 $extension = get_class( $wpdb->dbh ); 1702 } else { 1703 // Unknown sql extension. 1704 $extension = null; 1705 } 1706 1707 $server = $wpdb->get_var( 'SELECT VERSION()' ); 1708 1709 $client_version = $wpdb->dbh->client_info; 1710 1711 $fields = array( 1712 'extension' => array( 1713 'label' => __( 'Database Extension' ), 1714 'value' => $extension, 1715 ), 1716 'server_version' => array( 1717 'label' => __( 'Server version' ), 1718 'value' => $server, 1719 ), 1720 'client_version' => array( 1721 'label' => __( 'Client version' ), 1722 'value' => $client_version, 1723 ), 1724 'database_user' => array( 1725 'label' => __( 'Database username' ), 1726 'value' => $wpdb->dbuser, 1727 'private' => true, 1728 ), 1729 'database_host' => array( 1730 'label' => __( 'Database host' ), 1731 'value' => $wpdb->dbhost, 1732 'private' => true, 1733 ), 1734 'database_name' => array( 1735 'label' => __( 'Database name' ), 1736 'value' => $wpdb->dbname, 1737 'private' => true, 1738 ), 1739 'database_prefix' => array( 1740 'label' => __( 'Table prefix' ), 1741 'value' => $wpdb->prefix, 1742 'private' => true, 1743 ), 1744 'database_charset' => array( 1745 'label' => __( 'Database charset' ), 1746 'value' => $wpdb->charset, 1747 'private' => true, 1748 ), 1749 'database_collate' => array( 1750 'label' => __( 'Database collation' ), 1751 'value' => $wpdb->collate, 1752 'private' => true, 1753 ), 1754 'max_allowed_packet' => array( 1755 'label' => __( 'Max allowed packet size' ), 1756 'value' => self::get_mysql_var( 'max_allowed_packet' ), 1757 ), 1758 'max_connections' => array( 1759 'label' => __( 'Max connections number' ), 1760 'value' => self::get_mysql_var( 'max_connections' ), 1761 ), 1762 ); 1763 1764 return array( 1765 'label' => __( 'Database' ), 1766 'fields' => $fields, 1767 ); 1768 } 1769 1770 /** 1771 * Gets the file system section of the debug data. 1772 * 1773 * @since 6.7.0 1774 * 1775 * @return array<string, string|array> The debug data and other information for the Info screen. 1776 */ 1777 private static function get_wp_filesystem(): array { 1778 $upload_dir = wp_upload_dir(); 1779 $fonts_dir_exists = file_exists( wp_get_font_dir()['basedir'] ); 1780 $is_writable_abspath = wp_is_writable( ABSPATH ); 1781 $is_writable_wp_content_dir = wp_is_writable( WP_CONTENT_DIR ); 1782 $is_writable_upload_dir = wp_is_writable( $upload_dir['basedir'] ); 1783 $is_writable_wp_plugin_dir = wp_is_writable( WP_PLUGIN_DIR ); 1784 $is_writable_template_directory = wp_is_writable( get_theme_root( get_template() ) ); 1785 $is_writable_fonts_dir = $fonts_dir_exists ? wp_is_writable( wp_get_font_dir()['basedir'] ) : false; 1786 1787 $fields = array( 1788 'wordpress' => array( 1789 'label' => __( 'The main WordPress directory' ), 1790 'value' => ( $is_writable_abspath ? __( 'Writable' ) : __( 'Not writable' ) ), 1791 'debug' => ( $is_writable_abspath ? 'writable' : 'not writable' ), 1792 ), 1793 'wp-content' => array( 1794 'label' => __( 'The wp-content directory' ), 1795 'value' => ( $is_writable_wp_content_dir ? __( 'Writable' ) : __( 'Not writable' ) ), 1796 'debug' => ( $is_writable_wp_content_dir ? 'writable' : 'not writable' ), 1797 ), 1798 'uploads' => array( 1799 'label' => __( 'The uploads directory' ), 1800 'value' => ( $is_writable_upload_dir ? __( 'Writable' ) : __( 'Not writable' ) ), 1801 'debug' => ( $is_writable_upload_dir ? 'writable' : 'not writable' ), 1802 ), 1803 'plugins' => array( 1804 'label' => __( 'The plugins directory' ), 1805 'value' => ( $is_writable_wp_plugin_dir ? __( 'Writable' ) : __( 'Not writable' ) ), 1806 'debug' => ( $is_writable_wp_plugin_dir ? 'writable' : 'not writable' ), 1807 ), 1808 'themes' => array( 1809 'label' => __( 'The themes directory' ), 1810 'value' => ( $is_writable_template_directory ? __( 'Writable' ) : __( 'Not writable' ) ), 1811 'debug' => ( $is_writable_template_directory ? 'writable' : 'not writable' ), 1812 ), 1813 'fonts' => array( 1814 'label' => __( 'The fonts directory' ), 1815 'value' => $fonts_dir_exists 1816 ? ( $is_writable_fonts_dir ? __( 'Writable' ) : __( 'Not writable' ) ) 1817 : __( 'Does not exist' ), 1818 'debug' => $fonts_dir_exists 1819 ? ( $is_writable_fonts_dir ? 'writable' : 'not writable' ) 1820 : 'does not exist', 1821 ), 1822 ); 1823 1824 // Add more filesystem checks. 1825 if ( defined( 'WPMU_PLUGIN_DIR' ) && is_dir( WPMU_PLUGIN_DIR ) ) { 1826 $is_writable_wpmu_plugin_dir = wp_is_writable( WPMU_PLUGIN_DIR ); 1827 1828 $fields['mu-plugins'] = array( 1829 'label' => __( 'The must use plugins directory' ), 1830 'value' => ( $is_writable_wpmu_plugin_dir ? __( 'Writable' ) : __( 'Not writable' ) ), 1831 'debug' => ( $is_writable_wpmu_plugin_dir ? 'writable' : 'not writable' ), 1832 ); 1833 } 1834 1835 return array( 1836 'label' => __( 'Filesystem Permissions' ), 1837 'description' => __( 'Shows whether WordPress is able to write to the directories it needs access to.' ), 1838 'fields' => $fields, 1839 ); 1840 } 1841 1842 /** 1843 * Returns the value of a MySQL system variable. 1844 * 1845 * @since 5.9.0 1846 * 1847 * @global wpdb $wpdb WordPress database abstraction object. 1848 * 1849 * @param string $mysql_var Name of the MySQL system variable. 1850 * @return string|null The variable value on success. Null if the variable does not exist. 1851 */ 1852 public static function get_mysql_var( $mysql_var ) { 1853 global $wpdb; 1854 1855 $result = $wpdb->get_row( 1856 $wpdb->prepare( 'SHOW VARIABLES LIKE %s', $mysql_var ), 1857 ARRAY_A 1858 ); 1859 1860 if ( ! empty( $result ) && array_key_exists( 'Value', $result ) ) { 1861 return $result['Value']; 1862 } 1863 1864 return null; 1865 } 1866 1867 /** 1868 * Formats the information gathered for debugging, in a manner suitable for copying to a forum or support ticket. 1869 * 1870 * @since 5.2.0 1871 * 1872 * @param array $info_array Information gathered from the `WP_Debug_Data::debug_data()` function. 1873 * @param string $data_type The data type to return, either 'info' or 'debug'. 1874 * @return string The formatted data. 1875 */ 1876 public static function format( $info_array, $data_type ) { 1877 $return = "`\n"; 1878 1879 foreach ( $info_array as $section => $details ) { 1880 // Skip this section if there are no fields, or the section has been declared as private. 1881 if ( empty( $details['fields'] ) || ( isset( $details['private'] ) && $details['private'] ) ) { 1882 continue; 1883 } 1884 1885 $section_label = 'debug' === $data_type ? $section : $details['label']; 1886 1887 $return .= sprintf( 1888 "### %s%s ###\n\n", 1889 $section_label, 1890 ( isset( $details['show_count'] ) && $details['show_count'] ? sprintf( ' (%d)', count( $details['fields'] ) ) : '' ) 1891 ); 1892 1893 foreach ( $details['fields'] as $field_name => $field ) { 1894 if ( isset( $field['private'] ) && true === $field['private'] ) { 1895 continue; 1896 } 1897 1898 if ( 'debug' === $data_type && isset( $field['debug'] ) ) { 1899 $debug_data = $field['debug']; 1900 } else { 1901 $debug_data = $field['value']; 1902 } 1903 1904 // Can be array, one level deep only. 1905 if ( is_array( $debug_data ) ) { 1906 $value = ''; 1907 1908 foreach ( $debug_data as $sub_field_name => $sub_field_value ) { 1909 $value .= sprintf( "\n\t%s: %s", $sub_field_name, $sub_field_value ); 1910 } 1911 } elseif ( is_bool( $debug_data ) ) { 1912 $value = $debug_data ? 'true' : 'false'; 1913 } elseif ( empty( $debug_data ) && '0' !== $debug_data ) { 1914 $value = 'undefined'; 1915 } else { 1916 $value = $debug_data; 1917 } 1918 1919 if ( 'debug' === $data_type ) { 1920 $label = $field_name; 1921 } else { 1922 $label = $field['label']; 1923 } 1924 1925 $return .= sprintf( "%s: %s\n", $label, $value ); 1926 } 1927 1928 $return .= "\n"; 1929 } 1930 1931 $return .= '`'; 1932 1933 return $return; 1934 } 1935 1936 /** 1937 * Fetches the total size of all the database tables for the active database user. 1938 * 1939 * @since 5.2.0 1940 * 1941 * @global wpdb $wpdb WordPress database abstraction object. 1942 * 1943 * @return int The size of the database, in bytes. 1944 */ 1945 public static function get_database_size() { 1946 global $wpdb; 1947 $size = 0; 1948 $rows = $wpdb->get_results( 'SHOW TABLE STATUS', ARRAY_A ); 1949 1950 if ( $wpdb->num_rows > 0 ) { 1951 foreach ( $rows as $row ) { 1952 $size += $row['Data_length'] + $row['Index_length']; 1953 } 1954 } 1955 1956 return (int) $size; 1957 } 1958 1959 /** 1960 * Fetches the sizes of the WordPress directories: `wordpress` (ABSPATH), `plugins`, `themes`, and `uploads`. 1961 * Intended to supplement the array returned by `WP_Debug_Data::debug_data()`. 1962 * 1963 * @since 5.2.0 1964 * @deprecated 5.6.0 Use WP_REST_Site_Health_Controller::get_directory_sizes() 1965 * @see WP_REST_Site_Health_Controller::get_directory_sizes() 1966 * 1967 * @return array The sizes of the directories, also the database size and total installation size. 1968 */ 1969 public static function get_sizes() { 1970 _deprecated_function( __METHOD__, '5.6.0', 'WP_REST_Site_Health_Controller::get_directory_sizes()' ); 1971 1972 $size_db = self::get_database_size(); 1973 $upload_dir = wp_get_upload_dir(); 1974 1975 /* 1976 * We will be using the PHP max execution time to prevent the size calculations 1977 * from causing a timeout. The default value is 30 seconds, and some 1978 * hosts do not allow you to read configuration values. 1979 */ 1980 if ( function_exists( 'ini_get' ) ) { 1981 $max_execution_time = ini_get( 'max_execution_time' ); 1982 } 1983 1984 /* 1985 * The max_execution_time defaults to 0 when PHP runs from cli. 1986 * We still want to limit it below. 1987 */ 1988 if ( empty( $max_execution_time ) ) { 1989 $max_execution_time = 30; // 30 seconds. 1990 } 1991 1992 if ( $max_execution_time > 20 ) { 1993 /* 1994 * If the max_execution_time is set to lower than 20 seconds, reduce it a bit to prevent 1995 * edge-case timeouts that may happen after the size loop has finished running. 1996 */ 1997 $max_execution_time -= 2; 1998 } 1999 2000 /* 2001 * Go through the various installation directories and calculate their sizes. 2002 * No trailing slashes. 2003 */ 2004 $paths = array( 2005 'wordpress_size' => untrailingslashit( ABSPATH ), 2006 'themes_size' => get_theme_root(), 2007 'plugins_size' => WP_PLUGIN_DIR, 2008 'uploads_size' => $upload_dir['basedir'], 2009 'fonts_size' => wp_get_font_dir()['basedir'], 2010 ); 2011 2012 $exclude = $paths; 2013 unset( $exclude['wordpress_size'] ); 2014 $exclude = array_values( $exclude ); 2015 2016 $size_total = 0; 2017 $all_sizes = array(); 2018 2019 // Loop over all the directories we want to gather the sizes for. 2020 foreach ( $paths as $name => $path ) { 2021 $dir_size = null; // Default to timeout. 2022 $results = array( 2023 'path' => $path, 2024 'raw' => 0, 2025 ); 2026 2027 // If the directory does not exist, skip checking it, as it will skew the other results. 2028 if ( ! is_dir( $path ) ) { 2029 $all_sizes[ $name ] = array( 2030 'path' => $path, 2031 'raw' => 0, 2032 'size' => __( 'The directory does not exist.' ), 2033 'debug' => 'directory not found', 2034 ); 2035 2036 continue; 2037 } 2038 2039 if ( microtime( true ) - WP_START_TIMESTAMP < $max_execution_time ) { 2040 if ( 'wordpress_size' === $name ) { 2041 $dir_size = recurse_dirsize( $path, $exclude, $max_execution_time ); 2042 } else { 2043 $dir_size = recurse_dirsize( $path, null, $max_execution_time ); 2044 } 2045 } 2046 2047 if ( false === $dir_size ) { 2048 // Error reading. 2049 $results['size'] = __( 'The size cannot be calculated. The directory is not accessible. Usually caused by invalid permissions.' ); 2050 $results['debug'] = 'not accessible'; 2051 2052 // Stop total size calculation. 2053 $size_total = null; 2054 } elseif ( null === $dir_size ) { 2055 // Timeout. 2056 $results['size'] = __( 'The directory size calculation has timed out. Usually caused by a very large number of sub-directories and files.' ); 2057 $results['debug'] = 'timeout while calculating size'; 2058 2059 // Stop total size calculation. 2060 $size_total = null; 2061 } else { 2062 if ( null !== $size_total ) { 2063 $size_total += $dir_size; 2064 } 2065 2066 $results['raw'] = $dir_size; 2067 $results['size'] = size_format( $dir_size, 2 ); 2068 $results['debug'] = $results['size'] . " ({$dir_size} bytes)"; 2069 } 2070 2071 $all_sizes[ $name ] = $results; 2072 } 2073 2074 if ( $size_db > 0 ) { 2075 $database_size = size_format( $size_db, 2 ); 2076 2077 $all_sizes['database_size'] = array( 2078 'raw' => $size_db, 2079 'size' => $database_size, 2080 'debug' => $database_size . " ({$size_db} bytes)", 2081 ); 2082 } else { 2083 $all_sizes['database_size'] = array( 2084 'size' => __( 'Not available' ), 2085 'debug' => 'not available', 2086 ); 2087 } 2088 2089 if ( null !== $size_total && $size_db > 0 ) { 2090 $total_size = $size_total + $size_db; 2091 $total_size_mb = size_format( $total_size, 2 ); 2092 2093 $all_sizes['total_size'] = array( 2094 'raw' => $total_size, 2095 'size' => $total_size_mb, 2096 'debug' => $total_size_mb . " ({$total_size} bytes)", 2097 ); 2098 } else { 2099 $all_sizes['total_size'] = array( 2100 'size' => __( 'Total size is not available. Some errors were encountered when determining the size of your installation.' ), 2101 'debug' => 'not available', 2102 ); 2103 } 2104 2105 return $all_sizes; 2106 } 2107 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body
| Generated : Thu May 7 08:20:02 2026 | Cross-referenced by PHPXref |