wp/wp-admin/includes/class-wp-site-health.php
changeset 19 3d72ae0968f4
parent 18 be944660c56a
child 21 48c4eec2b7e6
equal deleted inserted replaced
18:be944660c56a 19:3d72ae0968f4
   282 				$core_current_version
   282 				$core_current_version
   283 			);
   283 			);
   284 
   284 
   285 			$result['description'] = sprintf(
   285 			$result['description'] = sprintf(
   286 				'<p>%s</p>',
   286 				'<p>%s</p>',
   287 				__( 'We were unable to check if any new versions of WordPress are available.' )
   287 				__( 'Unable to check if any new versions of WordPress are available.' )
   288 			);
   288 			);
   289 
   289 
   290 			$result['actions'] = sprintf(
   290 			$result['actions'] = sprintf(
   291 				'<a href="%s">%s</a>',
   291 				'<a href="%s">%s</a>',
   292 				esc_url( admin_url( 'update-core.php?force-check=1' ) ),
   292 				esc_url( admin_url( 'update-core.php?force-check=1' ) ),
   465 						'Your site has %d inactive plugins.',
   465 						'Your site has %d inactive plugins.',
   466 						$unused_plugins
   466 						$unused_plugins
   467 					),
   467 					),
   468 					$unused_plugins
   468 					$unused_plugins
   469 				),
   469 				),
   470 				__( 'Inactive plugins are tempting targets for attackers. If you&#8217;re not going to use a plugin, we recommend you remove it.' )
   470 				__( 'Inactive plugins are tempting targets for attackers. If you are not going to use a plugin, you should consider removing it.' )
   471 			);
   471 			);
   472 
   472 
   473 			$result['actions'] .= sprintf(
   473 			$result['actions'] .= sprintf(
   474 				'<p><a href="%s">%s</a></p>',
   474 				'<p><a href="%s">%s</a></p>',
   475 				esc_url( admin_url( 'plugins.php?plugin_status=inactive' ) ),
   475 				esc_url( admin_url( 'plugins.php?plugin_status=inactive' ) ),
   632 							),
   632 							),
   633 							$themes_inactive
   633 							$themes_inactive
   634 						),
   634 						),
   635 						sprintf(
   635 						sprintf(
   636 							/* translators: 1: The currently active theme. 2: The active theme's parent theme. */
   636 							/* translators: 1: The currently active theme. 2: The active theme's parent theme. */
   637 							__( 'To enhance your site&#8217;s security, we recommend you remove any themes you&#8217;re not using. You should keep your current theme, %1$s, and %2$s, its parent theme.' ),
   637 							__( 'To enhance your site&#8217;s security, you should consider removing any themes you are not using. You should keep your active theme, %1$s, and %2$s, its parent theme.' ),
   638 							$active_theme->name,
   638 							$active_theme->name,
   639 							$active_theme->parent()->name
   639 							$active_theme->parent()->name
   640 						)
   640 						)
   641 					);
   641 					);
   642 				} else {
   642 				} else {
   651 							),
   651 							),
   652 							$themes_inactive
   652 							$themes_inactive
   653 						),
   653 						),
   654 						sprintf(
   654 						sprintf(
   655 							/* translators: 1: The default theme for WordPress. 2: The currently active theme. 3: The active theme's parent theme. */
   655 							/* translators: 1: The default theme for WordPress. 2: The currently active theme. 3: The active theme's parent theme. */
   656 							__( 'To enhance your site&#8217;s security, we recommend you remove any themes you&#8217;re not using. You should keep %1$s, the default WordPress theme, %2$s, your current theme, and %3$s, its parent theme.' ),
   656 							__( 'To enhance your site&#8217;s security, you should consider removing any themes you are not using. You should keep %1$s, the default WordPress theme, %2$s, your active theme, and %3$s, its parent theme.' ),
   657 							$default_theme ? $default_theme->name : WP_DEFAULT_THEME,
   657 							$default_theme ? $default_theme->name : WP_DEFAULT_THEME,
   658 							$active_theme->name,
   658 							$active_theme->name,
   659 							$active_theme->parent()->name
   659 							$active_theme->parent()->name
   660 						)
   660 						)
   661 					);
   661 					);
   677 								$themes_inactive
   677 								$themes_inactive
   678 							),
   678 							),
   679 							$themes_inactive,
   679 							$themes_inactive,
   680 							$active_theme->name
   680 							$active_theme->name
   681 						),
   681 						),
   682 						__( 'We recommend removing any unused themes to enhance your site&#8217;s security.' )
   682 						__( 'You should consider removing any unused themes to enhance your site&#8217;s security.' )
   683 					);
   683 					);
   684 				} else {
   684 				} else {
   685 					$result['description'] .= sprintf(
   685 					$result['description'] .= sprintf(
   686 						'<p>%s %s</p>',
   686 						'<p>%s %s</p>',
   687 						sprintf(
   687 						sprintf(
   693 							),
   693 							),
   694 							$themes_inactive,
   694 							$themes_inactive,
   695 							$default_theme ? $default_theme->name : WP_DEFAULT_THEME,
   695 							$default_theme ? $default_theme->name : WP_DEFAULT_THEME,
   696 							$active_theme->name
   696 							$active_theme->name
   697 						),
   697 						),
   698 						__( 'We recommend removing any unused themes to enhance your site&#8217;s security.' )
   698 						__( 'You should consider removing any unused themes to enhance your site&#8217;s security.' )
   699 					);
   699 					);
   700 				}
   700 				}
   701 			}
   701 			}
   702 		}
   702 		}
   703 
   703 
   800 	 * Check if the passed extension or function are available.
   800 	 * Check if the passed extension or function are available.
   801 	 *
   801 	 *
   802 	 * Make the check for available PHP modules into a simple boolean operator for a cleaner test runner.
   802 	 * Make the check for available PHP modules into a simple boolean operator for a cleaner test runner.
   803 	 *
   803 	 *
   804 	 * @since 5.2.0
   804 	 * @since 5.2.0
   805 	 * @since 5.3.0 The `$constant` and `$class` parameters were added.
   805 	 * @since 5.3.0 The `$constant_name` and `$class_name` parameters were added.
   806 	 *
   806 	 *
   807 	 * @param string $extension Optional. The extension name to test. Default null.
   807 	 * @param string $extension_name Optional. The extension name to test. Default null.
   808 	 * @param string $function  Optional. The function name to test. Default null.
   808 	 * @param string $function_name  Optional. The function name to test. Default null.
   809 	 * @param string $constant  Optional. The constant name to test for. Default null.
   809 	 * @param string $constant_name  Optional. The constant name to test for. Default null.
   810 	 * @param string $class     Optional. The class name to test for. Default null.
   810 	 * @param string $class_name     Optional. The class name to test for. Default null.
   811 	 * @return bool Whether or not the extension and function are available.
   811 	 * @return bool Whether or not the extension and function are available.
   812 	 */
   812 	 */
   813 	private function test_php_extension_availability( $extension = null, $function = null, $constant = null, $class = null ) {
   813 	private function test_php_extension_availability( $extension_name = null, $function_name = null, $constant_name = null, $class_name = null ) {
   814 		// If no extension or function is passed, claim to fail testing, as we have nothing to test against.
   814 		// If no extension or function is passed, claim to fail testing, as we have nothing to test against.
   815 		if ( ! $extension && ! $function && ! $constant && ! $class ) {
   815 		if ( ! $extension_name && ! $function_name && ! $constant_name && ! $class_name ) {
   816 			return false;
   816 			return false;
   817 		}
   817 		}
   818 
   818 
   819 		if ( $extension && ! extension_loaded( $extension ) ) {
   819 		if ( $extension_name && ! extension_loaded( $extension_name ) ) {
   820 			return false;
   820 			return false;
   821 		}
   821 		}
   822 		if ( $function && ! function_exists( $function ) ) {
   822 
       
   823 		if ( $function_name && ! function_exists( $function_name ) ) {
   823 			return false;
   824 			return false;
   824 		}
   825 		}
   825 		if ( $constant && ! defined( $constant ) ) {
   826 
       
   827 		if ( $constant_name && ! defined( $constant_name ) ) {
   826 			return false;
   828 			return false;
   827 		}
   829 		}
   828 		if ( $class && ! class_exists( $class ) ) {
   830 
       
   831 		if ( $class_name && ! class_exists( $class_name ) ) {
   829 			return false;
   832 			return false;
   830 		}
   833 		}
   831 
   834 
   832 		return true;
   835 		return true;
   833 	}
   836 	}
   889 			),
   892 			),
   890 			'hash'      => array(
   893 			'hash'      => array(
   891 				'function' => 'hash',
   894 				'function' => 'hash',
   892 				'required' => false,
   895 				'required' => false,
   893 			),
   896 			),
       
   897 			'imagick'   => array(
       
   898 				'extension' => 'imagick',
       
   899 				'required'  => false,
       
   900 			),
   894 			'json'      => array(
   901 			'json'      => array(
   895 				'function' => 'json_last_error',
   902 				'function' => 'json_last_error',
   896 				'required' => true,
   903 				'required' => true,
   897 			),
   904 			),
   898 			'mbstring'  => array(
   905 			'mbstring'  => array(
   914 			),
   921 			),
   915 			'pcre'      => array(
   922 			'pcre'      => array(
   916 				'function' => 'preg_match',
   923 				'function' => 'preg_match',
   917 				'required' => false,
   924 				'required' => false,
   918 			),
   925 			),
   919 			'imagick'   => array(
       
   920 				'extension' => 'imagick',
       
   921 				'required'  => false,
       
   922 			),
       
   923 			'mod_xml'   => array(
   926 			'mod_xml'   => array(
   924 				'extension' => 'libxml',
   927 				'extension' => 'libxml',
   925 				'required'  => false,
   928 				'required'  => false,
   926 			),
   929 			),
   927 			'zip'       => array(
   930 			'zip'       => array(
   938 				'fallback_for' => 'imagick',
   941 				'fallback_for' => 'imagick',
   939 			),
   942 			),
   940 			'iconv'     => array(
   943 			'iconv'     => array(
   941 				'function' => 'iconv',
   944 				'function' => 'iconv',
   942 				'required' => false,
   945 				'required' => false,
       
   946 			),
       
   947 			'intl'      => array(
       
   948 				'extension' => 'intl',
       
   949 				'required'  => false,
   943 			),
   950 			),
   944 			'mcrypt'    => array(
   951 			'mcrypt'    => array(
   945 				'extension'    => 'mcrypt',
   952 				'extension'    => 'mcrypt',
   946 				'required'     => false,
   953 				'required'     => false,
   947 				'fallback_for' => 'libsodium',
   954 				'fallback_for' => 'libsodium',
   988 		$modules = apply_filters( 'site_status_test_php_modules', $modules );
   995 		$modules = apply_filters( 'site_status_test_php_modules', $modules );
   989 
   996 
   990 		$failures = array();
   997 		$failures = array();
   991 
   998 
   992 		foreach ( $modules as $library => $module ) {
   999 		foreach ( $modules as $library => $module ) {
   993 			$extension  = ( isset( $module['extension'] ) ? $module['extension'] : null );
  1000 			$extension_name = ( isset( $module['extension'] ) ? $module['extension'] : null );
   994 			$function   = ( isset( $module['function'] ) ? $module['function'] : null );
  1001 			$function_name  = ( isset( $module['function'] ) ? $module['function'] : null );
   995 			$constant   = ( isset( $module['constant'] ) ? $module['constant'] : null );
  1002 			$constant_name  = ( isset( $module['constant'] ) ? $module['constant'] : null );
   996 			$class_name = ( isset( $module['class'] ) ? $module['class'] : null );
  1003 			$class_name     = ( isset( $module['class'] ) ? $module['class'] : null );
   997 
  1004 
   998 			// If this module is a fallback for another function, check if that other function passed.
  1005 			// If this module is a fallback for another function, check if that other function passed.
   999 			if ( isset( $module['fallback_for'] ) ) {
  1006 			if ( isset( $module['fallback_for'] ) ) {
  1000 				/*
  1007 				/*
  1001 				 * If that other function has a failure, mark this module as required for usual operations.
  1008 				 * If that other function has a failure, mark this module as required for usual operations.
  1006 				} else {
  1013 				} else {
  1007 					continue;
  1014 					continue;
  1008 				}
  1015 				}
  1009 			}
  1016 			}
  1010 
  1017 
  1011 			if ( ! $this->test_php_extension_availability( $extension, $function, $constant, $class_name ) && ( ! isset( $module['php_bundled_version'] ) || version_compare( PHP_VERSION, $module['php_bundled_version'], '<' ) ) ) {
  1018 			if ( ! $this->test_php_extension_availability( $extension_name, $function_name, $constant_name, $class_name )
       
  1019 				&& ( ! isset( $module['php_bundled_version'] )
       
  1020 					|| version_compare( PHP_VERSION, $module['php_bundled_version'], '<' ) )
       
  1021 			) {
  1012 				if ( $module['required'] ) {
  1022 				if ( $module['required'] ) {
  1013 					$result['status'] = 'critical';
  1023 					$result['status'] = 'critical';
  1014 
  1024 
  1015 					$class         = 'error';
  1025 					$class         = 'error';
  1016 					$screen_reader = __( 'Error' );
  1026 					$screen_reader = __( 'Error' );
  1194 
  1204 
  1195 			$result['description'] .= sprintf(
  1205 			$result['description'] .= sprintf(
  1196 				'<p>%s</p>',
  1206 				'<p>%s</p>',
  1197 				sprintf(
  1207 				sprintf(
  1198 					/* translators: 1: The database engine in use (MySQL or MariaDB). 2: Database server recommended version number. */
  1208 					/* translators: 1: The database engine in use (MySQL or MariaDB). 2: Database server recommended version number. */
  1199 					__( 'For optimal performance and security reasons, we recommend running %1$s version %2$s or higher. Contact your web hosting company to correct this.' ),
  1209 					__( 'For optimal performance and security reasons, you should consider running %1$s version %2$s or higher. Contact your web hosting company to correct this.' ),
  1200 					( $this->is_mariadb ? 'MariaDB' : 'MySQL' ),
  1210 					( $this->is_mariadb ? 'MariaDB' : 'MySQL' ),
  1201 					$this->health_check_mysql_rec_version
  1211 					$this->health_check_mysql_rec_version
  1202 				)
  1212 				)
  1203 			);
  1213 			);
  1204 		}
  1214 		}
  1460 			'test'        => 'is_in_debug_mode',
  1470 			'test'        => 'is_in_debug_mode',
  1461 		);
  1471 		);
  1462 
  1472 
  1463 		if ( defined( 'WP_DEBUG' ) && WP_DEBUG ) {
  1473 		if ( defined( 'WP_DEBUG' ) && WP_DEBUG ) {
  1464 			if ( defined( 'WP_DEBUG_LOG' ) && WP_DEBUG_LOG ) {
  1474 			if ( defined( 'WP_DEBUG_LOG' ) && WP_DEBUG_LOG ) {
  1465 				$result['label'] = __( 'Your site is set to log errors to a potentially public file.' );
  1475 				$result['label'] = __( 'Your site is set to log errors to a potentially public file' );
  1466 
  1476 
  1467 				$result['status'] = ( 0 === strpos( ini_get( 'error_log' ), ABSPATH ) ) ? 'critical' : 'recommended';
  1477 				$result['status'] = ( 0 === strpos( ini_get( 'error_log' ), ABSPATH ) ) ? 'critical' : 'recommended';
  1468 
  1478 
  1469 				$result['description'] .= sprintf(
  1479 				$result['description'] .= sprintf(
  1470 					'<p>%s</p>',
  1480 					'<p>%s</p>',
  2106 	 *
  2116 	 *
  2107 	 * @return array The test results.
  2117 	 * @return array The test results.
  2108 	 */
  2118 	 */
  2109 	public function get_test_file_uploads() {
  2119 	public function get_test_file_uploads() {
  2110 		$result = array(
  2120 		$result = array(
  2111 			'label'       => __( 'Files can be uploaded.' ),
  2121 			'label'       => __( 'Files can be uploaded' ),
  2112 			'status'      => 'good',
  2122 			'status'      => 'good',
  2113 			'badge'       => array(
  2123 			'badge'       => array(
  2114 				'label' => __( 'Performance' ),
  2124 				'label' => __( 'Performance' ),
  2115 				'color' => 'blue',
  2125 				'color' => 'blue',
  2116 			),
  2126 			),
  2155 		$upload_max_filesize = ini_get( 'upload_max_filesize' );
  2165 		$upload_max_filesize = ini_get( 'upload_max_filesize' );
  2156 
  2166 
  2157 		if ( wp_convert_hr_to_bytes( $post_max_size ) < wp_convert_hr_to_bytes( $upload_max_filesize ) ) {
  2167 		if ( wp_convert_hr_to_bytes( $post_max_size ) < wp_convert_hr_to_bytes( $upload_max_filesize ) ) {
  2158 			$result['label'] = sprintf(
  2168 			$result['label'] = sprintf(
  2159 				/* translators: 1: post_max_size, 2: upload_max_filesize */
  2169 				/* translators: 1: post_max_size, 2: upload_max_filesize */
  2160 				__( 'The "%1$s" value is smaller than "%2$s".' ),
  2170 				__( 'The "%1$s" value is smaller than "%2$s"' ),
  2161 				'post_max_size',
  2171 				'post_max_size',
  2162 				'upload_max_filesize'
  2172 				'upload_max_filesize'
  2163 			);
  2173 			);
  2164 			$result['status'] = 'recommended';
  2174 			$result['status'] = 'recommended';
  2165 
  2175 
  2198 	 *
  2208 	 *
  2199 	 * @return array
  2209 	 * @return array
  2200 	 */
  2210 	 */
  2201 	public function get_test_authorization_header() {
  2211 	public function get_test_authorization_header() {
  2202 		$result = array(
  2212 		$result = array(
  2203 			'label'       => __( 'The Authorization header is working as expected.' ),
  2213 			'label'       => __( 'The Authorization header is working as expected' ),
  2204 			'status'      => 'good',
  2214 			'status'      => 'good',
  2205 			'badge'       => array(
  2215 			'badge'       => array(
  2206 				'label' => __( 'Security' ),
  2216 				'label' => __( 'Security' ),
  2207 				'color' => 'blue',
  2217 				'color' => 'blue',
  2208 			),
  2218 			),
  2213 			'actions'     => '',
  2223 			'actions'     => '',
  2214 			'test'        => 'authorization_header',
  2224 			'test'        => 'authorization_header',
  2215 		);
  2225 		);
  2216 
  2226 
  2217 		if ( ! isset( $_SERVER['PHP_AUTH_USER'], $_SERVER['PHP_AUTH_PW'] ) ) {
  2227 		if ( ! isset( $_SERVER['PHP_AUTH_USER'], $_SERVER['PHP_AUTH_PW'] ) ) {
  2218 			$result['label'] = __( 'The authorization header is missing.' );
  2228 			$result['label'] = __( 'The authorization header is missing' );
  2219 		} elseif ( 'user' !== $_SERVER['PHP_AUTH_USER'] || 'pwd' !== $_SERVER['PHP_AUTH_PW'] ) {
  2229 		} elseif ( 'user' !== $_SERVER['PHP_AUTH_USER'] || 'pwd' !== $_SERVER['PHP_AUTH_PW'] ) {
  2220 			$result['label'] = __( 'The authorization header is invalid.' );
  2230 			$result['label'] = __( 'The authorization header is invalid' );
  2221 		} else {
  2231 		} else {
  2222 			return $result;
  2232 			return $result;
  2223 		}
  2233 		}
  2224 
  2234 
  2225 		$result['status'] = 'recommended';
  2235 		$result['status'] = 'recommended';
  2369 
  2379 
  2370 		/**
  2380 		/**
  2371 		 * Add or modify which site status tests are run on a site.
  2381 		 * Add or modify which site status tests are run on a site.
  2372 		 *
  2382 		 *
  2373 		 * The site health is determined by a set of tests based on best practices from
  2383 		 * The site health is determined by a set of tests based on best practices from
  2374 		 * both the WordPress Hosting Team, but also web standards in general.
  2384 		 * both the WordPress Hosting Team and web standards in general.
  2375 		 *
  2385 		 *
  2376 		 * Some sites may not have the same requirements, for example the automatic update
  2386 		 * Some sites may not have the same requirements, for example the automatic update
  2377 		 * checks may be handled by a host, and are therefore disabled in core.
  2387 		 * checks may be handled by a host, and are therefore disabled in core.
  2378 		 * Or maybe you want to introduce a new test, is caching enabled/disabled/stale for example.
  2388 		 * Or maybe you want to introduce a new test, is caching enabled/disabled/stale for example.
  2379 		 *
  2389 		 *
  2380 		 * Tests may be added either as direct, or asynchronous ones. Any test that may require some time
  2390 		 * Tests may be added either as direct, or asynchronous ones. Any test that may require some time
  2381 		 * to complete should run asynchronously, to avoid extended loading periods within wp-admin.
  2391 		 * to complete should run asynchronously, to avoid extended loading periods within wp-admin.
  2382 		 *
  2392 		 *
  2383 		 * @since 5.2.0
  2393 		 * @since 5.2.0
  2384 		 * @since 5.6.0 Added the `async_direct_test` array key.
  2394 		 * @since 5.6.0 Added the `async_direct_test` array key for asynchronous tests.
  2385 		 *              Added the `skip_cron` array key.
  2395 		 *              Added the `skip_cron` array key for all tests.
  2386 		 *
  2396 		 *
  2387 		 * @param array $test_type {
  2397 		 * @param array[] $tests {
  2388 		 *     An associative array, where the `$test_type` is either `direct` or
  2398 		 *     An associative array of direct and asynchronous tests.
  2389 		 *     `async`, to declare if the test should run via Ajax calls after page load.
       
  2390 		 *
  2399 		 *
  2391 		 *     @type array $identifier {
  2400 		 *     @type array[] $direct {
  2392 		 *         `$identifier` should be a unique identifier for the test that should run.
  2401 		 *         An array of direct tests.
  2393 		 *         Plugins and themes are encouraged to prefix test identifiers with their slug
       
  2394 		 *         to avoid any collisions between tests.
       
  2395 		 *
  2402 		 *
  2396 		 *         @type string   $label             A friendly label for your test to identify it by.
  2403 		 *         @type array ...$identifier {
  2397 		 *         @type mixed    $test              A callable to perform a direct test, or a string AJAX action
  2404 		 *             `$identifier` should be a unique identifier for the test. Plugins and themes are encouraged to
  2398 		 *                                           to be called to perform an async test.
  2405 		 *             prefix test identifiers with their slug to avoid collisions between tests.
  2399 		 *         @type boolean  $has_rest          Optional. Denote if `$test` has a REST API endpoint.
  2406 		 *
  2400 		 *         @type boolean  $skip_cron         Whether to skip this test when running as cron.
  2407 		 *             @type string   $label     The friendly label to identify the test.
  2401 		 *         @type callable $async_direct_test A manner of directly calling the test marked as asynchronous,
  2408 		 *             @type callable $test      The callback function that runs the test and returns its result.
  2402 		 *                                           as the scheduled event can not authenticate, and endpoints
  2409 		 *             @type bool     $skip_cron Whether to skip this test when running as cron.
  2403 		 *                                           may require authentication.
  2410 		 *         }
       
  2411 		 *     }
       
  2412 		 *     @type array[] $async {
       
  2413 		 *         An array of asynchronous tests.
       
  2414 		 *
       
  2415 		 *         @type array ...$identifier {
       
  2416 		 *             `$identifier` should be a unique identifier for the test. Plugins and themes are encouraged to
       
  2417 		 *             prefix test identifiers with their slug to avoid collisions between tests.
       
  2418 		 *
       
  2419 		 *             @type string   $label             The friendly label to identify the test.
       
  2420 		 *             @type string   $test              An admin-ajax.php action to be called to perform the test, or
       
  2421 		 *                                               if `$has_rest` is true, a URL to a REST API endpoint to perform
       
  2422 		 *                                               the test.
       
  2423 		 *             @type bool     $has_rest          Whether the `$test` property points to a REST API endpoint.
       
  2424 		 *             @type bool     $skip_cron         Whether to skip this test when running as cron.
       
  2425 		 *             @type callable $async_direct_test A manner of directly calling the test marked as asynchronous,
       
  2426 		 *                                               as the scheduled event can not authenticate, and endpoints
       
  2427 		 *                                               may require authentication.
       
  2428 		 *         }
  2404 		 *     }
  2429 		 *     }
  2405 		 * }
  2430 		 * }
  2406 		 */
  2431 		 */
  2407 		$tests = apply_filters( 'site_status_tests', $tests );
  2432 		$tests = apply_filters( 'site_status_tests', $tests );
  2408 
  2433 
  2547 	 *
  2572 	 *
  2548 	 * @since 5.5.0
  2573 	 * @since 5.5.0
  2549 	 *
  2574 	 *
  2550 	 * @return object The test results.
  2575 	 * @return object The test results.
  2551 	 */
  2576 	 */
  2552 	function detect_plugin_theme_auto_update_issues() {
  2577 	public function detect_plugin_theme_auto_update_issues() {
  2553 		$mock_plugin = (object) array(
  2578 		$mock_plugin = (object) array(
  2554 			'id'            => 'w.org/plugins/a-fake-plugin',
  2579 			'id'            => 'w.org/plugins/a-fake-plugin',
  2555 			'slug'          => 'a-fake-plugin',
  2580 			'slug'          => 'a-fake-plugin',
  2556 			'plugin'        => 'a-fake-plugin/a-fake-plugin.php',
  2581 			'plugin'        => 'a-fake-plugin/a-fake-plugin.php',
  2557 			'new_version'   => '9.9',
  2582 			'new_version'   => '9.9',
  2630 	 *
  2655 	 *
  2631 	 * @since 5.2.0
  2656 	 * @since 5.2.0
  2632 	 *
  2657 	 *
  2633 	 * @return object The test results.
  2658 	 * @return object The test results.
  2634 	 */
  2659 	 */
  2635 	function can_perform_loopback() {
  2660 	public function can_perform_loopback() {
  2636 		$body    = array( 'site-health' => 'loopback-test' );
  2661 		$body    = array( 'site-health' => 'loopback-test' );
  2637 		$cookies = wp_unslash( $_COOKIE );
  2662 		$cookies = wp_unslash( $_COOKIE );
  2638 		$timeout = 10;
  2663 		$timeout = 10;
  2639 		$headers = array(
  2664 		$headers = array(
  2640 			'Cache-Control' => 'no-cache',
  2665 			'Cache-Control' => 'no-cache',