| [ 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 $fields['max_input_variables'] = array( 391 'label' => __( 'PHP max input variables' ), 392 'value' => ini_get( 'max_input_vars' ), 393 ); 394 $fields['time_limit'] = array( 395 'label' => __( 'PHP time limit' ), 396 'value' => ini_get( 'max_execution_time' ), 397 ); 398 399 if ( WP_Site_Health::get_instance()->php_memory_limit !== ini_get( 'memory_limit' ) ) { 400 $fields['memory_limit'] = array( 401 'label' => __( 'PHP memory limit' ), 402 'value' => WP_Site_Health::get_instance()->php_memory_limit, 403 ); 404 $fields['admin_memory_limit'] = array( 405 'label' => __( 'PHP memory limit (only for admin screens)' ), 406 'value' => ini_get( 'memory_limit' ), 407 ); 408 } else { 409 $fields['memory_limit'] = array( 410 'label' => __( 'PHP memory limit' ), 411 'value' => ini_get( 'memory_limit' ), 412 ); 413 } 414 415 $fields['max_input_time'] = array( 416 'label' => __( 'Max input time' ), 417 'value' => ini_get( 'max_input_time' ), 418 ); 419 $fields['upload_max_filesize'] = array( 420 'label' => __( 'Upload max filesize' ), 421 'value' => ini_get( 'upload_max_filesize' ), 422 ); 423 $fields['php_post_max_size'] = array( 424 'label' => __( 'PHP post max size' ), 425 'value' => ini_get( 'post_max_size' ), 426 ); 427 428 if ( function_exists( 'curl_version' ) ) { 429 $curl = curl_version(); 430 431 $fields['curl_version'] = array( 432 'label' => __( 'cURL version' ), 433 'value' => sprintf( '%s %s', $curl['version'], $curl['ssl_version'] ), 434 ); 435 } else { 436 $fields['curl_version'] = array( 437 'label' => __( 'cURL version' ), 438 'value' => __( 'Not available' ), 439 'debug' => 'not available', 440 ); 441 } 442 443 // SUHOSIN. 444 $suhosin_loaded = ( extension_loaded( 'suhosin' ) || ( defined( 'SUHOSIN_PATCH' ) && constant( 'SUHOSIN_PATCH' ) ) ); 445 446 $fields['suhosin'] = array( 447 'label' => __( 'Is SUHOSIN installed?' ), 448 'value' => ( $suhosin_loaded ? __( 'Yes' ) : __( 'No' ) ), 449 'debug' => $suhosin_loaded, 450 ); 451 452 // Imagick. 453 $imagick_loaded = extension_loaded( 'imagick' ); 454 455 $fields['imagick_availability'] = array( 456 'label' => __( 'Is the Imagick library available?' ), 457 'value' => ( $imagick_loaded ? __( 'Yes' ) : __( 'No' ) ), 458 'debug' => $imagick_loaded, 459 ); 460 461 // Opcode Cache. 462 if ( function_exists( 'opcache_get_status' ) ) { 463 $opcache_status = @opcache_get_status( false ); // phpcs:ignore WordPress.PHP.NoSilencedErrors.Discouraged -- Warning emitted in failure case. 464 465 if ( false === $opcache_status ) { 466 $fields['opcode_cache'] = array( 467 'label' => __( 'Opcode cache' ), 468 'value' => __( 'Disabled by configuration' ), 469 'debug' => 'not available', 470 ); 471 } else { 472 $fields['opcode_cache'] = array( 473 'label' => __( 'Opcode cache' ), 474 'value' => $opcache_status['opcache_enabled'] ? __( 'Enabled' ) : __( 'Disabled' ), 475 'debug' => $opcache_status['opcache_enabled'], 476 ); 477 478 if ( true === $opcache_status['opcache_enabled'] ) { 479 $fields['opcode_cache_memory_usage'] = array( 480 'label' => __( 'Opcode cache memory usage' ), 481 'value' => sprintf( 482 /* translators: 1: Used memory, 2: Total memory */ 483 __( '%1$s of %2$s' ), 484 size_format( $opcache_status['memory_usage']['used_memory'] ), 485 size_format( $opcache_status['memory_usage']['free_memory'] + $opcache_status['memory_usage']['used_memory'] ) 486 ), 487 'debug' => sprintf( 488 '%s of %s', 489 $opcache_status['memory_usage']['used_memory'], 490 $opcache_status['memory_usage']['free_memory'] + $opcache_status['memory_usage']['used_memory'] 491 ), 492 ); 493 494 if ( 0 !== $opcache_status['interned_strings_usage']['buffer_size'] ) { 495 $fields['opcode_cache_interned_strings_usage'] = array( 496 'label' => __( 'Opcode cache interned strings usage' ), 497 'value' => sprintf( 498 /* translators: 1: Percentage used, 2: Total memory, 3: Free memory */ 499 __( '%1$s%% of %2$s (%3$s free)' ), 500 number_format_i18n( ( $opcache_status['interned_strings_usage']['used_memory'] / $opcache_status['interned_strings_usage']['buffer_size'] ) * 100, 2 ), 501 size_format( $opcache_status['interned_strings_usage']['buffer_size'] ), 502 size_format( $opcache_status['interned_strings_usage']['free_memory'] ) 503 ), 504 'debug' => sprintf( 505 '%s%% of %s (%s free)', 506 round( ( $opcache_status['interned_strings_usage']['used_memory'] / $opcache_status['interned_strings_usage']['buffer_size'] ) * 100, 2 ), 507 $opcache_status['interned_strings_usage']['buffer_size'], 508 $opcache_status['interned_strings_usage']['free_memory'] 509 ), 510 ); 511 } 512 513 $fields['opcode_cache_hit_rate'] = array( 514 'label' => __( 'Opcode cache hit rate' ), 515 'value' => sprintf( 516 /* translators: %s: Hit rate percentage */ 517 __( '%s%%' ), 518 number_format_i18n( $opcache_status['opcache_statistics']['opcache_hit_rate'], 2 ) 519 ), 520 'debug' => round( $opcache_status['opcache_statistics']['opcache_hit_rate'], 2 ), 521 ); 522 523 $fields['opcode_cache_full'] = array( 524 'label' => __( 'Is the Opcode cache full?' ), 525 'value' => $opcache_status['cache_full'] ? __( 'Yes' ) : __( 'No' ), 526 'debug' => $opcache_status['cache_full'], 527 ); 528 } 529 } 530 } else { 531 $fields['opcode_cache'] = array( 532 'label' => __( 'Opcode cache' ), 533 'value' => __( 'Disabled' ), 534 'debug' => 'not available', 535 ); 536 } 537 538 // Pretty permalinks. 539 $pretty_permalinks_supported = got_url_rewrite(); 540 541 $fields['pretty_permalinks'] = array( 542 'label' => __( 'Are pretty permalinks supported?' ), 543 'value' => ( $pretty_permalinks_supported ? __( 'Yes' ) : __( 'No' ) ), 544 'debug' => $pretty_permalinks_supported, 545 ); 546 547 // Check if a .htaccess file exists. 548 if ( is_file( ABSPATH . '.htaccess' ) ) { 549 // If the file exists, grab the content of it. 550 $htaccess_content = file_get_contents( ABSPATH . '.htaccess' ); 551 552 // Filter away the core WordPress rules. 553 $filtered_htaccess_content = trim( preg_replace( '/\# BEGIN WordPress[\s\S]+?# END WordPress/si', '', $htaccess_content ) ); 554 $filtered_htaccess_content = ! empty( $filtered_htaccess_content ); 555 556 if ( $filtered_htaccess_content ) { 557 /* translators: %s: .htaccess */ 558 $htaccess_rules_string = sprintf( __( 'Custom rules have been added to your %s file.' ), '.htaccess' ); 559 } else { 560 /* translators: %s: .htaccess */ 561 $htaccess_rules_string = sprintf( __( 'Your %s file contains only core WordPress features.' ), '.htaccess' ); 562 } 563 564 $fields['htaccess_extra_rules'] = array( 565 'label' => __( '.htaccess rules' ), 566 'value' => $htaccess_rules_string, 567 'debug' => $filtered_htaccess_content, 568 ); 569 } 570 571 // Check if a robots.txt file exists. 572 if ( is_file( get_home_path() . 'robots.txt' ) ) { 573 // If the file exists, turn debug info to true. 574 $robotstxt_debug = true; 575 576 /* translators: %s: robots.txt */ 577 $robotstxt_string = sprintf( __( 'Your site is using a static %s file. WordPress cannot dynamically serve one.' ), 'robots.txt' ); 578 } elseif ( got_url_rewrite() ) { 579 // No robots.txt file available and rewrite rules in place, turn debug info to false. 580 $robotstxt_debug = false; 581 582 /* translators: %s: robots.txt */ 583 $robotstxt_string = sprintf( __( 'Your site is using the dynamic %s file which is generated by WordPress.' ), 'robots.txt' ); 584 } else { 585 // No robots.txt file, but without rewrite rules WP can't serve one. 586 $robotstxt_debug = true; 587 588 /* translators: %s: robots.txt */ 589 $robotstxt_string = sprintf( __( 'WordPress cannot dynamically serve a %s file due to a lack of rewrite rule support.' ), 'robots.txt' ); 590 591 } 592 593 $fields['static_robotstxt_file'] = array( 594 'label' => __( 'robots.txt' ), 595 'value' => $robotstxt_string, 596 'debug' => $robotstxt_debug, 597 ); 598 599 // Server time. 600 $date = new DateTime( 'now', new DateTimeZone( 'UTC' ) ); 601 602 $fields['current'] = array( 603 'label' => __( 'Current time' ), 604 'value' => $date->format( DateTime::ATOM ), 605 ); 606 $fields['utc-time'] = array( 607 'label' => __( 'Current UTC time' ), 608 'value' => $date->format( DateTime::RFC850 ), 609 ); 610 $fields['server-time'] = array( 611 'label' => __( 'Current Server time' ), 612 'value' => isset( $_SERVER['REQUEST_TIME'] ) ? wp_date( 'c', (int) $_SERVER['REQUEST_TIME'] ) : __( 'Unable to determine server time' ), 613 ); 614 615 return array( 616 'label' => __( 'Server' ), 617 'description' => __( 'The options shown below relate to your server setup. If changes are required, you may need your web host’s assistance.' ), 618 'fields' => $fields, 619 ); 620 } 621 622 /** 623 * Gets the WordPress media section of the debug data. 624 * 625 * @since 6.7.0 626 * 627 * @throws ImagickException 628 * @return array<string, string|array> The media handling debug data. 629 */ 630 private static function get_wp_media(): array { 631 // Spare few function calls. 632 $not_available = __( 'Not available' ); 633 634 // Populate the media fields. 635 $fields['image_editor'] = array( 636 'label' => __( 'Active editor' ), 637 'value' => _wp_image_editor_choose(), 638 ); 639 640 // Get ImageMagic information, if available. 641 if ( class_exists( 'Imagick' ) ) { 642 // Save the Imagick instance for later use. 643 $imagick = new Imagick(); 644 $imagemagick_version = $imagick->getVersion(); 645 } else { 646 $imagemagick_version = __( 'Not available' ); 647 } 648 649 $fields['imagick_module_version'] = array( 650 'label' => __( 'ImageMagick version number' ), 651 'value' => ( is_array( $imagemagick_version ) ? $imagemagick_version['versionNumber'] : $imagemagick_version ), 652 ); 653 654 $fields['imagemagick_version'] = array( 655 'label' => __( 'ImageMagick version string' ), 656 'value' => ( is_array( $imagemagick_version ) ? $imagemagick_version['versionString'] : $imagemagick_version ), 657 ); 658 659 $imagick_version = phpversion( 'imagick' ); 660 661 $fields['imagick_version'] = array( 662 'label' => __( 'Imagick version' ), 663 'value' => ( $imagick_version ) ? $imagick_version : __( 'Not available' ), 664 ); 665 666 // Get the PHP ini directive values. 667 $file_uploads = ini_get( 'file_uploads' ); 668 $post_max_size = ini_get( 'post_max_size' ); 669 $upload_max_filesize = ini_get( 'upload_max_filesize' ); 670 $max_file_uploads = ini_get( 'max_file_uploads' ); 671 $effective = min( wp_convert_hr_to_bytes( $post_max_size ), wp_convert_hr_to_bytes( $upload_max_filesize ) ); 672 673 // Add info in Media section. 674 $fields['file_uploads'] = array( 675 'label' => __( 'File uploads' ), 676 'value' => $file_uploads ? __( 'Enabled' ) : __( 'Disabled' ), 677 'debug' => $file_uploads, 678 ); 679 $fields['post_max_size'] = array( 680 'label' => __( 'Max size of post data allowed' ), 681 'value' => $post_max_size, 682 ); 683 $fields['upload_max_filesize'] = array( 684 'label' => __( 'Max size of an uploaded file' ), 685 'value' => $upload_max_filesize, 686 ); 687 $fields['max_effective_size'] = array( 688 'label' => __( 'Max effective file size' ), 689 'value' => size_format( $effective ), 690 ); 691 $fields['max_file_uploads'] = array( 692 'label' => __( 'Max simultaneous file uploads' ), 693 'value' => $max_file_uploads, 694 ); 695 696 // If Imagick is used as our editor, provide some more information about its limitations. 697 if ( 'WP_Image_Editor_Imagick' === _wp_image_editor_choose() && isset( $imagick ) && $imagick instanceof Imagick ) { 698 $limits = array( 699 'area' => ( defined( 'imagick::RESOURCETYPE_AREA' ) ? size_format( $imagick->getResourceLimit( imagick::RESOURCETYPE_AREA ) ) : $not_available ), 700 'disk' => ( defined( 'imagick::RESOURCETYPE_DISK' ) ? $imagick->getResourceLimit( imagick::RESOURCETYPE_DISK ) : $not_available ), 701 'file' => ( defined( 'imagick::RESOURCETYPE_FILE' ) ? $imagick->getResourceLimit( imagick::RESOURCETYPE_FILE ) : $not_available ), 702 'map' => ( defined( 'imagick::RESOURCETYPE_MAP' ) ? size_format( $imagick->getResourceLimit( imagick::RESOURCETYPE_MAP ) ) : $not_available ), 703 'memory' => ( defined( 'imagick::RESOURCETYPE_MEMORY' ) ? size_format( $imagick->getResourceLimit( imagick::RESOURCETYPE_MEMORY ) ) : $not_available ), 704 'thread' => ( defined( 'imagick::RESOURCETYPE_THREAD' ) ? $imagick->getResourceLimit( imagick::RESOURCETYPE_THREAD ) : $not_available ), 705 'time' => ( defined( 'imagick::RESOURCETYPE_TIME' ) ? $imagick->getResourceLimit( imagick::RESOURCETYPE_TIME ) : $not_available ), 706 ); 707 708 $limits_debug = array( 709 'imagick::RESOURCETYPE_AREA' => ( defined( 'imagick::RESOURCETYPE_AREA' ) ? size_format( $imagick->getResourceLimit( imagick::RESOURCETYPE_AREA ) ) : 'not available' ), 710 'imagick::RESOURCETYPE_DISK' => ( defined( 'imagick::RESOURCETYPE_DISK' ) ? $imagick->getResourceLimit( imagick::RESOURCETYPE_DISK ) : 'not available' ), 711 'imagick::RESOURCETYPE_FILE' => ( defined( 'imagick::RESOURCETYPE_FILE' ) ? $imagick->getResourceLimit( imagick::RESOURCETYPE_FILE ) : 'not available' ), 712 'imagick::RESOURCETYPE_MAP' => ( defined( 'imagick::RESOURCETYPE_MAP' ) ? size_format( $imagick->getResourceLimit( imagick::RESOURCETYPE_MAP ) ) : 'not available' ), 713 'imagick::RESOURCETYPE_MEMORY' => ( defined( 'imagick::RESOURCETYPE_MEMORY' ) ? size_format( $imagick->getResourceLimit( imagick::RESOURCETYPE_MEMORY ) ) : 'not available' ), 714 'imagick::RESOURCETYPE_THREAD' => ( defined( 'imagick::RESOURCETYPE_THREAD' ) ? $imagick->getResourceLimit( imagick::RESOURCETYPE_THREAD ) : 'not available' ), 715 'imagick::RESOURCETYPE_TIME' => ( defined( 'imagick::RESOURCETYPE_TIME' ) ? $imagick->getResourceLimit( imagick::RESOURCETYPE_TIME ) : 'not available' ), 716 ); 717 718 $fields['imagick_limits'] = array( 719 'label' => __( 'Imagick Resource Limits' ), 720 'value' => $limits, 721 'debug' => $limits_debug, 722 ); 723 724 try { 725 $formats = Imagick::queryFormats( '*' ); 726 } catch ( Exception $e ) { 727 $formats = array(); 728 } 729 730 $fields['imagemagick_file_formats'] = array( 731 'label' => __( 'ImageMagick supported file formats' ), 732 'value' => ( empty( $formats ) ) ? __( 'Unable to determine' ) : implode( ', ', $formats ), 733 'debug' => ( empty( $formats ) ) ? 'Unable to determine' : implode( ', ', $formats ), 734 ); 735 } 736 737 // Get the image format transforms. 738 $mappings = wp_get_image_editor_output_format( '', '' ); 739 $formatted_mappings = array(); 740 741 if ( ! empty( $mappings ) ) { 742 foreach ( $mappings as $format => $mime_type ) { 743 $formatted_mappings[] = sprintf( '%s → %s', $format, $mime_type ); 744 } 745 $mappings_display = implode( ', ', $formatted_mappings ); 746 } else { 747 $mappings_display = __( 'No format transforms defined' ); 748 } 749 750 $fields['image_format_transforms'] = array( 751 'label' => __( 'Image format transforms' ), 752 'value' => $mappings_display, 753 'debug' => ( empty( $mappings ) ) ? 'No format transforms defined' : $mappings_display, 754 ); 755 756 // Get GD information, if available. 757 if ( function_exists( 'gd_info' ) ) { 758 $gd = gd_info(); 759 } else { 760 $gd = false; 761 } 762 763 $fields['gd_version'] = array( 764 'label' => __( 'GD version' ), 765 'value' => ( is_array( $gd ) ? $gd['GD Version'] : $not_available ), 766 'debug' => ( is_array( $gd ) ? $gd['GD Version'] : 'not available' ), 767 ); 768 769 $gd_image_formats = array(); 770 $gd_supported_formats = array( 771 'GIF Create' => 'GIF', 772 'JPEG' => 'JPEG', 773 'PNG' => 'PNG', 774 'WebP' => 'WebP', 775 'BMP' => 'BMP', 776 'AVIF' => 'AVIF', 777 'HEIF' => 'HEIF', 778 'TIFF' => 'TIFF', 779 'XPM' => 'XPM', 780 ); 781 782 foreach ( $gd_supported_formats as $format_key => $format ) { 783 $index = $format_key . ' Support'; 784 if ( isset( $gd[ $index ] ) && $gd[ $index ] ) { 785 array_push( $gd_image_formats, $format ); 786 } 787 } 788 789 if ( ! empty( $gd_image_formats ) ) { 790 $fields['gd_formats'] = array( 791 'label' => __( 'GD supported file formats' ), 792 'value' => implode( ', ', $gd_image_formats ), 793 ); 794 } 795 796 // Get Ghostscript information, if available. 797 if ( function_exists( 'exec' ) ) { 798 $gs = exec( 'gs --version' ); 799 800 if ( empty( $gs ) ) { 801 $gs = $not_available; 802 $gs_debug = 'not available'; 803 } else { 804 $gs_debug = $gs; 805 } 806 } else { 807 $gs = __( 'Unable to determine if Ghostscript is installed' ); 808 $gs_debug = 'unknown'; 809 } 810 811 $fields['ghostscript_version'] = array( 812 'label' => __( 'Ghostscript version' ), 813 'value' => $gs, 814 'debug' => $gs_debug, 815 ); 816 817 return array( 818 'label' => __( 'Media Handling' ), 819 'fields' => $fields, 820 ); 821 } 822 823 /** 824 * Gets the WordPress MU plugins section of the debug data. 825 * 826 * @since 6.7.0 827 * 828 * @return array<string, string|bool|array> The must-use plugins debug data. 829 */ 830 private static function get_wp_mu_plugins(): array { 831 // List must use plugins if there are any. 832 $mu_plugins = get_mu_plugins(); 833 $fields = array(); 834 835 foreach ( $mu_plugins as $plugin_path => $plugin ) { 836 $plugin_version = $plugin['Version']; 837 $plugin_author = $plugin['Author']; 838 839 $plugin_version_string = __( 'No version or author information is available.' ); 840 $plugin_version_string_debug = 'author: (undefined), version: (undefined)'; 841 842 if ( ! empty( $plugin_version ) && ! empty( $plugin_author ) ) { 843 /* translators: 1: Plugin version number. 2: Plugin author name. */ 844 $plugin_version_string = sprintf( __( 'Version %1$s by %2$s' ), $plugin_version, $plugin_author ); 845 $plugin_version_string_debug = sprintf( 'version: %s, author: %s', $plugin_version, $plugin_author ); 846 } else { 847 if ( ! empty( $plugin_author ) ) { 848 /* translators: %s: Plugin author name. */ 849 $plugin_version_string = sprintf( __( 'By %s' ), $plugin_author ); 850 $plugin_version_string_debug = sprintf( 'author: %s, version: (undefined)', $plugin_author ); 851 } 852 853 if ( ! empty( $plugin_version ) ) { 854 /* translators: %s: Plugin version number. */ 855 $plugin_version_string = sprintf( __( 'Version %s' ), $plugin_version ); 856 $plugin_version_string_debug = sprintf( 'author: (undefined), version: %s', $plugin_version ); 857 } 858 } 859 860 $fields[ sanitize_text_field( $plugin['Name'] ) ] = array( 861 'label' => $plugin['Name'], 862 'value' => $plugin_version_string, 863 'debug' => $plugin_version_string_debug, 864 ); 865 } 866 867 return array( 868 'label' => __( 'Must Use Plugins' ), 869 'show_count' => true, 870 'fields' => $fields, 871 ); 872 } 873 874 /** 875 * Gets the WordPress paths and sizes section of the debug data. 876 * 877 * @since 6.7.0 878 * 879 * @return array|null Paths and sizes debug data for single sites, 880 * otherwise `null` for multi-site installs. 881 */ 882 private static function get_wp_paths_sizes(): ?array { 883 if ( is_multisite() ) { 884 return null; 885 } 886 887 $loading = __( 'Loading…' ); 888 889 $fields = array( 890 'wordpress_path' => array( 891 'label' => __( 'WordPress directory location' ), 892 'value' => untrailingslashit( ABSPATH ), 893 ), 894 'wordpress_size' => array( 895 'label' => __( 'WordPress directory size' ), 896 'value' => $loading, 897 'debug' => 'loading...', 898 ), 899 'uploads_path' => array( 900 'label' => __( 'Uploads directory location' ), 901 'value' => wp_upload_dir()['basedir'], 902 ), 903 'uploads_size' => array( 904 'label' => __( 'Uploads directory size' ), 905 'value' => $loading, 906 'debug' => 'loading...', 907 ), 908 'themes_path' => array( 909 'label' => __( 'Themes directory location' ), 910 'value' => get_theme_root(), 911 ), 912 'themes_size' => array( 913 'label' => __( 'Themes directory size' ), 914 'value' => $loading, 915 'debug' => 'loading...', 916 ), 917 'plugins_path' => array( 918 'label' => __( 'Plugins directory location' ), 919 'value' => WP_PLUGIN_DIR, 920 ), 921 'plugins_size' => array( 922 'label' => __( 'Plugins directory size' ), 923 'value' => $loading, 924 'debug' => 'loading...', 925 ), 926 'fonts_path' => array( 927 'label' => __( 'Fonts directory location' ), 928 'value' => wp_get_font_dir()['basedir'], 929 ), 930 'fonts_size' => array( 931 'label' => __( 'Fonts directory size' ), 932 'value' => $loading, 933 'debug' => 'loading...', 934 ), 935 'database_size' => array( 936 'label' => __( 'Database size' ), 937 'value' => $loading, 938 'debug' => 'loading...', 939 ), 940 'total_size' => array( 941 'label' => __( 'Total installation size' ), 942 'value' => $loading, 943 'debug' => 'loading...', 944 ), 945 ); 946 947 return array( 948 /* translators: Filesystem directory paths and storage sizes. */ 949 'label' => __( 'Directories and Sizes' ), 950 'fields' => $fields, 951 ); 952 } 953 954 /** 955 * Gets the WordPress active plugins section of the debug data. 956 * 957 * @since 6.7.0 958 * 959 * @return array<string, string|bool|array> The active plugins debug data. 960 */ 961 private static function get_wp_plugins_active(): array { 962 return array( 963 'label' => __( 'Active Plugins' ), 964 'show_count' => true, 965 'fields' => self::get_wp_plugins_raw_data()['wp-plugins-active'], 966 ); 967 } 968 969 /** 970 * Gets the WordPress inactive plugins section of the debug data. 971 * 972 * @since 6.7.0 973 * 974 * @return array<string, string|bool|array> The inactive plugins debug data. 975 */ 976 private static function get_wp_plugins_inactive(): array { 977 return array( 978 'label' => __( 'Inactive Plugins' ), 979 'show_count' => true, 980 'fields' => self::get_wp_plugins_raw_data()['wp-plugins-inactive'], 981 ); 982 } 983 984 /** 985 * Gets the raw plugin data for the WordPress active and inactive sections of the debug data. 986 * 987 * @since 6.7.0 988 * 989 * @return array<string, array<string, array<string, string>>> The raw plugin debug data for active and inactive plugins. 990 */ 991 private static function get_wp_plugins_raw_data(): array { 992 // List all available plugins. 993 $plugins = get_plugins(); 994 $plugin_updates = get_plugin_updates(); 995 $transient = get_site_transient( 'update_plugins' ); 996 997 $auto_updates = array(); 998 $fields = array( 999 'wp-plugins-active' => array(), 1000 'wp-plugins-inactive' => array(), 1001 ); 1002 1003 $auto_updates_enabled = wp_is_auto_update_enabled_for_type( 'plugin' ); 1004 1005 if ( $auto_updates_enabled ) { 1006 $auto_updates = (array) get_site_option( 'auto_update_plugins', array() ); 1007 } 1008 1009 foreach ( $plugins as $plugin_path => $plugin ) { 1010 $plugin_part = ( is_plugin_active( $plugin_path ) ) ? 'wp-plugins-active' : 'wp-plugins-inactive'; 1011 1012 $plugin_version = $plugin['Version']; 1013 $plugin_author = $plugin['Author']; 1014 1015 $plugin_version_string = __( 'No version or author information is available.' ); 1016 $plugin_version_string_debug = 'author: (undefined), version: (undefined)'; 1017 1018 if ( ! empty( $plugin_version ) && ! empty( $plugin_author ) ) { 1019 /* translators: 1: Plugin version number. 2: Plugin author name. */ 1020 $plugin_version_string = sprintf( __( 'Version %1$s by %2$s' ), $plugin_version, $plugin_author ); 1021 $plugin_version_string_debug = sprintf( 'version: %s, author: %s', $plugin_version, $plugin_author ); 1022 } else { 1023 if ( ! empty( $plugin_author ) ) { 1024 /* translators: %s: Plugin author name. */ 1025 $plugin_version_string = sprintf( __( 'By %s' ), $plugin_author ); 1026 $plugin_version_string_debug = sprintf( 'author: %s, version: (undefined)', $plugin_author ); 1027 } 1028 1029 if ( ! empty( $plugin_version ) ) { 1030 /* translators: %s: Plugin version number. */ 1031 $plugin_version_string = sprintf( __( 'Version %s' ), $plugin_version ); 1032 $plugin_version_string_debug = sprintf( 'author: (undefined), version: %s', $plugin_version ); 1033 } 1034 } 1035 1036 if ( array_key_exists( $plugin_path, $plugin_updates ) ) { 1037 /* translators: %s: Latest plugin version number. */ 1038 $plugin_version_string .= ' ' . sprintf( __( '(Latest version: %s)' ), $plugin_updates[ $plugin_path ]->update->new_version ); 1039 $plugin_version_string_debug .= sprintf( ' (latest version: %s)', $plugin_updates[ $plugin_path ]->update->new_version ); 1040 } 1041 1042 if ( $auto_updates_enabled ) { 1043 if ( isset( $transient->response[ $plugin_path ] ) ) { 1044 $item = $transient->response[ $plugin_path ]; 1045 } elseif ( isset( $transient->no_update[ $plugin_path ] ) ) { 1046 $item = $transient->no_update[ $plugin_path ]; 1047 } else { 1048 $item = array( 1049 'id' => $plugin_path, 1050 'slug' => '', 1051 'plugin' => $plugin_path, 1052 'new_version' => '', 1053 'url' => '', 1054 'package' => '', 1055 'icons' => array(), 1056 'banners' => array(), 1057 'banners_rtl' => array(), 1058 'tested' => '', 1059 'requires_php' => '', 1060 'compatibility' => new stdClass(), 1061 ); 1062 $item = wp_parse_args( $plugin, $item ); 1063 } 1064 1065 $auto_update_forced = wp_is_auto_update_forced_for_item( 'plugin', null, (object) $item ); 1066 1067 if ( ! is_null( $auto_update_forced ) ) { 1068 $enabled = $auto_update_forced; 1069 } else { 1070 $enabled = in_array( $plugin_path, $auto_updates, true ); 1071 } 1072 1073 if ( $enabled ) { 1074 $auto_updates_string = __( 'Auto-updates enabled' ); 1075 } else { 1076 $auto_updates_string = __( 'Auto-updates disabled' ); 1077 } 1078 1079 /** 1080 * Filters the text string of the auto-updates setting for each plugin in the Site Health debug data. 1081 * 1082 * @since 5.5.0 1083 * 1084 * @param string $auto_updates_string The string output for the auto-updates column. 1085 * @param string $plugin_path The path to the plugin file. 1086 * @param array $plugin An array of plugin data. 1087 * @param bool $enabled Whether auto-updates are enabled for this item. 1088 */ 1089 $auto_updates_string = apply_filters( 'plugin_auto_update_debug_string', $auto_updates_string, $plugin_path, $plugin, $enabled ); 1090 1091 $plugin_version_string .= ' | ' . $auto_updates_string; 1092 $plugin_version_string_debug .= ', ' . $auto_updates_string; 1093 } 1094 1095 $fields[ $plugin_part ][ sanitize_text_field( $plugin['Name'] ) ] = array( 1096 'label' => $plugin['Name'], 1097 'value' => $plugin_version_string, 1098 'debug' => $plugin_version_string_debug, 1099 ); 1100 } 1101 1102 return $fields; 1103 } 1104 1105 /** 1106 * Gets the WordPress active theme section of the debug data. 1107 * 1108 * @since 6.7.0 1109 * 1110 * @global array<string, bool|array> $_wp_theme_features The theme features for the active theme. 1111 * 1112 * @return array<string, string|array> The active theme debug data. 1113 */ 1114 private static function get_wp_active_theme(): array { 1115 global $_wp_theme_features; 1116 1117 // Populate the section for the currently active theme. 1118 $theme_features = array(); 1119 1120 if ( ! empty( $_wp_theme_features ) ) { 1121 foreach ( $_wp_theme_features as $feature => $options ) { 1122 $theme_features[] = $feature; 1123 } 1124 } 1125 1126 $active_theme = wp_get_theme(); 1127 $theme_updates = get_theme_updates(); 1128 $transient = get_site_transient( 'update_themes' ); 1129 1130 $active_theme_version = $active_theme->version; 1131 $active_theme_version_debug = $active_theme_version; 1132 1133 $auto_updates = array(); 1134 $auto_updates_enabled = wp_is_auto_update_enabled_for_type( 'theme' ); 1135 if ( $auto_updates_enabled ) { 1136 $auto_updates = (array) get_site_option( 'auto_update_themes', array() ); 1137 } 1138 1139 if ( array_key_exists( $active_theme->stylesheet, $theme_updates ) ) { 1140 $theme_update_new_version = $theme_updates[ $active_theme->stylesheet ]->update['new_version']; 1141 1142 /* translators: %s: Latest theme version number. */ 1143 $active_theme_version .= ' ' . sprintf( __( '(Latest version: %s)' ), $theme_update_new_version ); 1144 $active_theme_version_debug .= sprintf( ' (latest version: %s)', $theme_update_new_version ); 1145 } 1146 1147 $active_theme_author_uri = $active_theme->display( 'AuthorURI' ); 1148 1149 if ( $active_theme->parent_theme ) { 1150 $active_theme_parent_theme = sprintf( 1151 /* translators: 1: Theme name. 2: Theme slug. */ 1152 __( '%1$s (%2$s)' ), 1153 $active_theme->parent_theme, 1154 $active_theme->template 1155 ); 1156 $active_theme_parent_theme_debug = sprintf( 1157 '%s (%s)', 1158 $active_theme->parent_theme, 1159 $active_theme->template 1160 ); 1161 } else { 1162 $active_theme_parent_theme = __( 'None' ); 1163 $active_theme_parent_theme_debug = 'none'; 1164 } 1165 1166 $fields = array( 1167 'name' => array( 1168 'label' => __( 'Name' ), 1169 'value' => sprintf( 1170 /* translators: 1: Theme name. 2: Theme slug. */ 1171 __( '%1$s (%2$s)' ), 1172 $active_theme->name, 1173 $active_theme->stylesheet 1174 ), 1175 ), 1176 'version' => array( 1177 'label' => __( 'Version' ), 1178 'value' => $active_theme_version, 1179 'debug' => $active_theme_version_debug, 1180 ), 1181 'author' => array( 1182 'label' => __( 'Author' ), 1183 'value' => wp_kses( $active_theme->author, array() ), 1184 ), 1185 'author_website' => array( 1186 'label' => __( 'Author website' ), 1187 'value' => ( $active_theme_author_uri ? $active_theme_author_uri : __( 'Undefined' ) ), 1188 'debug' => ( $active_theme_author_uri ? $active_theme_author_uri : '(undefined)' ), 1189 ), 1190 'parent_theme' => array( 1191 'label' => __( 'Parent theme' ), 1192 'value' => $active_theme_parent_theme, 1193 'debug' => $active_theme_parent_theme_debug, 1194 ), 1195 'theme_features' => array( 1196 'label' => __( 'Theme features' ), 1197 'value' => implode( ', ', $theme_features ), 1198 ), 1199 'theme_path' => array( 1200 'label' => __( 'Theme directory location' ), 1201 'value' => get_stylesheet_directory(), 1202 ), 1203 ); 1204 1205 if ( $auto_updates_enabled ) { 1206 if ( isset( $transient->response[ $active_theme->stylesheet ] ) ) { 1207 $item = $transient->response[ $active_theme->stylesheet ]; 1208 } elseif ( isset( $transient->no_update[ $active_theme->stylesheet ] ) ) { 1209 $item = $transient->no_update[ $active_theme->stylesheet ]; 1210 } else { 1211 $item = array( 1212 'theme' => $active_theme->stylesheet, 1213 'new_version' => $active_theme->version, 1214 'url' => '', 1215 'package' => '', 1216 'requires' => '', 1217 'requires_php' => '', 1218 ); 1219 } 1220 1221 $auto_update_forced = wp_is_auto_update_forced_for_item( 'theme', null, (object) $item ); 1222 1223 if ( ! is_null( $auto_update_forced ) ) { 1224 $enabled = $auto_update_forced; 1225 } else { 1226 $enabled = in_array( $active_theme->stylesheet, $auto_updates, true ); 1227 } 1228 1229 if ( $enabled ) { 1230 $auto_updates_string = __( 'Enabled' ); 1231 } else { 1232 $auto_updates_string = __( 'Disabled' ); 1233 } 1234 1235 /** This filter is documented in wp-admin/includes/class-wp-debug-data.php */ 1236 $auto_updates_string = apply_filters( 'theme_auto_update_debug_string', $auto_updates_string, $active_theme, $enabled ); 1237 1238 $fields['auto_update'] = array( 1239 'label' => __( 'Auto-updates' ), 1240 'value' => $auto_updates_string, 1241 'debug' => $auto_updates_string, 1242 ); 1243 } 1244 1245 return array( 1246 'label' => __( 'Active Theme' ), 1247 'fields' => $fields, 1248 ); 1249 } 1250 1251 /** 1252 * Gets the WordPress parent theme section of the debug data. 1253 * 1254 * @since 6.7.0 1255 * 1256 * @return array<string, string|array> The parent theme debug data. 1257 */ 1258 private static function get_wp_parent_theme(): array { 1259 $theme_updates = get_theme_updates(); 1260 $transient = get_site_transient( 'update_themes' ); 1261 1262 $auto_updates = array(); 1263 $auto_updates_enabled = wp_is_auto_update_enabled_for_type( 'theme' ); 1264 if ( $auto_updates_enabled ) { 1265 $auto_updates = (array) get_site_option( 'auto_update_themes', array() ); 1266 } 1267 1268 $active_theme = wp_get_theme(); 1269 $parent_theme = $active_theme->parent(); 1270 $fields = array(); 1271 1272 if ( $parent_theme ) { 1273 $parent_theme_version = $parent_theme->version; 1274 $parent_theme_version_debug = $parent_theme_version; 1275 1276 if ( array_key_exists( $parent_theme->stylesheet, $theme_updates ) ) { 1277 $parent_theme_update_new_version = $theme_updates[ $parent_theme->stylesheet ]->update['new_version']; 1278 1279 /* translators: %s: Latest theme version number. */ 1280 $parent_theme_version .= ' ' . sprintf( __( '(Latest version: %s)' ), $parent_theme_update_new_version ); 1281 $parent_theme_version_debug .= sprintf( ' (latest version: %s)', $parent_theme_update_new_version ); 1282 } 1283 1284 $parent_theme_author_uri = $parent_theme->display( 'AuthorURI' ); 1285 1286 $fields = array( 1287 'name' => array( 1288 'label' => __( 'Name' ), 1289 'value' => sprintf( 1290 /* translators: 1: Theme name. 2: Theme slug. */ 1291 __( '%1$s (%2$s)' ), 1292 $parent_theme->name, 1293 $parent_theme->stylesheet 1294 ), 1295 ), 1296 'version' => array( 1297 'label' => __( 'Version' ), 1298 'value' => $parent_theme_version, 1299 'debug' => $parent_theme_version_debug, 1300 ), 1301 'author' => array( 1302 'label' => __( 'Author' ), 1303 'value' => wp_kses( $parent_theme->author, array() ), 1304 ), 1305 'author_website' => array( 1306 'label' => __( 'Author website' ), 1307 'value' => ( $parent_theme_author_uri ? $parent_theme_author_uri : __( 'Undefined' ) ), 1308 'debug' => ( $parent_theme_author_uri ? $parent_theme_author_uri : '(undefined)' ), 1309 ), 1310 'theme_path' => array( 1311 'label' => __( 'Theme directory location' ), 1312 'value' => get_template_directory(), 1313 ), 1314 ); 1315 1316 if ( $auto_updates_enabled ) { 1317 if ( isset( $transient->response[ $parent_theme->stylesheet ] ) ) { 1318 $item = $transient->response[ $parent_theme->stylesheet ]; 1319 } elseif ( isset( $transient->no_update[ $parent_theme->stylesheet ] ) ) { 1320 $item = $transient->no_update[ $parent_theme->stylesheet ]; 1321 } else { 1322 $item = array( 1323 'theme' => $parent_theme->stylesheet, 1324 'new_version' => $parent_theme->version, 1325 'url' => '', 1326 'package' => '', 1327 'requires' => '', 1328 'requires_php' => '', 1329 ); 1330 } 1331 1332 $auto_update_forced = wp_is_auto_update_forced_for_item( 'theme', null, (object) $item ); 1333 1334 if ( ! is_null( $auto_update_forced ) ) { 1335 $enabled = $auto_update_forced; 1336 } else { 1337 $enabled = in_array( $parent_theme->stylesheet, $auto_updates, true ); 1338 } 1339 1340 if ( $enabled ) { 1341 $parent_theme_auto_update_string = __( 'Enabled' ); 1342 } else { 1343 $parent_theme_auto_update_string = __( 'Disabled' ); 1344 } 1345 1346 /** This filter is documented in wp-admin/includes/class-wp-debug-data.php */ 1347 $parent_theme_auto_update_string = apply_filters( 'theme_auto_update_debug_string', $parent_theme_auto_update_string, $parent_theme, $enabled ); 1348 1349 $fields['auto_update'] = array( 1350 'label' => __( 'Auto-update' ), 1351 'value' => $parent_theme_auto_update_string, 1352 'debug' => $parent_theme_auto_update_string, 1353 ); 1354 } 1355 } 1356 1357 return array( 1358 'label' => __( 'Parent Theme' ), 1359 'fields' => $fields, 1360 ); 1361 } 1362 1363 /** 1364 * Gets the WordPress inactive themes section of the debug data. 1365 * 1366 * @since 6.7.0 1367 * 1368 * @return array<string, string|bool|array> The inactive themes debug data. 1369 */ 1370 private static function get_wp_themes_inactive(): array { 1371 $active_theme = wp_get_theme(); 1372 $parent_theme = $active_theme->parent(); 1373 $theme_updates = get_theme_updates(); 1374 $transient = get_site_transient( 'update_themes' ); 1375 1376 $auto_updates = array(); 1377 $auto_updates_enabled = wp_is_auto_update_enabled_for_type( 'theme' ); 1378 if ( $auto_updates_enabled ) { 1379 $auto_updates = (array) get_site_option( 'auto_update_themes', array() ); 1380 } 1381 1382 // Populate a list of all themes available in the installation. 1383 $all_themes = wp_get_themes(); 1384 $fields = array(); 1385 1386 foreach ( $all_themes as $theme_slug => $theme ) { 1387 // Exclude the currently active theme from the list of all themes. 1388 if ( $active_theme->stylesheet === $theme_slug ) { 1389 continue; 1390 } 1391 1392 // Exclude the currently active parent theme from the list of all themes. 1393 if ( ! empty( $parent_theme ) && $parent_theme->stylesheet === $theme_slug ) { 1394 continue; 1395 } 1396 1397 $theme_version = $theme->version; 1398 $theme_author = $theme->author; 1399 1400 // Sanitize. 1401 $theme_author = wp_kses( $theme_author, array() ); 1402 1403 $theme_version_string = __( 'No version or author information is available.' ); 1404 $theme_version_string_debug = 'undefined'; 1405 1406 if ( ! empty( $theme_version ) && ! empty( $theme_author ) ) { 1407 /* translators: 1: Theme version number. 2: Theme author name. */ 1408 $theme_version_string = sprintf( __( 'Version %1$s by %2$s' ), $theme_version, $theme_author ); 1409 $theme_version_string_debug = sprintf( 'version: %s, author: %s', $theme_version, $theme_author ); 1410 } else { 1411 if ( ! empty( $theme_author ) ) { 1412 /* translators: %s: Theme author name. */ 1413 $theme_version_string = sprintf( __( 'By %s' ), $theme_author ); 1414 $theme_version_string_debug = sprintf( 'author: %s, version: (undefined)', $theme_author ); 1415 } 1416 1417 if ( ! empty( $theme_version ) ) { 1418 /* translators: %s: Theme version number. */ 1419 $theme_version_string = sprintf( __( 'Version %s' ), $theme_version ); 1420 $theme_version_string_debug = sprintf( 'author: (undefined), version: %s', $theme_version ); 1421 } 1422 } 1423 1424 if ( array_key_exists( $theme_slug, $theme_updates ) ) { 1425 /* translators: %s: Latest theme version number. */ 1426 $theme_version_string .= ' ' . sprintf( __( '(Latest version: %s)' ), $theme_updates[ $theme_slug ]->update['new_version'] ); 1427 $theme_version_string_debug .= sprintf( ' (latest version: %s)', $theme_updates[ $theme_slug ]->update['new_version'] ); 1428 } 1429 1430 if ( $auto_updates_enabled ) { 1431 if ( isset( $transient->response[ $theme_slug ] ) ) { 1432 $item = $transient->response[ $theme_slug ]; 1433 } elseif ( isset( $transient->no_update[ $theme_slug ] ) ) { 1434 $item = $transient->no_update[ $theme_slug ]; 1435 } else { 1436 $item = array( 1437 'theme' => $theme_slug, 1438 'new_version' => $theme->version, 1439 'url' => '', 1440 'package' => '', 1441 'requires' => '', 1442 'requires_php' => '', 1443 ); 1444 } 1445 1446 $auto_update_forced = wp_is_auto_update_forced_for_item( 'theme', null, (object) $item ); 1447 1448 if ( ! is_null( $auto_update_forced ) ) { 1449 $enabled = $auto_update_forced; 1450 } else { 1451 $enabled = in_array( $theme_slug, $auto_updates, true ); 1452 } 1453 1454 if ( $enabled ) { 1455 $auto_updates_string = __( 'Auto-updates enabled' ); 1456 } else { 1457 $auto_updates_string = __( 'Auto-updates disabled' ); 1458 } 1459 1460 /** 1461 * Filters the text string of the auto-updates setting for each theme in the Site Health debug data. 1462 * 1463 * @since 5.5.0 1464 * 1465 * @param string $auto_updates_string The string output for the auto-updates column. 1466 * @param WP_Theme $theme An object of theme data. 1467 * @param bool $enabled Whether auto-updates are enabled for this item. 1468 */ 1469 $auto_updates_string = apply_filters( 'theme_auto_update_debug_string', $auto_updates_string, $theme, $enabled ); 1470 1471 $theme_version_string .= ' | ' . $auto_updates_string; 1472 $theme_version_string_debug .= ', ' . $auto_updates_string; 1473 } 1474 1475 $fields[ sanitize_text_field( $theme->name ) ] = array( 1476 'label' => sprintf( 1477 /* translators: 1: Theme name. 2: Theme slug. */ 1478 __( '%1$s (%2$s)' ), 1479 $theme->name, 1480 $theme_slug 1481 ), 1482 'value' => $theme_version_string, 1483 'debug' => $theme_version_string_debug, 1484 ); 1485 } 1486 1487 return array( 1488 'label' => __( 'Inactive Themes' ), 1489 'show_count' => true, 1490 'fields' => $fields, 1491 ); 1492 } 1493 1494 /** 1495 * Gets the WordPress constants section of the debug data. 1496 * 1497 * @since 6.7.0 1498 * 1499 * @return array<string, string|array> The WordPress constants debug data. 1500 */ 1501 private static function get_wp_constants(): array { 1502 // Check if WP_DEBUG_LOG is set. 1503 $wp_debug_log_value = __( 'Disabled' ); 1504 if ( is_string( WP_DEBUG_LOG ) ) { 1505 $wp_debug_log_value = WP_DEBUG_LOG; 1506 } elseif ( WP_DEBUG_LOG ) { 1507 $wp_debug_log_value = __( 'Enabled' ); 1508 } 1509 1510 // Check CONCATENATE_SCRIPTS. 1511 if ( defined( 'CONCATENATE_SCRIPTS' ) ) { 1512 $concatenate_scripts = CONCATENATE_SCRIPTS ? __( 'Enabled' ) : __( 'Disabled' ); 1513 $concatenate_scripts_debug = CONCATENATE_SCRIPTS ? 'true' : 'false'; 1514 } else { 1515 $concatenate_scripts = __( 'Undefined' ); 1516 $concatenate_scripts_debug = 'undefined'; 1517 } 1518 1519 // Check COMPRESS_SCRIPTS. 1520 if ( defined( 'COMPRESS_SCRIPTS' ) ) { 1521 $compress_scripts = COMPRESS_SCRIPTS ? __( 'Enabled' ) : __( 'Disabled' ); 1522 $compress_scripts_debug = COMPRESS_SCRIPTS ? 'true' : 'false'; 1523 } else { 1524 $compress_scripts = __( 'Undefined' ); 1525 $compress_scripts_debug = 'undefined'; 1526 } 1527 1528 // Check COMPRESS_CSS. 1529 if ( defined( 'COMPRESS_CSS' ) ) { 1530 $compress_css = COMPRESS_CSS ? __( 'Enabled' ) : __( 'Disabled' ); 1531 $compress_css_debug = COMPRESS_CSS ? 'true' : 'false'; 1532 } else { 1533 $compress_css = __( 'Undefined' ); 1534 $compress_css_debug = 'undefined'; 1535 } 1536 1537 // Check WP_ENVIRONMENT_TYPE. 1538 if ( defined( 'WP_ENVIRONMENT_TYPE' ) ) { 1539 $wp_environment_type = WP_ENVIRONMENT_TYPE ? WP_ENVIRONMENT_TYPE : __( 'Empty value' ); 1540 $wp_environment_type_debug = WP_ENVIRONMENT_TYPE; 1541 } else { 1542 $wp_environment_type = __( 'Undefined' ); 1543 $wp_environment_type_debug = 'undefined'; 1544 } 1545 1546 // Check DB_COLLATE. 1547 if ( defined( 'DB_COLLATE' ) ) { 1548 $db_collate = DB_COLLATE ? DB_COLLATE : __( 'Empty value' ); 1549 $db_collate_debug = DB_COLLATE; 1550 } else { 1551 $db_collate = __( 'Undefined' ); 1552 $db_collate_debug = 'undefined'; 1553 } 1554 1555 $fields = array( 1556 'ABSPATH' => array( 1557 'label' => 'ABSPATH', 1558 'value' => ABSPATH, 1559 'private' => true, 1560 ), 1561 'WP_HOME' => array( 1562 'label' => 'WP_HOME', 1563 'value' => ( defined( 'WP_HOME' ) ? WP_HOME : __( 'Undefined' ) ), 1564 'debug' => ( defined( 'WP_HOME' ) ? WP_HOME : 'undefined' ), 1565 ), 1566 'WP_SITEURL' => array( 1567 'label' => 'WP_SITEURL', 1568 'value' => ( defined( 'WP_SITEURL' ) ? WP_SITEURL : __( 'Undefined' ) ), 1569 'debug' => ( defined( 'WP_SITEURL' ) ? WP_SITEURL : 'undefined' ), 1570 ), 1571 'WP_CONTENT_DIR' => array( 1572 'label' => 'WP_CONTENT_DIR', 1573 'value' => WP_CONTENT_DIR, 1574 ), 1575 'WP_PLUGIN_DIR' => array( 1576 'label' => 'WP_PLUGIN_DIR', 1577 'value' => WP_PLUGIN_DIR, 1578 ), 1579 'WP_MEMORY_LIMIT' => array( 1580 'label' => 'WP_MEMORY_LIMIT', 1581 'value' => WP_MEMORY_LIMIT, 1582 ), 1583 'WP_MAX_MEMORY_LIMIT' => array( 1584 'label' => 'WP_MAX_MEMORY_LIMIT', 1585 'value' => WP_MAX_MEMORY_LIMIT, 1586 ), 1587 'WP_DEBUG' => array( 1588 'label' => 'WP_DEBUG', 1589 'value' => WP_DEBUG ? __( 'Enabled' ) : __( 'Disabled' ), 1590 'debug' => WP_DEBUG, 1591 ), 1592 'WP_DEBUG_DISPLAY' => array( 1593 'label' => 'WP_DEBUG_DISPLAY', 1594 'value' => WP_DEBUG_DISPLAY ? __( 'Enabled' ) : __( 'Disabled' ), 1595 'debug' => WP_DEBUG_DISPLAY, 1596 ), 1597 'WP_DEBUG_LOG' => array( 1598 'label' => 'WP_DEBUG_LOG', 1599 'value' => $wp_debug_log_value, 1600 'debug' => WP_DEBUG_LOG, 1601 ), 1602 'SCRIPT_DEBUG' => array( 1603 'label' => 'SCRIPT_DEBUG', 1604 'value' => SCRIPT_DEBUG ? __( 'Enabled' ) : __( 'Disabled' ), 1605 'debug' => SCRIPT_DEBUG, 1606 ), 1607 'WP_CACHE' => array( 1608 'label' => 'WP_CACHE', 1609 'value' => WP_CACHE ? __( 'Enabled' ) : __( 'Disabled' ), 1610 'debug' => WP_CACHE, 1611 ), 1612 'CONCATENATE_SCRIPTS' => array( 1613 'label' => 'CONCATENATE_SCRIPTS', 1614 'value' => $concatenate_scripts, 1615 'debug' => $concatenate_scripts_debug, 1616 ), 1617 'COMPRESS_SCRIPTS' => array( 1618 'label' => 'COMPRESS_SCRIPTS', 1619 'value' => $compress_scripts, 1620 'debug' => $compress_scripts_debug, 1621 ), 1622 'COMPRESS_CSS' => array( 1623 'label' => 'COMPRESS_CSS', 1624 'value' => $compress_css, 1625 'debug' => $compress_css_debug, 1626 ), 1627 'WP_ENVIRONMENT_TYPE' => array( 1628 'label' => 'WP_ENVIRONMENT_TYPE', 1629 'value' => $wp_environment_type, 1630 'debug' => $wp_environment_type_debug, 1631 ), 1632 'WP_DEVELOPMENT_MODE' => array( 1633 'label' => 'WP_DEVELOPMENT_MODE', 1634 'value' => WP_DEVELOPMENT_MODE ? WP_DEVELOPMENT_MODE : __( 'Disabled' ), 1635 'debug' => WP_DEVELOPMENT_MODE, 1636 ), 1637 'DB_CHARSET' => array( 1638 'label' => 'DB_CHARSET', 1639 'value' => ( defined( 'DB_CHARSET' ) ? DB_CHARSET : __( 'Undefined' ) ), 1640 'debug' => ( defined( 'DB_CHARSET' ) ? DB_CHARSET : 'undefined' ), 1641 ), 1642 'DB_COLLATE' => array( 1643 'label' => 'DB_COLLATE', 1644 'value' => $db_collate, 1645 'debug' => $db_collate_debug, 1646 ), 1647 'EMPTY_TRASH_DAYS' => array( 1648 'label' => 'EMPTY_TRASH_DAYS', 1649 'value' => EMPTY_TRASH_DAYS ? EMPTY_TRASH_DAYS : __( 'Empty value' ), 1650 'debug' => EMPTY_TRASH_DAYS, 1651 ), 1652 ); 1653 1654 return array( 1655 'label' => __( 'WordPress Constants' ), 1656 'description' => __( 'These settings alter where and how parts of WordPress are loaded.' ), 1657 'fields' => $fields, 1658 ); 1659 } 1660 1661 /** 1662 * Gets the WordPress database section of the debug data. 1663 * 1664 * @since 6.7.0 1665 * 1666 * @global wpdb $wpdb WordPress database abstraction object. 1667 * 1668 * @return array<string, string|array> The database debug data. 1669 */ 1670 private static function get_wp_database(): array { 1671 global $wpdb; 1672 1673 // Populate the database debug fields. 1674 if ( is_object( $wpdb->dbh ) ) { 1675 // mysqli or PDO. 1676 $extension = get_class( $wpdb->dbh ); 1677 } else { 1678 // Unknown sql extension. 1679 $extension = null; 1680 } 1681 1682 $server = $wpdb->get_var( 'SELECT VERSION()' ); 1683 1684 $client_version = $wpdb->dbh->client_info; 1685 1686 $fields = array( 1687 'extension' => array( 1688 'label' => __( 'Database Extension' ), 1689 'value' => $extension, 1690 ), 1691 'server_version' => array( 1692 'label' => __( 'Server version' ), 1693 'value' => $server, 1694 ), 1695 'client_version' => array( 1696 'label' => __( 'Client version' ), 1697 'value' => $client_version, 1698 ), 1699 'database_user' => array( 1700 'label' => __( 'Database username' ), 1701 'value' => $wpdb->dbuser, 1702 'private' => true, 1703 ), 1704 'database_host' => array( 1705 'label' => __( 'Database host' ), 1706 'value' => $wpdb->dbhost, 1707 'private' => true, 1708 ), 1709 'database_name' => array( 1710 'label' => __( 'Database name' ), 1711 'value' => $wpdb->dbname, 1712 'private' => true, 1713 ), 1714 'database_prefix' => array( 1715 'label' => __( 'Table prefix' ), 1716 'value' => $wpdb->prefix, 1717 'private' => true, 1718 ), 1719 'database_charset' => array( 1720 'label' => __( 'Database charset' ), 1721 'value' => $wpdb->charset, 1722 'private' => true, 1723 ), 1724 'database_collate' => array( 1725 'label' => __( 'Database collation' ), 1726 'value' => $wpdb->collate, 1727 'private' => true, 1728 ), 1729 'max_allowed_packet' => array( 1730 'label' => __( 'Max allowed packet size' ), 1731 'value' => self::get_mysql_var( 'max_allowed_packet' ), 1732 ), 1733 'max_connections' => array( 1734 'label' => __( 'Max connections number' ), 1735 'value' => self::get_mysql_var( 'max_connections' ), 1736 ), 1737 ); 1738 1739 return array( 1740 'label' => __( 'Database' ), 1741 'fields' => $fields, 1742 ); 1743 } 1744 1745 /** 1746 * Gets the file system section of the debug data. 1747 * 1748 * @since 6.7.0 1749 * 1750 * @return array<string, string|array> The debug data and other information for the Info screen. 1751 */ 1752 private static function get_wp_filesystem(): array { 1753 $upload_dir = wp_upload_dir(); 1754 $fonts_dir_exists = file_exists( wp_get_font_dir()['basedir'] ); 1755 $is_writable_abspath = wp_is_writable( ABSPATH ); 1756 $is_writable_wp_content_dir = wp_is_writable( WP_CONTENT_DIR ); 1757 $is_writable_upload_dir = wp_is_writable( $upload_dir['basedir'] ); 1758 $is_writable_wp_plugin_dir = wp_is_writable( WP_PLUGIN_DIR ); 1759 $is_writable_template_directory = wp_is_writable( get_theme_root( get_template() ) ); 1760 $is_writable_fonts_dir = $fonts_dir_exists ? wp_is_writable( wp_get_font_dir()['basedir'] ) : false; 1761 1762 $fields = array( 1763 'wordpress' => array( 1764 'label' => __( 'The main WordPress directory' ), 1765 'value' => ( $is_writable_abspath ? __( 'Writable' ) : __( 'Not writable' ) ), 1766 'debug' => ( $is_writable_abspath ? 'writable' : 'not writable' ), 1767 ), 1768 'wp-content' => array( 1769 'label' => __( 'The wp-content directory' ), 1770 'value' => ( $is_writable_wp_content_dir ? __( 'Writable' ) : __( 'Not writable' ) ), 1771 'debug' => ( $is_writable_wp_content_dir ? 'writable' : 'not writable' ), 1772 ), 1773 'uploads' => array( 1774 'label' => __( 'The uploads directory' ), 1775 'value' => ( $is_writable_upload_dir ? __( 'Writable' ) : __( 'Not writable' ) ), 1776 'debug' => ( $is_writable_upload_dir ? 'writable' : 'not writable' ), 1777 ), 1778 'plugins' => array( 1779 'label' => __( 'The plugins directory' ), 1780 'value' => ( $is_writable_wp_plugin_dir ? __( 'Writable' ) : __( 'Not writable' ) ), 1781 'debug' => ( $is_writable_wp_plugin_dir ? 'writable' : 'not writable' ), 1782 ), 1783 'themes' => array( 1784 'label' => __( 'The themes directory' ), 1785 'value' => ( $is_writable_template_directory ? __( 'Writable' ) : __( 'Not writable' ) ), 1786 'debug' => ( $is_writable_template_directory ? 'writable' : 'not writable' ), 1787 ), 1788 'fonts' => array( 1789 'label' => __( 'The fonts directory' ), 1790 'value' => $fonts_dir_exists 1791 ? ( $is_writable_fonts_dir ? __( 'Writable' ) : __( 'Not writable' ) ) 1792 : __( 'Does not exist' ), 1793 'debug' => $fonts_dir_exists 1794 ? ( $is_writable_fonts_dir ? 'writable' : 'not writable' ) 1795 : 'does not exist', 1796 ), 1797 ); 1798 1799 // Add more filesystem checks. 1800 if ( defined( 'WPMU_PLUGIN_DIR' ) && is_dir( WPMU_PLUGIN_DIR ) ) { 1801 $is_writable_wpmu_plugin_dir = wp_is_writable( WPMU_PLUGIN_DIR ); 1802 1803 $fields['mu-plugins'] = array( 1804 'label' => __( 'The must use plugins directory' ), 1805 'value' => ( $is_writable_wpmu_plugin_dir ? __( 'Writable' ) : __( 'Not writable' ) ), 1806 'debug' => ( $is_writable_wpmu_plugin_dir ? 'writable' : 'not writable' ), 1807 ); 1808 } 1809 1810 return array( 1811 'label' => __( 'Filesystem Permissions' ), 1812 'description' => __( 'Shows whether WordPress is able to write to the directories it needs access to.' ), 1813 'fields' => $fields, 1814 ); 1815 } 1816 1817 /** 1818 * Returns the value of a MySQL system variable. 1819 * 1820 * @since 5.9.0 1821 * 1822 * @global wpdb $wpdb WordPress database abstraction object. 1823 * 1824 * @param string $mysql_var Name of the MySQL system variable. 1825 * @return string|null The variable value on success. Null if the variable does not exist. 1826 */ 1827 public static function get_mysql_var( $mysql_var ) { 1828 global $wpdb; 1829 1830 $result = $wpdb->get_row( 1831 $wpdb->prepare( 'SHOW VARIABLES LIKE %s', $mysql_var ), 1832 ARRAY_A 1833 ); 1834 1835 if ( ! empty( $result ) && array_key_exists( 'Value', $result ) ) { 1836 return $result['Value']; 1837 } 1838 1839 return null; 1840 } 1841 1842 /** 1843 * Formats the information gathered for debugging, in a manner suitable for copying to a forum or support ticket. 1844 * 1845 * @since 5.2.0 1846 * 1847 * @param array $info_array Information gathered from the `WP_Debug_Data::debug_data()` function. 1848 * @param string $data_type The data type to return, either 'info' or 'debug'. 1849 * @return string The formatted data. 1850 */ 1851 public static function format( $info_array, $data_type ) { 1852 $return = "`\n"; 1853 1854 foreach ( $info_array as $section => $details ) { 1855 // Skip this section if there are no fields, or the section has been declared as private. 1856 if ( empty( $details['fields'] ) || ( isset( $details['private'] ) && $details['private'] ) ) { 1857 continue; 1858 } 1859 1860 $section_label = 'debug' === $data_type ? $section : $details['label']; 1861 1862 $return .= sprintf( 1863 "### %s%s ###\n\n", 1864 $section_label, 1865 ( isset( $details['show_count'] ) && $details['show_count'] ? sprintf( ' (%d)', count( $details['fields'] ) ) : '' ) 1866 ); 1867 1868 foreach ( $details['fields'] as $field_name => $field ) { 1869 if ( isset( $field['private'] ) && true === $field['private'] ) { 1870 continue; 1871 } 1872 1873 if ( 'debug' === $data_type && isset( $field['debug'] ) ) { 1874 $debug_data = $field['debug']; 1875 } else { 1876 $debug_data = $field['value']; 1877 } 1878 1879 // Can be array, one level deep only. 1880 if ( is_array( $debug_data ) ) { 1881 $value = ''; 1882 1883 foreach ( $debug_data as $sub_field_name => $sub_field_value ) { 1884 $value .= sprintf( "\n\t%s: %s", $sub_field_name, $sub_field_value ); 1885 } 1886 } elseif ( is_bool( $debug_data ) ) { 1887 $value = $debug_data ? 'true' : 'false'; 1888 } elseif ( empty( $debug_data ) && '0' !== $debug_data ) { 1889 $value = 'undefined'; 1890 } else { 1891 $value = $debug_data; 1892 } 1893 1894 if ( 'debug' === $data_type ) { 1895 $label = $field_name; 1896 } else { 1897 $label = $field['label']; 1898 } 1899 1900 $return .= sprintf( "%s: %s\n", $label, $value ); 1901 } 1902 1903 $return .= "\n"; 1904 } 1905 1906 $return .= '`'; 1907 1908 return $return; 1909 } 1910 1911 /** 1912 * Fetches the total size of all the database tables for the active database user. 1913 * 1914 * @since 5.2.0 1915 * 1916 * @global wpdb $wpdb WordPress database abstraction object. 1917 * 1918 * @return int The size of the database, in bytes. 1919 */ 1920 public static function get_database_size() { 1921 global $wpdb; 1922 $size = 0; 1923 $rows = $wpdb->get_results( 'SHOW TABLE STATUS', ARRAY_A ); 1924 1925 if ( $wpdb->num_rows > 0 ) { 1926 foreach ( $rows as $row ) { 1927 $size += $row['Data_length'] + $row['Index_length']; 1928 } 1929 } 1930 1931 return (int) $size; 1932 } 1933 1934 /** 1935 * Fetches the sizes of the WordPress directories: `wordpress` (ABSPATH), `plugins`, `themes`, and `uploads`. 1936 * Intended to supplement the array returned by `WP_Debug_Data::debug_data()`. 1937 * 1938 * @since 5.2.0 1939 * @deprecated 5.6.0 Use WP_REST_Site_Health_Controller::get_directory_sizes() 1940 * @see WP_REST_Site_Health_Controller::get_directory_sizes() 1941 * 1942 * @return array The sizes of the directories, also the database size and total installation size. 1943 */ 1944 public static function get_sizes() { 1945 _deprecated_function( __METHOD__, '5.6.0', 'WP_REST_Site_Health_Controller::get_directory_sizes()' ); 1946 1947 $size_db = self::get_database_size(); 1948 $upload_dir = wp_get_upload_dir(); 1949 1950 /* 1951 * We will be using the PHP max execution time to prevent the size calculations 1952 * from causing a timeout. The default value is 30 seconds, and some 1953 * hosts do not allow you to read configuration values. 1954 */ 1955 $max_execution_time = ini_get( 'max_execution_time' ); 1956 1957 /* 1958 * The max_execution_time defaults to 0 when PHP runs from cli. 1959 * We still want to limit it below. 1960 */ 1961 if ( empty( $max_execution_time ) ) { 1962 $max_execution_time = 30; // 30 seconds. 1963 } 1964 1965 if ( $max_execution_time > 20 ) { 1966 /* 1967 * If the max_execution_time is set to lower than 20 seconds, reduce it a bit to prevent 1968 * edge-case timeouts that may happen after the size loop has finished running. 1969 */ 1970 $max_execution_time -= 2; 1971 } 1972 1973 /* 1974 * Go through the various installation directories and calculate their sizes. 1975 * No trailing slashes. 1976 */ 1977 $paths = array( 1978 'wordpress_size' => untrailingslashit( ABSPATH ), 1979 'themes_size' => get_theme_root(), 1980 'plugins_size' => WP_PLUGIN_DIR, 1981 'uploads_size' => $upload_dir['basedir'], 1982 'fonts_size' => wp_get_font_dir()['basedir'], 1983 ); 1984 1985 $exclude = $paths; 1986 unset( $exclude['wordpress_size'] ); 1987 $exclude = array_values( $exclude ); 1988 1989 $size_total = 0; 1990 $all_sizes = array(); 1991 1992 // Loop over all the directories we want to gather the sizes for. 1993 foreach ( $paths as $name => $path ) { 1994 $dir_size = null; // Default to timeout. 1995 $results = array( 1996 'path' => $path, 1997 'raw' => 0, 1998 ); 1999 2000 // If the directory does not exist, skip checking it, as it will skew the other results. 2001 if ( ! is_dir( $path ) ) { 2002 $all_sizes[ $name ] = array( 2003 'path' => $path, 2004 'raw' => 0, 2005 'size' => __( 'The directory does not exist.' ), 2006 'debug' => 'directory not found', 2007 ); 2008 2009 continue; 2010 } 2011 2012 if ( microtime( true ) - WP_START_TIMESTAMP < $max_execution_time ) { 2013 if ( 'wordpress_size' === $name ) { 2014 $dir_size = recurse_dirsize( $path, $exclude, $max_execution_time ); 2015 } else { 2016 $dir_size = recurse_dirsize( $path, null, $max_execution_time ); 2017 } 2018 } 2019 2020 if ( false === $dir_size ) { 2021 // Error reading. 2022 $results['size'] = __( 'The size cannot be calculated. The directory is not accessible. Usually caused by invalid permissions.' ); 2023 $results['debug'] = 'not accessible'; 2024 2025 // Stop total size calculation. 2026 $size_total = null; 2027 } elseif ( null === $dir_size ) { 2028 // Timeout. 2029 $results['size'] = __( 'The directory size calculation has timed out. Usually caused by a very large number of sub-directories and files.' ); 2030 $results['debug'] = 'timeout while calculating size'; 2031 2032 // Stop total size calculation. 2033 $size_total = null; 2034 } else { 2035 if ( null !== $size_total ) { 2036 $size_total += $dir_size; 2037 } 2038 2039 $results['raw'] = $dir_size; 2040 $results['size'] = size_format( $dir_size, 2 ); 2041 $results['debug'] = $results['size'] . " ({$dir_size} bytes)"; 2042 } 2043 2044 $all_sizes[ $name ] = $results; 2045 } 2046 2047 if ( $size_db > 0 ) { 2048 $database_size = size_format( $size_db, 2 ); 2049 2050 $all_sizes['database_size'] = array( 2051 'raw' => $size_db, 2052 'size' => $database_size, 2053 'debug' => $database_size . " ({$size_db} bytes)", 2054 ); 2055 } else { 2056 $all_sizes['database_size'] = array( 2057 'size' => __( 'Not available' ), 2058 'debug' => 'not available', 2059 ); 2060 } 2061 2062 if ( null !== $size_total && $size_db > 0 ) { 2063 $total_size = $size_total + $size_db; 2064 $total_size_mb = size_format( $total_size, 2 ); 2065 2066 $all_sizes['total_size'] = array( 2067 'raw' => $total_size, 2068 'size' => $total_size_mb, 2069 'debug' => $total_size_mb . " ({$total_size} bytes)", 2070 ); 2071 } else { 2072 $all_sizes['total_size'] = array( 2073 'size' => __( 'Total size is not available. Some errors were encountered when determining the size of your installation.' ), 2074 'debug' => 'not available', 2075 ); 2076 } 2077 2078 return $all_sizes; 2079 } 2080 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body
| Generated : Mon Jul 6 08:20:14 2026 | Cross-referenced by PHPXref |