[ Index ]

PHP Cross Reference of WordPress

title

Body

[close]

/wp-admin/includes/ -> class-wp-site-health.php (source)

   1  <?php
   2  /**
   3   * Class for looking up a site's health based on a user's WordPress environment.
   4   *
   5   * @package WordPress
   6   * @subpackage Site_Health
   7   * @since 5.2.0
   8   */
   9  
  10  class WP_Site_Health {
  11      private $mysql_min_version_check;
  12      private $mysql_rec_version_check;
  13  
  14      public $is_mariadb                           = false;
  15      private $mysql_server_version                = '';
  16      private $health_check_mysql_required_version = '5.5';
  17      private $health_check_mysql_rec_version      = '';
  18  
  19      public $schedules;
  20      public $crons;
  21      public $last_missed_cron     = null;
  22      public $last_late_cron       = null;
  23      private $timeout_missed_cron = null;
  24      private $timeout_late_cron   = null;
  25  
  26      /**
  27       * WP_Site_Health constructor.
  28       *
  29       * @since 5.2.0
  30       */
  31  	public function __construct() {
  32          $this->prepare_sql_data();
  33  
  34          $this->timeout_late_cron   = 0;
  35          $this->timeout_missed_cron = - 5 * MINUTE_IN_SECONDS;
  36  
  37          if ( defined( 'DISABLE_WP_CRON' ) && DISABLE_WP_CRON ) {
  38              $this->timeout_late_cron   = - 15 * MINUTE_IN_SECONDS;
  39              $this->timeout_missed_cron = - 1 * HOUR_IN_SECONDS;
  40          }
  41  
  42          add_filter( 'admin_body_class', array( $this, 'admin_body_class' ) );
  43  
  44          add_action( 'admin_enqueue_scripts', array( $this, 'enqueue_scripts' ) );
  45      }
  46  
  47      /**
  48       * Enqueues the site health scripts.
  49       *
  50       * @since 5.2.0
  51       */
  52  	public function enqueue_scripts() {
  53          $screen = get_current_screen();
  54          if ( 'site-health' !== $screen->id ) {
  55              return;
  56          }
  57  
  58          $health_check_js_variables = array(
  59              'screen'      => $screen->id,
  60              'nonce'       => array(
  61                  'site_status'        => wp_create_nonce( 'health-check-site-status' ),
  62                  'site_status_result' => wp_create_nonce( 'health-check-site-status-result' ),
  63              ),
  64              'site_status' => array(
  65                  'direct' => array(),
  66                  'async'  => array(),
  67                  'issues' => array(
  68                      'good'        => 0,
  69                      'recommended' => 0,
  70                      'critical'    => 0,
  71                  ),
  72              ),
  73          );
  74  
  75          $issue_counts = get_transient( 'health-check-site-status-result' );
  76  
  77          if ( false !== $issue_counts ) {
  78              $issue_counts = json_decode( $issue_counts );
  79  
  80              $health_check_js_variables['site_status']['issues'] = $issue_counts;
  81          }
  82  
  83          if ( 'site-health' === $screen->id && ! isset( $_GET['tab'] ) ) {
  84              $tests = WP_Site_Health::get_tests();
  85  
  86              // Don't run https test on localhost
  87              if ( 'localhost' === preg_replace( '|https?://|', '', get_site_url() ) ) {
  88                  unset( $tests['direct']['https_status'] );
  89              }
  90  
  91              foreach ( $tests['direct'] as $test ) {
  92                  if ( is_string( $test['test'] ) ) {
  93                      $test_function = sprintf(
  94                          'get_test_%s',
  95                          $test['test']
  96                      );
  97  
  98                      if ( method_exists( $this, $test_function ) && is_callable( array( $this, $test_function ) ) ) {
  99                          $health_check_js_variables['site_status']['direct'][] = call_user_func( array( $this, $test_function ) );
 100                          continue;
 101                      }
 102                  }
 103  
 104                  if ( is_callable( $test['test'] ) ) {
 105                      $health_check_js_variables['site_status']['direct'][] = call_user_func( $test['test'] );
 106                  }
 107              }
 108  
 109              foreach ( $tests['async'] as $test ) {
 110                  if ( is_string( $test['test'] ) ) {
 111                      $health_check_js_variables['site_status']['async'][] = array(
 112                          'test'      => $test['test'],
 113                          'completed' => false,
 114                      );
 115                  }
 116              }
 117          }
 118  
 119          wp_localize_script( 'site-health', 'SiteHealth', $health_check_js_variables );
 120      }
 121  
 122      /**
 123       * Run the SQL version checks.
 124       *
 125       * These values are used in later tests, but the part of preparing them is more easily managed early
 126       * in the class for ease of access and discovery.
 127       *
 128       * @since 5.2.0
 129       *
 130       * @global wpdb $wpdb WordPress database abstraction object.
 131       */
 132  	private function prepare_sql_data() {
 133          global $wpdb;
 134  
 135          if ( $wpdb->use_mysqli ) {
 136              // phpcs:ignore WordPress.DB.RestrictedFunctions.mysql_mysqli_get_server_info
 137              $mysql_server_type = mysqli_get_server_info( $wpdb->dbh );
 138          } else {
 139              // phpcs:ignore WordPress.DB.RestrictedFunctions.mysql_mysql_get_server_info
 140              $mysql_server_type = mysql_get_server_info( $wpdb->dbh );
 141          }
 142  
 143          $this->mysql_server_version = $wpdb->get_var( 'SELECT VERSION()' );
 144  
 145          $this->health_check_mysql_rec_version = '5.6';
 146  
 147          if ( stristr( $mysql_server_type, 'mariadb' ) ) {
 148              $this->is_mariadb                     = true;
 149              $this->health_check_mysql_rec_version = '10.0';
 150          }
 151  
 152          $this->mysql_min_version_check = version_compare( '5.5', $this->mysql_server_version, '<=' );
 153          $this->mysql_rec_version_check = version_compare( $this->health_check_mysql_rec_version, $this->mysql_server_version, '<=' );
 154      }
 155  
 156      /**
 157       * Test if `wp_version_check` is blocked.
 158       *
 159       * It's possible to block updates with the `wp_version_check` filter, but this can't be checked during an
 160       * AJAX call, as the filter is never introduced then.
 161       *
 162       * This filter overrides a normal page request if it's made by an admin through the AJAX call with the
 163       * right query argument to check for this.
 164       *
 165       * @since 5.2.0
 166       */
 167  	public function check_wp_version_check_exists() {
 168          if ( ! is_admin() || ! is_user_logged_in() || ! current_user_can( 'update_core' ) || ! isset( $_GET['health-check-test-wp_version_check'] ) ) {
 169              return;
 170          }
 171  
 172          echo ( has_filter( 'wp_version_check', 'wp_version_check' ) ? 'yes' : 'no' );
 173  
 174          die();
 175      }
 176  
 177      /**
 178       * Tests for WordPress version and outputs it.
 179       *
 180       * Gives various results depending on what kind of updates are available, if any, to encourage the
 181       * user to install security updates as a priority.
 182       *
 183       * @since 5.2.0
 184       *
 185       * @return array The test result.
 186       */
 187  	public function get_test_wordpress_version() {
 188          $result = array(
 189              'label'       => '',
 190              'status'      => '',
 191              'badge'       => array(
 192                  'label' => __( 'Performance' ),
 193                  'color' => 'blue',
 194              ),
 195              'description' => '',
 196              'actions'     => '',
 197              'test'        => 'wordpress_version',
 198          );
 199  
 200          $core_current_version = get_bloginfo( 'version' );
 201          $core_updates         = get_core_updates();
 202  
 203          if ( ! is_array( $core_updates ) ) {
 204              $result['status'] = 'recommended';
 205  
 206              $result['label'] = sprintf(
 207                  /* translators: %s: Your current version of WordPress. */
 208                  __( 'WordPress version %s' ),
 209                  $core_current_version
 210              );
 211  
 212              $result['description'] = sprintf(
 213                  '<p>%s</p>',
 214                  __( 'We were unable to check if any new versions of WordPress are available.' )
 215              );
 216  
 217              $result['actions'] = sprintf(
 218                  '<a href="%s">%s</a>',
 219                  esc_url( admin_url( 'update-core.php?force-check=1' ) ),
 220                  __( 'Check for updates manually' )
 221              );
 222          } else {
 223              foreach ( $core_updates as $core => $update ) {
 224                  if ( 'upgrade' === $update->response ) {
 225                      $current_version = explode( '.', $core_current_version );
 226                      $new_version     = explode( '.', $update->version );
 227  
 228                      $current_major = $current_version[0] . '.' . $current_version[1];
 229                      $new_major     = $new_version[0] . '.' . $new_version[1];
 230  
 231                      $result['label'] = sprintf(
 232                          /* translators: %s: The latest version of WordPress available. */
 233                          __( 'WordPress update available (%s)' ),
 234                          $update->version
 235                      );
 236  
 237                      $result['actions'] = sprintf(
 238                          '<a href="%s">%s</a>',
 239                          esc_url( admin_url( 'update-core.php' ) ),
 240                          __( 'Install the latest version of WordPress' )
 241                      );
 242  
 243                      if ( $current_major !== $new_major ) {
 244                          // This is a major version mismatch.
 245                          $result['status']      = 'recommended';
 246                          $result['description'] = sprintf(
 247                              '<p>%s</p>',
 248                              __( 'A new version of WordPress is available.' )
 249                          );
 250                      } else {
 251                          // This is a minor version, sometimes considered more critical.
 252                          $result['status']         = 'critical';
 253                          $result['badge']['label'] = __( 'Security' );
 254                          $result['description']    = sprintf(
 255                              '<p>%s</p>',
 256                              __( 'A new minor update is available for your site. Because minor updates often address security, it&#8217;s important to install them.' )
 257                          );
 258                      }
 259                  } else {
 260                      $result['status'] = 'good';
 261                      $result['label']  = sprintf(
 262                          /* translators: %s: The current version of WordPress installed on this site. */
 263                          __( 'Your WordPress version is up to date (%s)' ),
 264                          $core_current_version
 265                      );
 266  
 267                      $result['description'] = sprintf(
 268                          '<p>%s</p>',
 269                          __( 'You are currently running the latest version of WordPress available, keep it up!' )
 270                      );
 271                  }
 272              }
 273          }
 274  
 275          return $result;
 276      }
 277  
 278      /**
 279       * Test if plugins are outdated, or unnecessary.
 280       *
 281       * The tests checks if your plugins are up to date, and encourages you to remove any that are not in use.
 282       *
 283       * @since 5.2.0
 284       *
 285       * @return array The test result.
 286       */
 287  	public function get_test_plugin_version() {
 288          $result = array(
 289              'label'       => __( 'Your plugins are all up to date' ),
 290              'status'      => 'good',
 291              'badge'       => array(
 292                  'label' => __( 'Security' ),
 293                  'color' => 'blue',
 294              ),
 295              'description' => sprintf(
 296                  '<p>%s</p>',
 297                  __( 'Plugins extend your site&#8217;s functionality with things like contact forms, ecommerce and much more. That means they have deep access to your site, so it&#8217;s vital to keep them up to date.' )
 298              ),
 299              'actions'     => sprintf(
 300                  '<p><a href="%s">%s</a></p>',
 301                  esc_url( admin_url( 'plugins.php' ) ),
 302                  __( 'Manage your plugins' )
 303              ),
 304              'test'        => 'plugin_version',
 305          );
 306  
 307          $plugins        = get_plugins();
 308          $plugin_updates = get_plugin_updates();
 309  
 310          $plugins_have_updates = false;
 311          $plugins_active       = 0;
 312          $plugins_total        = 0;
 313          $plugins_need_update  = 0;
 314  
 315          // Loop over the available plugins and check their versions and active state.
 316          foreach ( $plugins as $plugin_path => $plugin ) {
 317              $plugins_total++;
 318  
 319              if ( is_plugin_active( $plugin_path ) ) {
 320                  $plugins_active++;
 321              }
 322  
 323              $plugin_version = $plugin['Version'];
 324  
 325              if ( array_key_exists( $plugin_path, $plugin_updates ) ) {
 326                  $plugins_need_update++;
 327                  $plugins_have_updates = true;
 328              }
 329          }
 330  
 331          // Add a notice if there are outdated plugins.
 332          if ( $plugins_need_update > 0 ) {
 333              $result['status'] = 'critical';
 334  
 335              $result['label'] = __( 'You have plugins waiting to be updated' );
 336  
 337              $result['description'] .= sprintf(
 338                  '<p>%s</p>',
 339                  sprintf(
 340                      /* translators: %d: The number of outdated plugins. */
 341                      _n(
 342                          'Your site has %d plugin waiting to be updated.',
 343                          'Your site has %d plugins waiting to be updated.',
 344                          $plugins_need_update
 345                      ),
 346                      $plugins_need_update
 347                  )
 348              );
 349  
 350              $result['actions'] .= sprintf(
 351                  '<p><a href="%s">%s</a></p>',
 352                  esc_url( network_admin_url( 'plugins.php?plugin_status=upgrade' ) ),
 353                  __( 'Update your plugins' )
 354              );
 355          } else {
 356              if ( 1 === $plugins_active ) {
 357                  $result['description'] .= sprintf(
 358                      '<p>%s</p>',
 359                      __( 'Your site has 1 active plugin, and it is up to date.' )
 360                  );
 361              } else {
 362                  $result['description'] .= sprintf(
 363                      '<p>%s</p>',
 364                      sprintf(
 365                          /* translators: %d: The number of active plugins. */
 366                          _n(
 367                              'Your site has %d active plugin, and it is up to date.',
 368                              'Your site has %d active plugins, and they are all up to date.',
 369                              $plugins_active
 370                          ),
 371                          $plugins_active
 372                      )
 373                  );
 374              }
 375          }
 376  
 377          // Check if there are inactive plugins.
 378          if ( $plugins_total > $plugins_active && ! is_multisite() ) {
 379              $unused_plugins = $plugins_total - $plugins_active;
 380  
 381              $result['status'] = 'recommended';
 382  
 383              $result['label'] = __( 'You should remove inactive plugins' );
 384  
 385              $result['description'] .= sprintf(
 386                  '<p>%s %s</p>',
 387                  sprintf(
 388                      /* translators: %d: The number of inactive plugins. */
 389                      _n(
 390                          'Your site has %d inactive plugin.',
 391                          'Your site has %d inactive plugins.',
 392                          $unused_plugins
 393                      ),
 394                      $unused_plugins
 395                  ),
 396                  __( 'Inactive plugins are tempting targets for attackers. If you&#8217;re not going to use a plugin, we recommend you remove it.' )
 397              );
 398  
 399              $result['actions'] .= sprintf(
 400                  '<p><a href="%s">%s</a></p>',
 401                  esc_url( admin_url( 'plugins.php?plugin_status=inactive' ) ),
 402                  __( 'Manage inactive plugins' )
 403              );
 404          }
 405  
 406          return $result;
 407      }
 408  
 409      /**
 410       * Test if themes are outdated, or unnecessary.
 411       *
 412       * The tests checks if your site has a default theme (to fall back on if there is a need), if your themes
 413       * are up to date and, finally, encourages you to remove any themes that are not needed.
 414       *
 415       * @since 5.2.0
 416       *
 417       * @return array The test results.
 418       */
 419  	public function get_test_theme_version() {
 420          $result = array(
 421              'label'       => __( 'Your themes are all up to date' ),
 422              'status'      => 'good',
 423              'badge'       => array(
 424                  'label' => __( 'Security' ),
 425                  'color' => 'blue',
 426              ),
 427              'description' => sprintf(
 428                  '<p>%s</p>',
 429                  __( 'Themes add your site&#8217;s look and feel. It&#8217;s important to keep them up to date, to stay consistent with your brand and keep your site secure.' )
 430              ),
 431              'actions'     => sprintf(
 432                  '<p><a href="%s">%s</a></p>',
 433                  esc_url( admin_url( 'themes.php' ) ),
 434                  __( 'Manage your themes' )
 435              ),
 436              'test'        => 'theme_version',
 437          );
 438  
 439          $theme_updates = get_theme_updates();
 440  
 441          $themes_total        = 0;
 442          $themes_need_updates = 0;
 443          $themes_inactive     = 0;
 444  
 445          // This value is changed during processing to determine how many themes are considered a reasonable amount.
 446          $allowed_theme_count = 1;
 447  
 448          $has_default_theme   = false;
 449          $has_unused_themes   = false;
 450          $show_unused_themes  = true;
 451          $using_default_theme = false;
 452  
 453          // Populate a list of all themes available in the install.
 454          $all_themes   = wp_get_themes();
 455          $active_theme = wp_get_theme();
 456  
 457          // If WP_DEFAULT_THEME doesn't exist, fall back to the latest core default theme.
 458          $default_theme = wp_get_theme( WP_DEFAULT_THEME );
 459          if ( ! $default_theme->exists() ) {
 460              $default_theme = WP_Theme::get_core_default_theme();
 461          }
 462  
 463          if ( $default_theme ) {
 464              $has_default_theme = true;
 465  
 466              if (
 467                  $active_theme->get_stylesheet() === $default_theme->get_stylesheet()
 468              ||
 469                  is_child_theme() && $active_theme->get_template() === $default_theme->get_template()
 470              ) {
 471                  $using_default_theme = true;
 472              }
 473          }
 474  
 475          foreach ( $all_themes as $theme_slug => $theme ) {
 476              $themes_total++;
 477  
 478              if ( array_key_exists( $theme_slug, $theme_updates ) ) {
 479                  $themes_need_updates++;
 480              }
 481          }
 482  
 483          // If this is a child theme, increase the allowed theme count by one, to account for the parent.
 484          if ( is_child_theme() ) {
 485              $allowed_theme_count++;
 486          }
 487  
 488          // If there's a default theme installed and not in use, we count that as allowed as well.
 489          if ( $has_default_theme && ! $using_default_theme ) {
 490              $allowed_theme_count++;
 491          }
 492  
 493          if ( $themes_total > $allowed_theme_count ) {
 494              $has_unused_themes = true;
 495              $themes_inactive   = ( $themes_total - $allowed_theme_count );
 496          }
 497  
 498          // Check if any themes need to be updated.
 499          if ( $themes_need_updates > 0 ) {
 500              $result['status'] = 'critical';
 501  
 502              $result['label'] = __( 'You have themes waiting to be updated' );
 503  
 504              $result['description'] .= sprintf(
 505                  '<p>%s</p>',
 506                  sprintf(
 507                      /* translators: %d: The number of outdated themes. */
 508                      _n(
 509                          'Your site has %d theme waiting to be updated.',
 510                          'Your site has %d themes waiting to be updated.',
 511                          $themes_need_updates
 512                      ),
 513                      $themes_need_updates
 514                  )
 515              );
 516          } else {
 517              // Give positive feedback about the site being good about keeping things up to date.
 518              if ( 1 === $themes_total ) {
 519                  $result['description'] .= sprintf(
 520                      '<p>%s</p>',
 521                      __( 'Your site has 1 installed theme, and it is up to date.' )
 522                  );
 523              } else {
 524                  $result['description'] .= sprintf(
 525                      '<p>%s</p>',
 526                      sprintf(
 527                          /* translators: %d: The number of themes. */
 528                          _n(
 529                              'Your site has %d installed theme, and it is up to date.',
 530                              'Your site has %d installed themes, and they are all up to date.',
 531                              $themes_total
 532                          ),
 533                          $themes_total
 534                      )
 535                  );
 536              }
 537          }
 538  
 539          if ( $has_unused_themes && $show_unused_themes && ! is_multisite() ) {
 540  
 541              // This is a child theme, so we want to be a bit more explicit in our messages.
 542              if ( is_child_theme() ) {
 543                  // Recommend removing inactive themes, except a default theme, your current one, and the parent theme.
 544                  $result['status'] = 'recommended';
 545  
 546                  $result['label'] = __( 'You should remove inactive themes' );
 547  
 548                  if ( $using_default_theme ) {
 549                      $result['description'] .= sprintf(
 550                          '<p>%s %s</p>',
 551                          sprintf(
 552                              /* translators: %d: The number of inactive themes. */
 553                              _n(
 554                                  'Your site has %d inactive theme.',
 555                                  'Your site has %d inactive themes.',
 556                                  $themes_inactive
 557                              ),
 558                              $themes_inactive
 559                          ),
 560                          sprintf(
 561                              /* translators: 1: The currently active theme. 2: The active theme's parent theme. */
 562                              __( '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.' ),
 563                              $active_theme->name,
 564                              $active_theme->parent()->name
 565                          )
 566                      );
 567                  } else {
 568                      $result['description'] .= sprintf(
 569                          '<p>%s %s</p>',
 570                          sprintf(
 571                              /* translators: %d: The number of inactive themes. */
 572                              _n(
 573                                  'Your site has %d inactive theme.',
 574                                  'Your site has %d inactive themes.',
 575                                  $themes_inactive
 576                              ),
 577                              $themes_inactive
 578                          ),
 579                          sprintf(
 580                              /* translators: 1: The default theme for WordPress. 2: The currently active theme. 3: The active theme's parent theme. */
 581                              __( '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.' ),
 582                              $default_theme ? $default_theme->name : WP_DEFAULT_THEME,
 583                              $active_theme->name,
 584                              $active_theme->parent()->name
 585                          )
 586                      );
 587                  }
 588              } else {
 589                  // Recommend removing all inactive themes.
 590                  $result['status'] = 'recommended';
 591  
 592                  $result['label'] = __( 'You should remove inactive themes' );
 593  
 594                  if ( $using_default_theme ) {
 595                      $result['description'] .= sprintf(
 596                          '<p>%s %s</p>',
 597                          sprintf(
 598                              /* translators: 1: The amount of inactive themes. 2: The currently active theme. */
 599                              _n(
 600                                  'Your site has %1$d inactive theme, other than %2$s, your active theme.',
 601                                  'Your site has %1$d inactive themes, other than %2$s, your active theme.',
 602                                  $themes_inactive
 603                              ),
 604                              $themes_inactive,
 605                              $active_theme->name
 606                          ),
 607                          __( 'We recommend removing any unused themes to enhance your site&#8217;s security.' )
 608                      );
 609                  } else {
 610                      $result['description'] .= sprintf(
 611                          '<p>%s %s</p>',
 612                          sprintf(
 613                              /* translators: 1: The amount of inactive themes. 2: The default theme for WordPress. 3: The currently active theme. */
 614                              _n(
 615                                  'Your site has %1$d inactive theme, other than %2$s, the default WordPress theme, and %3$s, your active theme.',
 616                                  'Your site has %1$d inactive themes, other than %2$s, the default WordPress theme, and %3$s, your active theme.',
 617                                  $themes_inactive
 618                              ),
 619                              $themes_inactive,
 620                              $default_theme ? $default_theme->name : WP_DEFAULT_THEME,
 621                              $active_theme->name
 622                          ),
 623                          __( 'We recommend removing any unused themes to enhance your site&#8217;s security.' )
 624                      );
 625                  }
 626              }
 627          }
 628  
 629          // If no default Twenty* theme exists.
 630          if ( ! $has_default_theme ) {
 631              $result['status'] = 'recommended';
 632  
 633              $result['label'] = __( 'Have a default theme available' );
 634  
 635              $result['description'] .= sprintf(
 636                  '<p>%s</p>',
 637                  __( 'Your site does not have any default theme. Default themes are used by WordPress automatically if anything is wrong with your normal theme.' )
 638              );
 639          }
 640  
 641          return $result;
 642      }
 643  
 644      /**
 645       * Test if the supplied PHP version is supported.
 646       *
 647       * @since 5.2.0
 648       *
 649       * @return array The test results.
 650       */
 651  	public function get_test_php_version() {
 652          $response = wp_check_php_version();
 653  
 654          $result = array(
 655              'label'       => sprintf(
 656                  /* translators: %s: The current PHP version. */
 657                  __( 'PHP is up to date (%s)' ),
 658                  PHP_VERSION
 659              ),
 660              'status'      => 'good',
 661              'badge'       => array(
 662                  'label' => __( 'Performance' ),
 663                  'color' => 'blue',
 664              ),
 665              'description' => sprintf(
 666                  '<p>%s</p>',
 667                  __( 'PHP is the programming language we use to build and maintain WordPress. Newer versions of PHP are both faster and more secure, so updating will have a positive effect on your site&#8217;s performance.' )
 668              ),
 669              'actions'     => sprintf(
 670                  '<p><a href="%s" target="_blank" rel="noopener noreferrer">%s <span class="screen-reader-text">%s</span><span aria-hidden="true" class="dashicons dashicons-external"></span></a></p>',
 671                  esc_url( wp_get_update_php_url() ),
 672                  __( 'Learn more about updating PHP' ),
 673                  /* translators: Accessibility text. */
 674                  __( '(opens in a new tab)' )
 675              ),
 676              'test'        => 'php_version',
 677          );
 678  
 679          // PHP is up to date.
 680          if ( ! $response || version_compare( PHP_VERSION, $response['recommended_version'], '>=' ) ) {
 681              return $result;
 682          }
 683  
 684          // The PHP version is older than the recommended version, but still acceptable.
 685          if ( $response['is_supported'] ) {
 686              $result['label']  = __( 'We recommend that you update PHP' );
 687              $result['status'] = 'recommended';
 688  
 689              return $result;
 690          }
 691  
 692          // The PHP version is only receiving security fixes.
 693          if ( $response['is_secure'] ) {
 694              $result['label']  = __( 'Your PHP version should be updated' );
 695              $result['status'] = 'recommended';
 696  
 697              return $result;
 698          }
 699  
 700          // Anything no longer secure must be updated.
 701          $result['label']          = __( 'Your PHP version requires an update' );
 702          $result['status']         = 'critical';
 703          $result['badge']['label'] = __( 'Security' );
 704  
 705          return $result;
 706      }
 707  
 708      /**
 709       * Check if the passed extension or function are available.
 710       *
 711       * Make the check for available PHP modules into a simple boolean operator for a cleaner test runner.
 712       *
 713       * @since 5.2.0
 714       *
 715       * @param string $extension Optional. The extension name to test. Default null.
 716       * @param string $function  Optional. The function name to test. Default null.
 717       *
 718       * @return bool Whether or not the extension and function are available.
 719       */
 720  	private function test_php_extension_availability( $extension = null, $function = null ) {
 721          // If no extension or function is passed, claim to fail testing, as we have nothing to test against.
 722          if ( ! $extension && ! $function ) {
 723              return false;
 724          }
 725  
 726          if ( $extension && ! extension_loaded( $extension ) ) {
 727              return false;
 728          }
 729          if ( $function && ! function_exists( $function ) ) {
 730              return false;
 731          }
 732  
 733          return true;
 734      }
 735  
 736      /**
 737       * Test if required PHP modules are installed on the host.
 738       *
 739       * This test builds on the recommendations made by the WordPress Hosting Team
 740       * as seen at https://make.wordpress.org/hosting/handbook/handbook/server-environment/#php-extensions
 741       *
 742       * @since 5.2.0
 743       *
 744       * @return array
 745       */
 746  	public function get_test_php_extensions() {
 747          $result = array(
 748              'label'       => __( 'Required and recommended modules are installed' ),
 749              'status'      => 'good',
 750              'badge'       => array(
 751                  'label' => __( 'Performance' ),
 752                  'color' => 'blue',
 753              ),
 754              'description' => sprintf(
 755                  '<p>%s</p><p>%s</p>',
 756                  __( 'PHP modules perform most of the tasks on the server that make your site run. Any changes to these must be made by your server administrator.' ),
 757                  sprintf(
 758                      /* translators: 1: Link to the hosting group page about recommended PHP modules. 2: Additional link attributes. 3: Accessibility text. */
 759                      __( 'The WordPress Hosting Team maintains a list of those modules, both recommended and required, in <a href="%1$s" %2$s>the team handbook%3$s</a>.' ),
 760                      /* translators: Localized team handbook, if one exists. */
 761                      esc_url( __( 'https://make.wordpress.org/hosting/handbook/handbook/server-environment/#php-extensions' ) ),
 762                      'target="_blank" rel="noopener noreferrer"',
 763                      sprintf(
 764                          ' <span class="screen-reader-text">%s</span><span aria-hidden="true" class="dashicons dashicons-external"></span>',
 765                          /* translators: Accessibility text. */
 766                          __( '(opens in a new tab)' )
 767                      )
 768                  )
 769              ),
 770              'actions'     => '',
 771              'test'        => 'php_extensions',
 772          );
 773  
 774          $modules = array(
 775              'bcmath'    => array(
 776                  'function' => 'bcadd',
 777                  'required' => false,
 778              ),
 779              'curl'      => array(
 780                  'function' => 'curl_version',
 781                  'required' => false,
 782              ),
 783              'exif'      => array(
 784                  'function' => 'exif_read_data',
 785                  'required' => false,
 786              ),
 787              'filter'    => array(
 788                  'function' => 'filter_list',
 789                  'required' => false,
 790              ),
 791              'fileinfo'  => array(
 792                  'function' => 'finfo_file',
 793                  'required' => false,
 794              ),
 795              'mod_xml'   => array(
 796                  'extension' => 'libxml',
 797                  'required'  => false,
 798              ),
 799              'mysqli'    => array(
 800                  'function' => 'mysqli_connect',
 801                  'required' => false,
 802              ),
 803              'libsodium' => array(
 804                  'function'            => 'sodium_compare',
 805                  'required'            => false,
 806                  'php_bundled_version' => '7.2.0',
 807              ),
 808              'openssl'   => array(
 809                  'function' => 'openssl_encrypt',
 810                  'required' => false,
 811              ),
 812              'pcre'      => array(
 813                  'function' => 'preg_match',
 814                  'required' => false,
 815              ),
 816              'imagick'   => array(
 817                  'extension' => 'imagick',
 818                  'required'  => false,
 819              ),
 820              'gd'        => array(
 821                  'extension'    => 'gd',
 822                  'required'     => false,
 823                  'fallback_for' => 'imagick',
 824              ),
 825              'mcrypt'    => array(
 826                  'extension'    => 'mcrypt',
 827                  'required'     => false,
 828                  'fallback_for' => 'libsodium',
 829              ),
 830              'xmlreader' => array(
 831                  'extension'    => 'xmlreader',
 832                  'required'     => false,
 833                  'fallback_for' => 'xml',
 834              ),
 835              'zlib'      => array(
 836                  'extension'    => 'zlib',
 837                  'required'     => false,
 838                  'fallback_for' => 'zip',
 839              ),
 840          );
 841  
 842          /**
 843           * An array representing all the modules we wish to test for.
 844           *
 845           * @since 5.2.0
 846           *
 847           * @param array $modules {
 848           *     An associated array of modules to test for.
 849           *
 850           *     array $module {
 851           *         An associated array of module properties used during testing.
 852           *         One of either `$function` or `$extension` must be provided, or they will fail by default.
 853           *
 854           *         string $function     Optional. A function name to test for the existence of.
 855           *         string $extension    Optional. An extension to check if is loaded in PHP.
 856           *         bool   $required     Is this a required feature or not.
 857           *         string $fallback_for Optional. The module this module replaces as a fallback.
 858           *     }
 859           * }
 860           */
 861          $modules = apply_filters( 'site_status_test_php_modules', $modules );
 862  
 863          $failures = array();
 864  
 865          foreach ( $modules as $library => $module ) {
 866              $extension = ( isset( $module['extension'] ) ? $module['extension'] : null );
 867              $function  = ( isset( $module['function'] ) ? $module['function'] : null );
 868  
 869              // If this module is a fallback for another function, check if that other function passed.
 870              if ( isset( $module['fallback_for'] ) ) {
 871                  /*
 872                   * If that other function has a failure, mark this module as required for normal operations.
 873                   * If that other function hasn't failed, skip this test as it's only a fallback.
 874                   */
 875                  if ( isset( $failures[ $module['fallback_for'] ] ) ) {
 876                      $module['required'] = true;
 877                  } else {
 878                      continue;
 879                  }
 880              }
 881  
 882              if ( ! $this->test_php_extension_availability( $extension, $function ) && ( ! isset( $module['php_bundled_version'] ) || version_compare( PHP_VERSION, $module['php_bundled_version'], '<' ) ) ) {
 883                  if ( $module['required'] ) {
 884                      $result['status'] = 'critical';
 885  
 886                      $class         = 'error';
 887                      $screen_reader = __( 'Error' );
 888                      $message       = sprintf(
 889                          /* translators: %s: The module name. */
 890                          __( 'The required module, %s, is not installed, or has been disabled.' ),
 891                          $library
 892                      );
 893                  } else {
 894                      $class         = 'warning';
 895                      $screen_reader = __( 'Warning' );
 896                      $message       = sprintf(
 897                          /* translators: %s: The module name. */
 898                          __( 'The optional module, %s, is not installed, or has been disabled.' ),
 899                          $library
 900                      );
 901                  }
 902  
 903                  if ( ! $module['required'] && 'good' === $result['status'] ) {
 904                      $result['status'] = 'recommended';
 905                  }
 906  
 907                  $failures[ $library ] = "<span class='dashicons $class'><span class='screen-reader-text'>$screen_reader</span></span> $message";
 908              }
 909          }
 910  
 911          if ( ! empty( $failures ) ) {
 912              $output = '<ul>';
 913  
 914              foreach ( $failures as $failure ) {
 915                  $output .= sprintf(
 916                      '<li>%s</li>',
 917                      $failure
 918                  );
 919              }
 920  
 921              $output .= '</ul>';
 922          }
 923  
 924          if ( 'good' !== $result['status'] ) {
 925              if ( 'recommended' === $result['status'] ) {
 926                  $result['label'] = __( 'One or more recommended modules are missing' );
 927              }
 928              if ( 'critical' === $result['status'] ) {
 929                  $result['label'] = __( 'One or more required modules are missing' );
 930              }
 931  
 932              $result['description'] .= sprintf(
 933                  '<p>%s</p>',
 934                  $output
 935              );
 936          }
 937  
 938          return $result;
 939      }
 940  
 941      /**
 942       * Test if the SQL server is up to date.
 943       *
 944       * @since 5.2.0
 945       *
 946       * @return array The test results.
 947       */
 948  	public function get_test_sql_server() {
 949          $result = array(
 950              'label'       => __( 'SQL server is up to date' ),
 951              'status'      => 'good',
 952              'badge'       => array(
 953                  'label' => __( 'Performance' ),
 954                  'color' => 'blue',
 955              ),
 956              'description' => sprintf(
 957                  '<p>%s</p>',
 958                  __( 'The SQL server is a required piece of software for the database WordPress uses to store all your site&#8217;s content and settings.' )
 959              ),
 960              'actions'     => sprintf(
 961                  '<p><a href="%s" target="_blank" rel="noopener noreferrer">%s <span class="screen-reader-text">%s</span><span aria-hidden="true" class="dashicons dashicons-external"></span></a></p>',
 962                  /* translators: Localized version of WordPress requirements if one exists. */
 963                  esc_url( __( 'https://wordpress.org/about/requirements/' ) ),
 964                  __( 'Learn more about what WordPress requires to run.' ),
 965                  /* translators: Accessibility text. */
 966                  __( '(opens in a new tab)' )
 967              ),
 968              'test'        => 'sql_server',
 969          );
 970  
 971          $db_dropin = file_exists( WP_CONTENT_DIR . '/db.php' );
 972  
 973          if ( ! $this->mysql_rec_version_check ) {
 974              $result['status'] = 'recommended';
 975  
 976              $result['label'] = __( 'Outdated SQL server' );
 977  
 978              $result['description'] .= sprintf(
 979                  '<p>%s</p>',
 980                  sprintf(
 981                      /* translators: 1: The database engine in use (MySQL or MariaDB). 2: Database server recommended version number. */
 982                      __( 'For optimal performance and security reasons, we recommend running %1$s version %2$s or higher. Contact your web hosting company to correct this.' ),
 983                      ( $this->is_mariadb ? 'MariaDB' : 'MySQL' ),
 984                      $this->health_check_mysql_rec_version
 985                  )
 986              );
 987          }
 988  
 989          if ( ! $this->mysql_min_version_check ) {
 990              $result['status'] = 'critical';
 991  
 992              $result['label']          = __( 'Severely outdated SQL server' );
 993              $result['badge']['label'] = __( 'Security' );
 994  
 995              $result['description'] .= sprintf(
 996                  '<p>%s</p>',
 997                  sprintf(
 998                      /* translators: 1: The database engine in use (MySQL or MariaDB). 2: Database server minimum version number. */
 999                      __( 'WordPress requires %1$s version %2$s or higher. Contact your web hosting company to correct this.' ),
1000                      ( $this->is_mariadb ? 'MariaDB' : 'MySQL' ),
1001                      $this->health_check_mysql_required_version
1002                  )
1003              );
1004          }
1005  
1006          if ( $db_dropin ) {
1007              $result['description'] .= sprintf(
1008                  '<p>%s</p>',
1009                  wp_kses(
1010                      sprintf(
1011                          /* translators: 1: The name of the drop-in. 2: The name of the database engine. */
1012                          __( 'You are using a %1$s drop-in which might mean that a %2$s database is not being used.' ),
1013                          '<code>wp-content/db.php</code>',
1014                          ( $this->is_mariadb ? 'MariaDB' : 'MySQL' )
1015                      ),
1016                      array(
1017                          'code' => true,
1018                      )
1019                  )
1020              );
1021          }
1022  
1023          return $result;
1024      }
1025  
1026      /**
1027       * Test if the database server is capable of using utf8mb4.
1028       *
1029       * @since 5.2.0
1030       *
1031       * @return array The test results.
1032       */
1033  	public function get_test_utf8mb4_support() {
1034          global $wpdb;
1035  
1036          $result = array(
1037              'label'       => __( 'UTF8MB4 is supported' ),
1038              'status'      => 'good',
1039              'badge'       => array(
1040                  'label' => __( 'Performance' ),
1041                  'color' => 'blue',
1042              ),
1043              'description' => sprintf(
1044                  '<p>%s</p>',
1045                  __( 'UTF8MB4 is a database storage attribute that makes sure your site can store non-English text and other strings (for instance emoticons) without unexpected problems.' )
1046              ),
1047              'actions'     => '',
1048              'test'        => 'utf8mb4_support',
1049          );
1050  
1051          if ( ! $this->is_mariadb ) {
1052              if ( version_compare( $this->mysql_server_version, '5.5.3', '<' ) ) {
1053                  $result['status'] = 'recommended';
1054  
1055                  $result['label'] = __( 'utf8mb4 requires a MySQL update' );
1056  
1057                  $result['description'] .= sprintf(
1058                      '<p>%s</p>',
1059                      sprintf(
1060                          /* translators: %s: Version number. */
1061                          __( 'WordPress&#8217; utf8mb4 support requires MySQL version %s or greater. Please contact your server administrator.' ),
1062                          '5.5.3'
1063                      )
1064                  );
1065              } else {
1066                  $result['description'] .= sprintf(
1067                      '<p>%s</p>',
1068                      __( 'Your MySQL version supports utf8mb4.' )
1069                  );
1070              }
1071          } else { // MariaDB introduced utf8mb4 support in 5.5.0
1072              if ( version_compare( $this->mysql_server_version, '5.5.0', '<' ) ) {
1073                  $result['status'] = 'recommended';
1074  
1075                  $result['label'] = __( 'utf8mb4 requires a MariaDB update' );
1076  
1077                  $result['description'] .= sprintf(
1078                      '<p>%s</p>',
1079                      sprintf(
1080                          /* translators: %s: Version number. */
1081                          __( 'WordPress&#8217; utf8mb4 support requires MariaDB version %s or greater. Please contact your server administrator.' ),
1082                          '5.5.0'
1083                      )
1084                  );
1085              } else {
1086                  $result['description'] .= sprintf(
1087                      '<p>%s</p>',
1088                      __( 'Your MariaDB version supports utf8mb4.' )
1089                  );
1090              }
1091          }
1092  
1093          if ( $wpdb->use_mysqli ) {
1094              // phpcs:ignore WordPress.DB.RestrictedFunctions.mysql_mysqli_get_client_info
1095              $mysql_client_version = mysqli_get_client_info();
1096          } else {
1097              // phpcs:ignore WordPress.DB.RestrictedFunctions.mysql_mysql_get_client_info
1098              $mysql_client_version = mysql_get_client_info();
1099          }
1100  
1101          /*
1102           * libmysql has supported utf8mb4 since 5.5.3, same as the MySQL server.
1103           * mysqlnd has supported utf8mb4 since 5.0.9.
1104           */
1105          if ( false !== strpos( $mysql_client_version, 'mysqlnd' ) ) {
1106              $mysql_client_version = preg_replace( '/^\D+([\d.]+).*/', '$1', $mysql_client_version );
1107              if ( version_compare( $mysql_client_version, '5.0.9', '<' ) ) {
1108                  $result['status'] = 'recommended';
1109  
1110                  $result['label'] = __( 'utf8mb4 requires a newer client library' );
1111  
1112                  $result['description'] .= sprintf(
1113                      '<p>%s</p>',
1114                      sprintf(
1115                          /* translators: 1: Name of the library, 2: Number of version. */
1116                          __( 'WordPress&#8217; utf8mb4 support requires MySQL client library (%1$s) version %2$s or newer. Please contact your server administrator.' ),
1117                          'mysqlnd',
1118                          '5.0.9'
1119                      )
1120                  );
1121              }
1122          } else {
1123              if ( version_compare( $mysql_client_version, '5.5.3', '<' ) ) {
1124                  $result['status'] = 'recommended';
1125  
1126                  $result['label'] = __( 'utf8mb4 requires a newer client library' );
1127  
1128                  $result['description'] .= sprintf(
1129                      '<p>%s</p>',
1130                      sprintf(
1131                          /* translators: 1: Name of the library, 2: Number of version. */
1132                          __( 'WordPress&#8217; utf8mb4 support requires MySQL client library (%1$s) version %2$s or newer. Please contact your server administrator.' ),
1133                          'libmysql',
1134                          '5.5.3'
1135                      )
1136                  );
1137              }
1138          }
1139  
1140          return $result;
1141      }
1142  
1143      /**
1144       * Test if the site can communicate with WordPress.org.
1145       *
1146       * @since 5.2.0
1147       *
1148       * @return array The test results.
1149       */
1150  	public function get_test_dotorg_communication() {
1151          $result = array(
1152              'label'       => __( 'Can communicate with WordPress.org' ),
1153              'status'      => '',
1154              'badge'       => array(
1155                  'label' => __( 'Security' ),
1156                  'color' => 'blue',
1157              ),
1158              'description' => sprintf(
1159                  '<p>%s</p>',
1160                  __( 'Communicating with the WordPress servers is used to check for new versions, and to both install and update WordPress core, themes or plugins.' )
1161              ),
1162              'actions'     => '',
1163              'test'        => 'dotorg_communication',
1164          );
1165  
1166          $wp_dotorg = wp_remote_get(
1167              'https://api.wordpress.org',
1168              array(
1169                  'timeout' => 10,
1170              )
1171          );
1172          if ( ! is_wp_error( $wp_dotorg ) ) {
1173              $result['status'] = 'good';
1174          } else {
1175              $result['status'] = 'critical';
1176  
1177              $result['label'] = __( 'Could not reach WordPress.org' );
1178  
1179              $result['description'] .= sprintf(
1180                  '<p>%s</p>',
1181                  sprintf(
1182                      '<span class="error"><span class="screen-reader-text">%s</span></span> %s',
1183                      __( 'Error' ),
1184                      sprintf(
1185                          /* translators: 1: The IP address WordPress.org resolves to. 2: The error returned by the lookup. */
1186                          __( 'Your site is unable to reach WordPress.org at %1$s, and returned the error: %2$s' ),
1187                          gethostbyname( 'api.wordpress.org' ),
1188                          $wp_dotorg->get_error_message()
1189                      )
1190                  )
1191              );
1192  
1193              $result['actions'] = sprintf(
1194                  '<p><a href="%s" target="_blank" rel="noopener noreferrer">%s <span class="screen-reader-text">%s</span><span aria-hidden="true" class="dashicons dashicons-external"></span></a></p>',
1195                  /* translators: Localized Support reference. */
1196                  esc_url( __( 'https://wordpress.org/support' ) ),
1197                  __( 'Get help resolving this issue.' ),
1198                  /* translators: Accessibility text. */
1199                  __( '(opens in a new tab)' )
1200              );
1201          }
1202  
1203          return $result;
1204      }
1205  
1206      /**
1207       * Test if debug information is enabled.
1208       *
1209       * When WP_DEBUG is enabled, errors and information may be disclosed to site visitors, or it may be
1210       * logged to a publicly accessible file.
1211       *
1212       * Debugging is also frequently left enabled after looking for errors on a site, as site owners do
1213       * not understand the implications of this.
1214       *
1215       * @since 5.2.0
1216       *
1217       * @return array The test results.
1218       */
1219  	public function get_test_is_in_debug_mode() {
1220          $result = array(
1221              'label'       => __( 'Your site is not set to output debug information' ),
1222              'status'      => 'good',
1223              'badge'       => array(
1224                  'label' => __( 'Security' ),
1225                  'color' => 'blue',
1226              ),
1227              'description' => sprintf(
1228                  '<p>%s</p>',
1229                  __( 'Debug mode is often enabled to gather more details about an error or site failure, but may contain sensitive information which should not be available on a publicly available website.' )
1230              ),
1231              'actions'     => sprintf(
1232                  '<p><a href="%s" target="_blank" rel="noopener noreferrer">%s <span class="screen-reader-text">%s</span><span aria-hidden="true" class="dashicons dashicons-external"></span></a></p>',
1233                  /* translators: Documentation explaining debugging in WordPress. */
1234                  esc_url( __( 'https://wordpress.org/support/article/debugging-in-wordpress/' ) ),
1235                  __( 'Learn more about debugging in WordPress.' ),
1236                  /* translators: Accessibility text. */
1237                  __( '(opens in a new tab)' )
1238              ),
1239              'test'        => 'is_in_debug_mode',
1240          );
1241  
1242          if ( defined( 'WP_DEBUG' ) && WP_DEBUG ) {
1243              if ( defined( 'WP_DEBUG_LOG' ) && WP_DEBUG_LOG ) {
1244                  $result['label'] = __( 'Your site is set to log errors to a potentially public file.' );
1245  
1246                  $result['status'] = 'critical';
1247  
1248                  $result['description'] .= sprintf(
1249                      '<p>%s</p>',
1250                      sprintf(
1251                          /* translators: %s: WP_DEBUG_LOG */
1252                          __( 'The value, %s, has been added to this website&#8217;s configuration file. This means any errors on the site will be written to a file which is potentially available to normal users.' ),
1253                          '<code>WP_DEBUG_LOG</code>'
1254                      )
1255                  );
1256              }
1257  
1258              if ( defined( 'WP_DEBUG_DISPLAY' ) && WP_DEBUG_DISPLAY ) {
1259                  $result['label'] = __( 'Your site is set to display errors to site visitors' );
1260  
1261                  $result['status'] = 'critical';
1262  
1263                  $result['description'] .= sprintf(
1264                      '<p>%s</p>',
1265                      sprintf(
1266                          /* translators: 1: WP_DEBUG_DISPLAY, 2: WP_DEBUG */
1267                          __( 'The value, %1$s, has either been enabled by %2$s or added to your configuration file. This will make errors display on the front end of your site.' ),
1268                          '<code>WP_DEBUG_DISPLAY</code>',
1269                          '<code>WP_DEBUG</code>'
1270                      )
1271                  );
1272              }
1273          }
1274  
1275          return $result;
1276      }
1277  
1278      /**
1279       * Test if your site is serving content over HTTPS.
1280       *
1281       * Many sites have varying degrees of HTTPS support, the most common of which is sites that have it
1282       * enabled, but only if you visit the right site address.
1283       *
1284       * @since 5.2.0
1285       *
1286       * @return array The test results.
1287       */
1288  	public function get_test_https_status() {
1289          $result = array(
1290              'label'       => __( 'Your website is using an active HTTPS connection.' ),
1291              'status'      => 'good',
1292              'badge'       => array(
1293                  'label' => __( 'Security' ),
1294                  'color' => 'blue',
1295              ),
1296              'description' => sprintf(
1297                  '<p>%s</p>',
1298                  __( 'An HTTPS connection is needed for many features on the web today, it also gains the trust of your visitors by helping to protecting their online privacy.' )
1299              ),
1300              'actions'     => sprintf(
1301                  '<p><a href="%s" target="_blank" rel="noopener noreferrer">%s <span class="screen-reader-text">%s</span><span aria-hidden="true" class="dashicons dashicons-external"></span></a></p>',
1302                  /* translators: Documentation explaining HTTPS and why it should be used. */
1303                  esc_url( __( 'https://wordpress.org/support/article/why-should-i-use-https/' ) ),
1304                  __( 'Learn more about why you should use HTTPS' ),
1305                  /* translators: Accessibility text. */
1306                  __( '(opens in a new tab)' )
1307              ),
1308              'test'        => 'https_status',
1309          );
1310  
1311          if ( is_ssl() ) {
1312              $wp_url   = get_bloginfo( 'wpurl' );
1313              $site_url = get_bloginfo( 'url' );
1314  
1315              if ( 'https' !== substr( $wp_url, 0, 5 ) || 'https' !== substr( $site_url, 0, 5 ) ) {
1316                  $result['status'] = 'recommended';
1317  
1318                  $result['label'] = __( 'Only parts of your site are using HTTPS' );
1319  
1320                  $result['description'] = sprintf(
1321                      '<p>%s</p>',
1322                      sprintf(
1323                          /* translators: %s: URL to General Settings screen. */
1324                          __( 'You are accessing this website using HTTPS, but your <a href="%s">WordPress Address</a> is not set up to use HTTPS by default.' ),
1325                          esc_url( admin_url( 'options-general.php' ) )
1326                      )
1327                  );
1328  
1329                  $result['actions'] .= sprintf(
1330                      '<p><a href="%s">%s</a></p>',
1331                      esc_url( admin_url( 'options-general.php' ) ),
1332                      __( 'Update your site addresses' )
1333                  );
1334              }
1335          } else {
1336              $result['status'] = 'recommended';
1337  
1338              $result['label'] = __( 'Your site does not use HTTPS' );
1339          }
1340  
1341          return $result;
1342      }
1343  
1344      /**
1345       * Check if the HTTP API can handle SSL/TLS requests.
1346       *
1347       * @since 5.2.0
1348       *
1349       * @return array The test results.
1350       */
1351  	public function get_test_ssl_support() {
1352          $result = array(
1353              'label'       => '',
1354              'status'      => '',
1355              'badge'       => array(
1356                  'label' => __( 'Security' ),
1357                  'color' => 'blue',
1358              ),
1359              'description' => sprintf(
1360                  '<p>%s</p>',
1361                  __( 'Securely communicating between servers are needed for transactions such as fetching files, conducting sales on store sites, and much more.' )
1362              ),
1363              'actions'     => '',
1364              'test'        => 'ssl_support',
1365          );
1366  
1367          $supports_https = wp_http_supports( array( 'ssl' ) );
1368  
1369          if ( $supports_https ) {
1370              $result['status'] = 'good';
1371  
1372              $result['label'] = __( 'Your site can communicate securely with other services' );
1373          } else {
1374              $result['status'] = 'critical';
1375  
1376              $result['label'] = __( 'Your site is unable to communicate securely with other services' );
1377  
1378              $result['description'] .= sprintf(
1379                  '<p>%s</p>',
1380                  __( 'Talk to your web host about OpenSSL support for PHP.' )
1381              );
1382          }
1383  
1384          return $result;
1385      }
1386  
1387      /**
1388       * Test if scheduled events run as intended.
1389       *
1390       * If scheduled events are not running, this may indicate something with WP_Cron is not working as intended,
1391       * or that there are orphaned events hanging around from older code.
1392       *
1393       * @since 5.2.0
1394       *
1395       * @return array The test results.
1396       */
1397  	public function get_test_scheduled_events() {
1398          $result = array(
1399              'label'       => __( 'Scheduled events are running' ),
1400              'status'      => 'good',
1401              'badge'       => array(
1402                  'label' => __( 'Performance' ),
1403                  'color' => 'blue',
1404              ),
1405              'description' => sprintf(
1406                  '<p>%s</p>',
1407                  __( 'Scheduled events are what periodically looks for updates to plugins, themes and WordPress itself. It is also what makes sure scheduled posts are published on time. It may also be used by various plugins to make sure that planned actions are executed.' )
1408              ),
1409              'actions'     => '',
1410              'test'        => 'scheduled_events',
1411          );
1412  
1413          $this->wp_schedule_test_init();
1414  
1415          if ( is_wp_error( $this->has_missed_cron() ) ) {
1416              $result['status'] = 'critical';
1417  
1418              $result['label'] = __( 'It was not possible to check your scheduled events' );
1419  
1420              $result['description'] = sprintf(
1421                  '<p>%s</p>',
1422                  sprintf(
1423                      /* translators: %s: The error message returned while from the cron scheduler. */
1424                      __( 'While trying to test your site&#8217;s scheduled events, the following error was returned: %s' ),
1425                      $this->has_missed_cron()->get_error_message()
1426                  )
1427              );
1428          } elseif ( $this->has_missed_cron() ) {
1429              $result['status'] = 'recommended';
1430  
1431              $result['label'] = __( 'A scheduled event has failed' );
1432  
1433              $result['description'] = sprintf(
1434                  '<p>%s</p>',
1435                  sprintf(
1436                      /* translators: %s: The name of the failed cron event. */
1437                      __( 'The scheduled event, %s, failed to run. Your site still works, but this may indicate that scheduling posts or automated updates may not work as intended.' ),
1438                      $this->last_missed_cron
1439                  )
1440              );
1441          } elseif ( $this->has_late_cron() ) {
1442              $result['status'] = 'recommended';
1443  
1444              $result['label'] = __( 'A scheduled event is late' );
1445  
1446              $result['description'] = sprintf(
1447                  '<p>%s</p>',
1448                  sprintf(
1449                      /* translators: %s: The name of the late cron event. */
1450                      __( 'The scheduled event, %s, is late to run. Your site still works, but this may indicate that scheduling posts or automated updates may not work as intended.' ),
1451                      $this->last_late_cron
1452                  )
1453              );
1454          }
1455  
1456          return $result;
1457      }
1458  
1459      /**
1460       * Test if WordPress can run automated background updates.
1461       *
1462       * Background updates in WordPress are primarily used for minor releases and security updates. It's important
1463       * to either have these working, or be aware that they are intentionally disabled for whatever reason.
1464       *
1465       * @since 5.2.0
1466       *
1467       * @return array The test results.
1468       */
1469  	public function get_test_background_updates() {
1470          $result = array(
1471              'label'       => __( 'Background updates are working' ),
1472              'status'      => 'good',
1473              'badge'       => array(
1474                  'label' => __( 'Security' ),
1475                  'color' => 'blue',
1476              ),
1477              'description' => sprintf(
1478                  '<p>%s</p>',
1479                  __( 'Background updates ensure that WordPress can auto-update if a security update is released for the version you are currently using.' )
1480              ),
1481              'actions'     => '',
1482              'test'        => 'background_updates',
1483          );
1484  
1485          if ( ! class_exists( 'WP_Site_Health_Auto_Updates' ) ) {
1486              require_once( ABSPATH . 'wp-admin/includes/class-wp-site-health-auto-updates.php' );
1487          }
1488  
1489          // Run the auto-update tests in a separate class,
1490          // as there are many considerations to be made.
1491          $automatic_updates = new WP_Site_Health_Auto_Updates();
1492          $tests             = $automatic_updates->run_tests();
1493  
1494          $output = '<ul>';
1495  
1496          foreach ( $tests as $test ) {
1497              $severity_string = __( 'Passed' );
1498  
1499              if ( 'fail' === $test->severity ) {
1500                  $result['label'] = __( 'Background updates are not working as expected' );
1501  
1502                  $result['status'] = 'critical';
1503  
1504                  $severity_string = __( 'Error' );
1505              }
1506  
1507              if ( 'warning' === $test->severity && 'good' === $result['status'] ) {
1508                  $result['label'] = __( 'Background updates may not be working properly' );
1509  
1510                  $result['status'] = 'recommended';
1511  
1512                  $severity_string = __( 'Warning' );
1513              }
1514  
1515              $output .= sprintf(
1516                  '<li><span class="dashicons %s"><span class="screen-reader-text">%s</span></span> %s</li>',
1517                  esc_attr( $test->severity ),
1518                  $severity_string,
1519                  $test->description
1520              );
1521          }
1522  
1523          $output .= '</ul>';
1524  
1525          if ( 'good' !== $result['status'] ) {
1526              $result['description'] .= sprintf(
1527                  '<p>%s</p>',
1528                  $output
1529              );
1530          }
1531  
1532          return $result;
1533      }
1534  
1535      /**
1536       * Test if loopbacks work as expected.
1537       *
1538       * A loopback is when WordPress queries itself, for example to start a new WP_Cron instance, or when editing a
1539       * plugin or theme. This has shown itself to be a recurring issue as code can very easily break this interaction.
1540       *
1541       * @since 5.2.0
1542       *
1543       * @return array The test results.
1544       */
1545  	public function get_test_loopback_requests() {
1546          $result = array(
1547              'label'       => __( 'Your site can perform loopback requests' ),
1548              'status'      => 'good',
1549              'badge'       => array(
1550                  'label' => __( 'Performance' ),
1551                  'color' => 'blue',
1552              ),
1553              'description' => sprintf(
1554                  '<p>%s</p>',
1555                  __( 'Loopback requests are used to run scheduled events, and are also used by the built-in editors for themes and plugins to verify code stability.' )
1556              ),
1557              'actions'     => '',
1558              'test'        => 'loopback_requests',
1559          );
1560  
1561          $check_loopback = $this->can_perform_loopback();
1562  
1563          $result['status'] = $check_loopback->status;
1564  
1565          if ( 'good' !== $check_loopback->status ) {
1566              $result['label'] = __( 'Your site could not complete a loopback request' );
1567  
1568              $result['description'] .= sprintf(
1569                  '<p>%s</p>',
1570                  $check_loopback->message
1571              );
1572          }
1573  
1574          return $result;
1575      }
1576  
1577      /**
1578       * Test if HTTP requests are blocked.
1579       *
1580       * It's possible to block all outgoing communication (with the possibility of whitelisting hosts) via the
1581       * HTTP API. This may create problems for users as many features are running as services these days.
1582       *
1583       * @since 5.2.0
1584       *
1585       * @return array The test results.
1586       */
1587  	public function get_test_http_requests() {
1588          $result = array(
1589              'label'       => __( 'HTTP requests seem to be working as expected' ),
1590              'status'      => 'good',
1591              'badge'       => array(
1592                  'label' => __( 'Performance' ),
1593                  'color' => 'blue',
1594              ),
1595              'description' => sprintf(
1596                  '<p>%s</p>',
1597                  __( 'It is possible for site maintainers to block all, or some, communication to other sites and services. If set up incorrectly, this may prevent plugins and themes from working as intended.' )
1598              ),
1599              'actions'     => '',
1600              'test'        => 'http_requests',
1601          );
1602  
1603          $blocked = false;
1604          $hosts   = array();
1605  
1606          if ( defined( 'WP_HTTP_BLOCK_EXTERNAL' ) && WP_HTTP_BLOCK_EXTERNAL ) {
1607              $blocked = true;
1608          }
1609  
1610          if ( defined( 'WP_ACCESSIBLE_HOSTS' ) ) {
1611              $hosts = explode( ',', WP_ACCESSIBLE_HOSTS );
1612          }
1613  
1614          if ( $blocked && 0 === sizeof( $hosts ) ) {
1615              $result['status'] = 'critical';
1616  
1617              $result['label'] = __( 'HTTP requests are blocked' );
1618  
1619              $result['description'] .= sprintf(
1620                  '<p>%s</p>',
1621                  sprintf(
1622                      /* translators: %s: Name of the constant used. */
1623                      __( 'HTTP requests have been blocked by the %s constant, with no allowed hosts.' ),
1624                      '<code>WP_HTTP_BLOCK_EXTERNAL</code>'
1625                  )
1626              );
1627          }
1628  
1629          if ( $blocked && 0 < sizeof( $hosts ) ) {
1630              $result['status'] = 'recommended';
1631  
1632              $result['label'] = __( 'HTTP requests are partially blocked' );
1633  
1634              $result['description'] .= sprintf(
1635                  '<p>%s</p>',
1636                  sprintf(
1637                      /* translators: 1: Name of the constant used. 2: List of hostnames whitelisted. */
1638                      __( 'HTTP requests have been blocked by the %1$s constant, with some hosts whitelisted: %2$s.' ),
1639                      '<code>WP_HTTP_BLOCK_EXTERNAL</code>',
1640                      implode( ',', $hosts )
1641                  )
1642              );
1643          }
1644  
1645          return $result;
1646      }
1647  
1648      /**
1649       * Test if the REST API is accessible.
1650       *
1651       * Various security measures may block the REST API from working, or it may have been disabled in general.
1652       * This is required for the new block editor to work, so we explicitly test for this.
1653       *
1654       * @since 5.2.0
1655       *
1656       * @return array The test results.
1657       */
1658  	public function get_test_rest_availability() {
1659          $result = array(
1660              'label'       => __( 'The REST API is available' ),
1661              'status'      => 'good',
1662              'badge'       => array(
1663                  'label' => __( 'Performance' ),
1664                  'color' => 'blue',
1665              ),
1666              'description' => sprintf(
1667                  '<p>%s</p>',
1668                  __( 'The REST API is one way WordPress, and other applications, communicate with the server. One example is the block editor screen, which relies on this to display, and save, your posts and pages.' )
1669              ),
1670              'actions'     => '',
1671              'test'        => 'rest_availability',
1672          );
1673  
1674          $cookies = wp_unslash( $_COOKIE );
1675          $timeout = 10;
1676          $headers = array(
1677              'Cache-Control' => 'no-cache',
1678              'X-WP-Nonce'    => wp_create_nonce( 'wp_rest' ),
1679          );
1680  
1681          // Include Basic auth in loopback requests.
1682          if ( isset( $_SERVER['PHP_AUTH_USER'] ) && isset( $_SERVER['PHP_AUTH_PW'] ) ) {
1683              $headers['Authorization'] = 'Basic ' . base64_encode( wp_unslash( $_SERVER['PHP_AUTH_USER'] ) . ':' . wp_unslash( $_SERVER['PHP_AUTH_PW'] ) );
1684          }
1685  
1686          $url = rest_url( 'wp/v2/types/post' );
1687  
1688          // The context for this is editing with the new block editor.
1689          $url = add_query_arg(
1690              array(
1691                  'context' => 'edit',
1692              ),
1693              $url
1694          );
1695  
1696          $r = wp_remote_get( $url, compact( 'cookies', 'headers', 'timeout' ) );
1697  
1698          if ( is_wp_error( $r ) ) {
1699              $result['status'] = 'critical';
1700  
1701              $result['label'] = __( 'The REST API encountered an error' );
1702  
1703              $result['description'] .= sprintf(
1704                  '<p>%s</p>',
1705                  sprintf(
1706                      '%s<br>%s',
1707                      __( 'The REST API request failed due to an error.' ),
1708                      sprintf(
1709                          /* translators: 1: The HTTP response code. 2: The error message returned. */
1710                          __( 'Error: [%1$s] %2$s' ),
1711                          wp_remote_retrieve_response_code( $r ),
1712                          $r->get_error_message()
1713                      )
1714                  )
1715              );
1716          } elseif ( 200 !== wp_remote_retrieve_response_code( $r ) ) {
1717              $result['status'] = 'recommended';
1718  
1719              $result['label'] = __( 'The REST API encountered an unexpected result' );
1720  
1721              $result['description'] .= sprintf(
1722                  '<p>%s</p>',
1723                  sprintf(
1724                      /* translators: 1: The HTTP response code returned. 2: The error message returned. */
1725                      __( 'The REST API call gave the following unexpected result: (%1$d) %2$s.' ),
1726                      wp_remote_retrieve_response_code( $r ),
1727                      wp_remote_retrieve_body( $r )
1728                  )
1729              );
1730          } else {
1731              $json = json_decode( wp_remote_retrieve_body( $r ), true );
1732  
1733              if ( false !== $json && ! isset( $json['capabilities'] ) ) {
1734                  $result['status'] = 'recommended';
1735  
1736                  $result['label'] = __( 'The REST API did not behave correctly' );
1737  
1738                  $result['description'] .= sprintf(
1739                      '<p>%s</p>',
1740                      sprintf(
1741                          /* translators: %s: The name of the query parameter being tested. */
1742                          __( 'The REST API did not process the %s query parameter correctly.' ),
1743                          '<code>context</code>'
1744                      )
1745                  );
1746              }
1747          }
1748  
1749          return $result;
1750      }
1751  
1752      /**
1753       * Return a set of tests that belong to the site status page.
1754       *
1755       * Each site status test is defined here, they may be `direct` tests, that run on page load, or `async` tests
1756       * which will run later down the line via JavaScript calls to improve page performance and hopefully also user
1757       * experiences.
1758       *
1759       * @since 5.2.0
1760       *
1761       * @return array The list of tests to run.
1762       */
1763  	public static function get_tests() {
1764          $tests = array(
1765              'direct' => array(
1766                  'wordpress_version' => array(
1767                      'label' => __( 'WordPress Version' ),
1768                      'test'  => 'wordpress_version',
1769                  ),
1770                  'plugin_version'    => array(
1771                      'label' => __( 'Plugin Versions' ),
1772                      'test'  => 'plugin_version',
1773                  ),
1774                  'theme_version'     => array(
1775                      'label' => __( 'Theme Versions' ),
1776                      'test'  => 'theme_version',
1777                  ),
1778                  'php_version'       => array(
1779                      'label' => __( 'PHP Version' ),
1780                      'test'  => 'php_version',
1781                  ),
1782                  'sql_server'        => array(
1783                      'label' => __( 'Database Server version' ),
1784                      'test'  => 'sql_server',
1785                  ),
1786                  'php_extensions'    => array(
1787                      'label' => __( 'PHP Extensions' ),
1788                      'test'  => 'php_extensions',
1789                  ),
1790                  'utf8mb4_support'   => array(
1791                      'label' => __( 'MySQL utf8mb4 support' ),
1792                      'test'  => 'utf8mb4_support',
1793                  ),
1794                  'https_status'      => array(
1795                      'label' => __( 'HTTPS status' ),
1796                      'test'  => 'https_status',
1797                  ),
1798                  'ssl_support'       => array(
1799                      'label' => __( 'Secure communication' ),
1800                      'test'  => 'ssl_support',
1801                  ),
1802                  'scheduled_events'  => array(
1803                      'label' => __( 'Scheduled events' ),
1804                      'test'  => 'scheduled_events',
1805                  ),
1806                  'http_requests'     => array(
1807                      'label' => __( 'HTTP Requests' ),
1808                      'test'  => 'http_requests',
1809                  ),
1810                  'debug_enabled'     => array(
1811                      'label' => __( 'Debugging enabled' ),
1812                      'test'  => 'is_in_debug_mode',
1813                  ),
1814              ),
1815              'async'  => array(
1816                  'dotorg_communication' => array(
1817                      'label' => __( 'Communication with WordPress.org' ),
1818                      'test'  => 'dotorg_communication',
1819                  ),
1820                  'background_updates'   => array(
1821                      'label' => __( 'Background updates' ),
1822                      'test'  => 'background_updates',
1823                  ),
1824                  'loopback_requests'    => array(
1825                      'label' => __( 'Loopback request' ),
1826                      'test'  => 'loopback_requests',
1827                  ),
1828              ),
1829          );
1830  
1831          // Conditionally include REST rules if the function for it exists.
1832          if ( function_exists( 'rest_url' ) ) {
1833              $tests['direct']['rest_availability'] = array(
1834                  'label' => __( 'REST API availability' ),
1835                  'test'  => 'rest_availability',
1836              );
1837          }
1838  
1839          /**
1840           * Add or modify which site status tests are run on a site.
1841           *
1842           * The site health is determined by a set of tests based on best practices from
1843           * both the WordPress Hosting Team, but also web standards in general.
1844           *
1845           * Some sites may not have the same requirements, for example the automatic update
1846           * checks may be handled by a host, and are therefore disabled in core.
1847           * Or maybe you want to introduce a new test, is caching enabled/disabled/stale for example.
1848           *
1849           * Tests may be added either as direct, or asynchronous ones. Any test that may require some time
1850           * to complete should run asynchronously, to avoid extended loading periods within wp-admin.
1851           *
1852           * @since 5.2.0
1853           *
1854           * @param array $test_type {
1855           *     An associative array, where the `$test_type` is either `direct` or
1856           *     `async`, to declare if the test should run via AJAX calls after page load.
1857           *
1858           *     @type array $identifier {
1859           *         `$identifier` should be a unique identifier for the test that should run.
1860           *         Plugins and themes are encouraged to prefix test identifiers with their slug
1861           *         to avoid any collisions between tests.
1862           *
1863           *         @type string $label A friendly label for your test to identify it by.
1864           *         @type mixed  $test  A callable to perform a direct test, or a string AJAX action to be called
1865           *                             to perform an async test.
1866           *     }
1867           * }
1868           */
1869          $tests = apply_filters( 'site_status_tests', $tests );
1870  
1871          return $tests;
1872      }
1873  
1874      /**
1875       * Add a class to the body HTML tag.
1876       *
1877       * Filters the body class string for admin pages and adds our own class for easier styling.
1878       *
1879       * @since 5.2.0
1880       *
1881       * @param string $body_class The body class string.
1882       * @return string The modified body class string.
1883       */
1884  	public function admin_body_class( $body_class ) {
1885          $body_class .= ' site-health';
1886  
1887          return $body_class;
1888      }
1889  
1890      /**
1891       * Initiate the WP_Cron schedule test cases.
1892       *
1893       * @since 5.2.0
1894       */
1895  	private function wp_schedule_test_init() {
1896          $this->schedules = wp_get_schedules();
1897          $this->get_cron_tasks();
1898      }
1899  
1900      /**
1901       * Populate our list of cron events and store them to a class-wide variable.
1902       *
1903       * @since 5.2.0
1904       */
1905  	private function get_cron_tasks() {
1906          $cron_tasks = _get_cron_array();
1907  
1908          if ( empty( $cron_tasks ) ) {
1909              $this->crons = new WP_Error( 'no_tasks', __( 'No scheduled events exist on this site.' ) );
1910              return;
1911          }
1912  
1913          $this->crons = array();
1914  
1915          foreach ( $cron_tasks as $time => $cron ) {
1916              foreach ( $cron as $hook => $dings ) {
1917                  foreach ( $dings as $sig => $data ) {
1918  
1919                      $this->crons[ "$hook-$sig-$time" ] = (object) array(
1920                          'hook'     => $hook,
1921                          'time'     => $time,
1922                          'sig'      => $sig,
1923                          'args'     => $data['args'],
1924                          'schedule' => $data['schedule'],
1925                          'interval' => isset( $data['interval'] ) ? $data['interval'] : null,
1926                      );
1927  
1928                  }
1929              }
1930          }
1931      }
1932  
1933      /**
1934       * Check if any scheduled tasks have been missed.
1935       *
1936       * Returns a boolean value of `true` if a scheduled task has been missed and ends processing. If the list of
1937       * crons is an instance of WP_Error, return the instance instead of a boolean value.
1938       *
1939       * @since 5.2.0
1940       *
1941       * @return bool|WP_Error True if a cron was missed, false if not. WP_Error if the cron is set to that.
1942       */
1943  	public function has_missed_cron() {
1944          if ( is_wp_error( $this->crons ) ) {
1945              return $this->crons;
1946          }
1947  
1948          foreach ( $this->crons as $id => $cron ) {
1949              if ( ( $cron->time - time() ) < $this->timeout_missed_cron ) {
1950                  $this->last_missed_cron = $cron->hook;
1951                  return true;
1952              }
1953          }
1954  
1955          return false;
1956      }
1957  
1958      /**
1959       * Check if any scheduled tasks are late.
1960       *
1961       * Returns a boolean value of `true` if a scheduled task is late and ends processing. If the list of
1962       * crons is an instance of WP_Error, return the instance instead of a boolean value.
1963       *
1964       * @since 5.3.0
1965       *
1966       * @return bool|WP_Error True if a cron is late, false if not. WP_Error if the cron is set to that.
1967       */
1968  	public function has_late_cron() {
1969          if ( is_wp_error( $this->crons ) ) {
1970              return $this->crons;
1971          }
1972  
1973          foreach ( $this->crons as $id => $cron ) {
1974              $cron_offset = $cron->time - time();
1975              if (
1976                      $cron_offset >= $this->timeout_missed_cron &&
1977                      $cron_offset < $this->timeout_late_cron
1978                  ) {
1979                  $this->last_late_cron = $cron->hook;
1980                  return true;
1981              }
1982          }
1983  
1984          return false;
1985      }
1986  
1987      /**
1988       * Run a loopback test on our site.
1989       *
1990       * Loopbacks are what WordPress uses to communicate with itself to start up WP_Cron, scheduled posts,
1991       * make sure plugin or theme edits don't cause site failures and similar.
1992       *
1993       * @since 5.2.0
1994       *
1995       * @return object The test results.
1996       */
1997  	function can_perform_loopback() {
1998          $cookies = wp_unslash( $_COOKIE );
1999          $timeout = 10;
2000          $headers = array(
2001              'Cache-Control' => 'no-cache',
2002          );
2003  
2004          // Include Basic auth in loopback requests.
2005          if ( isset( $_SERVER['PHP_AUTH_USER'] ) && isset( $_SERVER['PHP_AUTH_PW'] ) ) {
2006              $headers['Authorization'] = 'Basic ' . base64_encode( wp_unslash( $_SERVER['PHP_AUTH_USER'] ) . ':' . wp_unslash( $_SERVER['PHP_AUTH_PW'] ) );
2007          }
2008  
2009          $url = admin_url();
2010  
2011          $r = wp_remote_get( $url, compact( 'cookies', 'headers', 'timeout' ) );
2012  
2013          if ( is_wp_error( $r ) ) {
2014              return (object) array(
2015                  'status'  => 'critical',
2016                  'message' => sprintf(
2017                      '%s<br>%s',
2018                      __( 'The loopback request to your site failed, this means features relying on them are not currently working as expected.' ),
2019                      sprintf(
2020                          /* translators: 1: The HTTP response code. 2: The error message returned. */
2021                          __( 'Error: [%1$s] %2$s' ),
2022                          wp_remote_retrieve_response_code( $r ),
2023                          $r->get_error_message()
2024                      )
2025                  ),
2026              );
2027          }
2028  
2029          if ( 200 !== wp_remote_retrieve_response_code( $r ) ) {
2030              return (object) array(
2031                  'status'  => 'recommended',
2032                  'message' => sprintf(
2033                      /* translators: %d: The HTTP response code returned. */
2034                      __( 'The loopback request returned an unexpected http status code, %d, it was not possible to determine if this will prevent features from working as expected.' ),
2035                      wp_remote_retrieve_response_code( $r )
2036                  ),
2037              );
2038          }
2039  
2040          return (object) array(
2041              'status'  => 'good',
2042              'message' => __( 'The loopback request to your site completed successfully.' ),
2043          );
2044      }
2045  }


Generated: Sat Sep 21 01:00:03 2019 Cross-referenced by PHPXref 0.7.1