File "class-wp-site-health.php"
Full path: /home/kosmetik/public_html/wp-includes/wp-admin/includes/class-wp-site-health.php
File
size: 65.67 B
MIME-type: text/x-php
Charset: utf-8
Download Open Edit Advanced Editor Back
<?php
class WP_Site_Health
{
private static $instance = null;
private $mysql_min_version_check;
private $mysql_rec_version_check;
public $is_mariadb = false;
private $mysql_server_version = '';
private $health_check_mysql_required_version = '5.5';
private $health_check_mysql_rec_version = '';
public $php_memory_limit;
public $schedules;
public $crons;
public $last_missed_cron = null;
public $last_late_cron = null;
private $timeout_missed_cron = null;
private $timeout_late_cron = null;
public function __construct()
{
$this->maybe_create_scheduled_event();
$this->php_memory_limit = ini_get('memory_limit');
$this->timeout_late_cron = 0;
$this->timeout_missed_cron = -5 * MINUTE_IN_SECONDS;
if (defined('DISABLE_WP_CRON') && DISABLE_WP_CRON) {
$this->timeout_late_cron = -15 * MINUTE_IN_SECONDS;
$this->timeout_missed_cron = -1 * HOUR_IN_SECONDS;
}
add_filter('admin_body_class', array($this, 'admin_body_class'));
add_action('admin_enqueue_scripts', array($this, 'enqueue_scripts'));
add_action('wp_site_health_scheduled_check', array($this, 'wp_cron_scheduled_check'));
}
public static function get_instance()
{
if (null === self::$instance) {
self::$instance = new WP_Site_Health();
}
return self::$instance;
}
public function enqueue_scripts()
{
$screen = get_current_screen();
if ('site-health' !== $screen->id && 'dashboard' !== $screen->id) {
return;
}
$health_check_js_variables = array('screen' => $screen->id, 'nonce' => array('site_status' => wp_create_nonce('health-check-site-status'), 'site_status_result' => wp_create_nonce('health-check-site-status-result')), 'site_status' => array('direct' => array(), 'async' => array(), 'issues' => array('good' => 0, 'recommended' => 0, 'critical' => 0)));
$issue_counts = get_transient('health-check-site-status-result');
if (false !== $issue_counts) {
$issue_counts = json_decode($issue_counts);
$health_check_js_variables['site_status']['issues'] = $issue_counts;
}
if ('site-health' === $screen->id && !isset($_GET['tab'])) {
$tests = WP_Site_Health::get_tests();
if ($this->is_development_environment()) {
unset($tests['async']['https_status']);
}
foreach ($tests['direct'] as $test) {
if (is_string($test['test'])) {
$test_function = sprintf('get_test_%s', $test['test']);
if (method_exists($this, $test_function) && is_callable(array($this, $test_function))) {
$health_check_js_variables['site_status']['direct'][] = $this->perform_test(array($this, $test_function));
continue;
}
}
if (is_callable($test['test'])) {
$health_check_js_variables['site_status']['direct'][] = $this->perform_test($test['test']);
}
}
foreach ($tests['async'] as $test) {
if (is_string($test['test'])) {
$health_check_js_variables['site_status']['async'][] = array('test' => $test['test'], 'has_rest' => isset($test['has_rest']) ? $test['has_rest'] : false, 'completed' => false, 'headers' => isset($test['headers']) ? $test['headers'] : array());
}
}
}
wp_localize_script('site-health', 'SiteHealth', $health_check_js_variables);
}
private function perform_test($callback)
{
return apply_filters('site_status_test_result', call_user_func($callback));
}
private function prepare_sql_data()
{
global $wpdb;
if ($wpdb->use_mysqli) {
$mysql_server_type = mysqli_get_server_info($wpdb->dbh);
} else {
$mysql_server_type = mysql_get_server_info($wpdb->dbh);
}
$this->mysql_server_version = $wpdb->get_var('SELECT VERSION()');
$this->health_check_mysql_rec_version = '5.6';
if (stristr($mysql_server_type, 'mariadb')) {
$this->is_mariadb = true;
$this->health_check_mysql_rec_version = '10.0';
}
$this->mysql_min_version_check = version_compare('5.5', $this->mysql_server_version, '<=');
$this->mysql_rec_version_check = version_compare($this->health_check_mysql_rec_version, $this->mysql_server_version, '<=');
}
public function check_wp_version_check_exists()
{
if (!is_admin() || !is_user_logged_in() || !current_user_can('update_core') || !isset($_GET['health-check-test-wp_version_check'])) {
return;
}
echo has_filter('wp_version_check', 'wp_version_check') ? 'yes' : 'no';
die;
}
public function get_test_wordpress_version()
{
$result = array('label' => '', 'status' => '', 'badge' => array('label' => __('Performance'), 'color' => 'blue'), 'description' => '', 'actions' => '', 'test' => 'wordpress_version');
$core_current_version = get_bloginfo('version');
$core_updates = get_core_updates();
if (!is_array($core_updates)) {
$result['status'] = 'recommended';
$result['label'] = sprintf(__('WordPress version %s'), $core_current_version);
$result['description'] = sprintf('<p>%s</p>', __('We were unable to check if any new versions of WordPress are available.'));
$result['actions'] = sprintf('<a href="%s">%s</a>', esc_url(admin_url('update-core.php?force-check=1')), __('Check for updates manually'));
} else {
foreach ($core_updates as $core => $update) {
if ('upgrade' === $update->response) {
$current_version = explode('.', $core_current_version);
$new_version = explode('.', $update->version);
$current_major = $current_version[0] . '.' . $current_version[1];
$new_major = $new_version[0] . '.' . $new_version[1];
$result['label'] = sprintf(__('WordPress update available (%s)'), $update->version);
$result['actions'] = sprintf('<a href="%s">%s</a>', esc_url(admin_url('update-core.php')), __('Install the latest version of WordPress'));
if ($current_major !== $new_major) {
$result['status'] = 'recommended';
$result['description'] = sprintf('<p>%s</p>', __('A new version of WordPress is available.'));
} else {
$result['status'] = 'critical';
$result['badge']['label'] = __('Security');
$result['description'] = sprintf('<p>%s</p>', __('A new minor update is available for your site. Because minor updates often address security, it’s important to install them.'));
}
} else {
$result['status'] = 'good';
$result['label'] = sprintf(__('Your version of WordPress (%s) is up to date'), $core_current_version);
$result['description'] = sprintf('<p>%s</p>', __('You are currently running the latest version of WordPress available, keep it up!'));
}
}
}
return $result;
}
public function get_test_plugin_version()
{
$result = array('label' => __('Your plugins are all up to date'), 'status' => 'good', 'badge' => array('label' => __('Security'), 'color' => 'blue'), 'description' => sprintf('<p>%s</p>', __('Plugins extend your site’s functionality with things like contact forms, ecommerce and much more. That means they have deep access to your site, so it’s vital to keep them up to date.')), 'actions' => sprintf('<p><a href="%s">%s</a></p>', esc_url(admin_url('plugins.php')), __('Manage your plugins')), 'test' => 'plugin_version');
$plugins = get_plugins();
$plugin_updates = get_plugin_updates();
$plugins_have_updates = false;
$plugins_active = 0;
$plugins_total = 0;
$plugins_need_update = 0;
foreach ($plugins as $plugin_path => $plugin) {
$plugins_total++;
if (is_plugin_active($plugin_path)) {
$plugins_active++;
}
$plugin_version = $plugin['Version'];
if (array_key_exists($plugin_path, $plugin_updates)) {
$plugins_need_update++;
$plugins_have_updates = true;
}
}
if ($plugins_need_update > 0) {
$result['status'] = 'critical';
$result['label'] = __('You have plugins waiting to be updated');
$result['description'] .= sprintf('<p>%s</p>', sprintf(_n('Your site has %d plugin waiting to be updated.', 'Your site has %d plugins waiting to be updated.', $plugins_need_update), $plugins_need_update));
$result['actions'] .= sprintf('<p><a href="%s">%s</a></p>', esc_url(network_admin_url('plugins.php?plugin_status=upgrade')), __('Update your plugins'));
} else {
if (1 === $plugins_active) {
$result['description'] .= sprintf('<p>%s</p>', __('Your site has 1 active plugin, and it is up to date.'));
} else {
$result['description'] .= sprintf('<p>%s</p>', sprintf(_n('Your site has %d active plugin, and it is up to date.', 'Your site has %d active plugins, and they are all up to date.', $plugins_active), $plugins_active));
}
}
if ($plugins_total > $plugins_active && !is_multisite()) {
$unused_plugins = $plugins_total - $plugins_active;
$result['status'] = 'recommended';
$result['label'] = __('You should remove inactive plugins');
$result['description'] .= sprintf('<p>%s %s</p>', sprintf(_n('Your site has %d inactive plugin.', 'Your site has %d inactive plugins.', $unused_plugins), $unused_plugins), __('Inactive plugins are tempting targets for attackers. If you’re not going to use a plugin, we recommend you remove it.'));
$result['actions'] .= sprintf('<p><a href="%s">%s</a></p>', esc_url(admin_url('plugins.php?plugin_status=inactive')), __('Manage inactive plugins'));
}
return $result;
}
public function get_test_theme_version()
{
$result = array('label' => __('Your themes are all up to date'), 'status' => 'good', 'badge' => array('label' => __('Security'), 'color' => 'blue'), 'description' => sprintf('<p>%s</p>', __('Themes add your site’s look and feel. It’s important to keep them up to date, to stay consistent with your brand and keep your site secure.')), 'actions' => sprintf('<p><a href="%s">%s</a></p>', esc_url(admin_url('themes.php')), __('Manage your themes')), 'test' => 'theme_version');
$theme_updates = get_theme_updates();
$themes_total = 0;
$themes_need_updates = 0;
$themes_inactive = 0;
$allowed_theme_count = 1;
$has_default_theme = false;
$has_unused_themes = false;
$show_unused_themes = true;
$using_default_theme = false;
$all_themes = wp_get_themes();
$active_theme = wp_get_theme();
$default_theme = wp_get_theme(WP_DEFAULT_THEME);
if (!$default_theme->exists()) {
$default_theme = WP_Theme::get_core_default_theme();
}
if ($default_theme) {
$has_default_theme = true;
if ($active_theme->get_stylesheet() === $default_theme->get_stylesheet() || is_child_theme() && $active_theme->get_template() === $default_theme->get_template()) {
$using_default_theme = true;
}
}
foreach ($all_themes as $theme_slug => $theme) {
$themes_total++;
if (array_key_exists($theme_slug, $theme_updates)) {
$themes_need_updates++;
}
}
if (is_child_theme()) {
$allowed_theme_count++;
}
if ($has_default_theme && !$using_default_theme) {
$allowed_theme_count++;
}
if ($themes_total > $allowed_theme_count) {
$has_unused_themes = true;
$themes_inactive = $themes_total - $allowed_theme_count;
}
if ($themes_need_updates > 0) {
$result['status'] = 'critical';
$result['label'] = __('You have themes waiting to be updated');
$result['description'] .= sprintf('<p>%s</p>', sprintf(_n('Your site has %d theme waiting to be updated.', 'Your site has %d themes waiting to be updated.', $themes_need_updates), $themes_need_updates));
} else {
if (1 === $themes_total) {
$result['description'] .= sprintf('<p>%s</p>', __('Your site has 1 installed theme, and it is up to date.'));
} else {
$result['description'] .= sprintf('<p>%s</p>', sprintf(_n('Your site has %d installed theme, and it is up to date.', 'Your site has %d installed themes, and they are all up to date.', $themes_total), $themes_total));
}
}
if ($has_unused_themes && $show_unused_themes && !is_multisite()) {
if ($active_theme->parent()) {
$result['status'] = 'recommended';
$result['label'] = __('You should remove inactive themes');
if ($using_default_theme) {
$result['description'] .= sprintf('<p>%s %s</p>', sprintf(_n('Your site has %d inactive theme.', 'Your site has %d inactive themes.', $themes_inactive), $themes_inactive), sprintf(__('To enhance your site’s security, we recommend you remove any themes you’re not using. You should keep your current theme, %1$s, and %2$s, its parent theme.'), $active_theme->name, $active_theme->parent()->name));
} else {
$result['description'] .= sprintf('<p>%s %s</p>', sprintf(_n('Your site has %d inactive theme.', 'Your site has %d inactive themes.', $themes_inactive), $themes_inactive), sprintf(__('To enhance your site’s security, we recommend you remove any themes you’re not using. You should keep %1$s, the default WordPress theme, %2$s, your current theme, and %3$s, its parent theme.'), $default_theme ? $default_theme->name : WP_DEFAULT_THEME, $active_theme->name, $active_theme->parent()->name));
}
} else {
$result['status'] = 'recommended';
$result['label'] = __('You should remove inactive themes');
if ($using_default_theme) {
$result['description'] .= sprintf('<p>%s %s</p>', sprintf(_n('Your site has %1$d inactive theme, other than %2$s, your active theme.', 'Your site has %1$d inactive themes, other than %2$s, your active theme.', $themes_inactive), $themes_inactive, $active_theme->name), __('We recommend removing any unused themes to enhance your site’s security.'));
} else {
$result['description'] .= sprintf('<p>%s %s</p>', sprintf(_n('Your site has %1$d inactive theme, other than %2$s, the default WordPress theme, and %3$s, your active theme.', 'Your site has %1$d inactive themes, other than %2$s, the default WordPress theme, and %3$s, your active theme.', $themes_inactive), $themes_inactive, $default_theme ? $default_theme->name : WP_DEFAULT_THEME, $active_theme->name), __('We recommend removing any unused themes to enhance your site’s security.'));
}
}
}
if (!$has_default_theme) {
$result['status'] = 'recommended';
$result['label'] = __('Have a default theme available');
$result['description'] .= sprintf('<p>%s</p>', __('Your site does not have any default theme. Default themes are used by WordPress automatically if anything is wrong with your chosen theme.'));
}
return $result;
}
public function get_test_php_version()
{
$response = wp_check_php_version();
$result = array('label' => sprintf(__('Your site is running the current version of PHP (%s)'), PHP_VERSION), 'status' => 'good', 'badge' => array('label' => __('Performance'), 'color' => 'blue'), 'description' => sprintf('<p>%s</p>', sprintf(__('PHP is the programming language used to build and maintain WordPress. Newer versions of PHP are created with increased performance in mind, so you may see a positive effect on your site’s performance. The minimum recommended version of PHP is %s.'), $response ? $response['recommended_version'] : '')), 'actions' => sprintf('<p><a href="%s" target="_blank" rel="noopener">%s <span class="screen-reader-text">%s</span><span aria-hidden="true" class="dashicons dashicons-external"></span></a></p>', esc_url(wp_get_update_php_url()), __('Learn more about updating PHP'), __('(opens in a new tab)')), 'test' => 'php_version');
if (!$response || version_compare(PHP_VERSION, $response['recommended_version'], '>=')) {
return $result;
}
if ($response['is_supported']) {
$result['label'] = sprintf(__('Your site is running an older version of PHP (%s)'), PHP_VERSION);
$result['status'] = 'recommended';
return $result;
}
if ($response['is_secure']) {
$result['label'] = sprintf(__('Your site is running an older version of PHP (%s), which should be updated'), PHP_VERSION);
$result['status'] = 'recommended';
return $result;
}
$result['label'] = sprintf(__('Your site is running an outdated version of PHP (%s), which requires an update'), PHP_VERSION);
$result['status'] = 'critical';
$result['badge']['label'] = __('Security');
return $result;
}
private function test_php_extension_availability($extension = null, $function = null, $constant = null, $class = null)
{
if (!$extension && !$function && !$constant && !$class) {
return false;
}
if ($extension && !extension_loaded($extension)) {
return false;
}
if ($function && !function_exists($function)) {
return false;
}
if ($constant && !defined($constant)) {
return false;
}
if ($class && !class_exists($class)) {
return false;
}
return true;
}
public function get_test_php_extensions()
{
$result = array('label' => __('Required and recommended modules are installed'), 'status' => 'good', 'badge' => array('label' => __('Performance'), 'color' => 'blue'), 'description' => sprintf('<p>%s</p><p>%s</p>', __('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.'), sprintf(__('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>.'), esc_url(__('https://make.wordpress.org/hosting/handbook/handbook/server-environment/#php-extensions')), 'target="_blank" rel="noopener"', sprintf(' <span class="screen-reader-text">%s</span><span aria-hidden="true" class="dashicons dashicons-external"></span>', __('(opens in a new tab)')))), 'actions' => '', 'test' => 'php_extensions');
$modules = array('curl' => array('function' => 'curl_version', 'required' => false), 'dom' => array('class' => 'DOMNode', 'required' => false), 'exif' => array('function' => 'exif_read_data', 'required' => false), 'fileinfo' => array('function' => 'finfo_file', 'required' => false), 'hash' => array('function' => 'hash', 'required' => false), 'json' => array('function' => 'json_last_error', 'required' => true), 'mbstring' => array('function' => 'mb_check_encoding', 'required' => false), 'mysqli' => array('function' => 'mysqli_connect', 'required' => false), 'libsodium' => array('constant' => 'SODIUM_LIBRARY_VERSION', 'required' => false, 'php_bundled_version' => '7.2.0'), 'openssl' => array('function' => 'openssl_encrypt', 'required' => false), 'pcre' => array('function' => 'preg_match', 'required' => false), 'imagick' => array('extension' => 'imagick', 'required' => false), 'mod_xml' => array('extension' => 'libxml', 'required' => false), 'zip' => array('class' => 'ZipArchive', 'required' => false), 'filter' => array('function' => 'filter_list', 'required' => false), 'gd' => array('extension' => 'gd', 'required' => false, 'fallback_for' => 'imagick'), 'iconv' => array('function' => 'iconv', 'required' => false), 'mcrypt' => array('extension' => 'mcrypt', 'required' => false, 'fallback_for' => 'libsodium'), 'simplexml' => array('extension' => 'simplexml', 'required' => false, 'fallback_for' => 'mod_xml'), 'xmlreader' => array('extension' => 'xmlreader', 'required' => false, 'fallback_for' => 'mod_xml'), 'zlib' => array('extension' => 'zlib', 'required' => false, 'fallback_for' => 'zip'));
$modules = apply_filters('site_status_test_php_modules', $modules);
$failures = array();
foreach ($modules as $library => $module) {
$extension = isset($module['extension']) ? $module['extension'] : null;
$function = isset($module['function']) ? $module['function'] : null;
$constant = isset($module['constant']) ? $module['constant'] : null;
$class_name = isset($module['class']) ? $module['class'] : null;
if (isset($module['fallback_for'])) {
if (isset($failures[$module['fallback_for']])) {
$module['required'] = true;
} else {
continue;
}
}
if (!$this->test_php_extension_availability($extension, $function, $constant, $class_name) && (!isset($module['php_bundled_version']) || version_compare(PHP_VERSION, $module['php_bundled_version'], '<'))) {
if ($module['required']) {
$result['status'] = 'critical';
$class = 'error';
$screen_reader = __('Error');
$message = sprintf(__('The required module, %s, is not installed, or has been disabled.'), $library);
} else {
$class = 'warning';
$screen_reader = __('Warning');
$message = sprintf(__('The optional module, %s, is not installed, or has been disabled.'), $library);
}
if (!$module['required'] && 'good' === $result['status']) {
$result['status'] = 'recommended';
}
$failures[$library] = "<span class='dashicons {$class}'><span class='screen-reader-text'>{$screen_reader}</span></span> {$message}";
}
}
if (!empty($failures)) {
$output = '<ul>';
foreach ($failures as $failure) {
$output .= sprintf('<li>%s</li>', $failure);
}
$output .= '</ul>';
}
if ('good' !== $result['status']) {
if ('recommended' === $result['status']) {
$result['label'] = __('One or more recommended modules are missing');
}
if ('critical' === $result['status']) {
$result['label'] = __('One or more required modules are missing');
}
$result['description'] .= $output;
}
return $result;
}
public function get_test_php_default_timezone()
{
$result = array('label' => __('PHP default timezone is valid'), 'status' => 'good', 'badge' => array('label' => __('Performance'), 'color' => 'blue'), 'description' => sprintf('<p>%s</p>', __('PHP default timezone was configured by WordPress on loading. This is necessary for correct calculations of dates and times.')), 'actions' => '', 'test' => 'php_default_timezone');
if ('UTC' !== date_default_timezone_get()) {
$result['status'] = 'critical';
$result['label'] = __('PHP default timezone is invalid');
$result['description'] = sprintf('<p>%s</p>', sprintf(__('PHP default timezone was changed after WordPress loading by a %s function call. This interferes with correct calculations of dates and times.'), '<code>date_default_timezone_set()</code>'));
}
return $result;
}
public function get_test_php_sessions()
{
$result = array('label' => __('No PHP sessions detected'), 'status' => 'good', 'badge' => array('label' => __('Performance'), 'color' => 'blue'), 'description' => sprintf('<p>%s</p>', sprintf(__('PHP sessions created by a %1$s function call may interfere with REST API and loopback requests. An active session should be closed by %2$s before making any HTTP requests.'), '<code>session_start()</code>', '<code>session_write_close()</code>')), 'test' => 'php_sessions');
if (function_exists('session_status') && PHP_SESSION_ACTIVE === session_status()) {
$result['status'] = 'critical';
$result['label'] = __('An active PHP session was detected');
$result['description'] = sprintf('<p>%s</p>', sprintf(__('A PHP session was created by a %1$s function call. This interferes with REST API and loopback requests. The session should be closed by %2$s before making any HTTP requests.'), '<code>session_start()</code>', '<code>session_write_close()</code>'));
}
return $result;
}
public function get_test_sql_server()
{
if (!$this->mysql_server_version) {
$this->prepare_sql_data();
}
$result = array('label' => __('SQL server is up to date'), 'status' => 'good', 'badge' => array('label' => __('Performance'), 'color' => 'blue'), 'description' => sprintf('<p>%s</p>', __('The SQL server is a required piece of software for the database WordPress uses to store all your site’s content and settings.')), 'actions' => sprintf('<p><a href="%s" target="_blank" rel="noopener">%s <span class="screen-reader-text">%s</span><span aria-hidden="true" class="dashicons dashicons-external"></span></a></p>', esc_url(__('https://wordpress.org/about/requirements/')), __('Learn more about what WordPress requires to run.'), __('(opens in a new tab)')), 'test' => 'sql_server');
$db_dropin = file_exists(WP_CONTENT_DIR . '/db.php');
if (!$this->mysql_rec_version_check) {
$result['status'] = 'recommended';
$result['label'] = __('Outdated SQL server');
$result['description'] .= sprintf('<p>%s</p>', sprintf(__('For optimal performance and security reasons, we recommend running %1$s version %2$s or higher. Contact your web hosting company to correct this.'), $this->is_mariadb ? 'MariaDB' : 'MySQL', $this->health_check_mysql_rec_version));
}
if (!$this->mysql_min_version_check) {
$result['status'] = 'critical';
$result['label'] = __('Severely outdated SQL server');
$result['badge']['label'] = __('Security');
$result['description'] .= sprintf('<p>%s</p>', sprintf(__('WordPress requires %1$s version %2$s or higher. Contact your web hosting company to correct this.'), $this->is_mariadb ? 'MariaDB' : 'MySQL', $this->health_check_mysql_required_version));
}
if ($db_dropin) {
$result['description'] .= sprintf('<p>%s</p>', wp_kses(sprintf(__('You are using a %1$s drop-in which might mean that a %2$s database is not being used.'), '<code>wp-content/db.php</code>', $this->is_mariadb ? 'MariaDB' : 'MySQL'), array('code' => true)));
}
return $result;
}
public function get_test_utf8mb4_support()
{
global $wpdb;
if (!$this->mysql_server_version) {
$this->prepare_sql_data();
}
$result = array('label' => __('UTF8MB4 is supported'), 'status' => 'good', 'badge' => array('label' => __('Performance'), 'color' => 'blue'), 'description' => sprintf('<p>%s</p>', __('UTF8MB4 is the character set WordPress prefers for database storage because it safely supports the widest set of characters and encodings, including Emoji, enabling better support for non-English languages.')), 'actions' => '', 'test' => 'utf8mb4_support');
if (!$this->is_mariadb) {
if (version_compare($this->mysql_server_version, '5.5.3', '<')) {
$result['status'] = 'recommended';
$result['label'] = __('utf8mb4 requires a MySQL update');
$result['description'] .= sprintf('<p>%s</p>', sprintf(__('WordPress’ utf8mb4 support requires MySQL version %s or greater. Please contact your server administrator.'), '5.5.3'));
} else {
$result['description'] .= sprintf('<p>%s</p>', __('Your MySQL version supports utf8mb4.'));
}
} else {
if (version_compare($this->mysql_server_version, '5.5.0', '<')) {
$result['status'] = 'recommended';
$result['label'] = __('utf8mb4 requires a MariaDB update');
$result['description'] .= sprintf('<p>%s</p>', sprintf(__('WordPress’ utf8mb4 support requires MariaDB version %s or greater. Please contact your server administrator.'), '5.5.0'));
} else {
$result['description'] .= sprintf('<p>%s</p>', __('Your MariaDB version supports utf8mb4.'));
}
}
if ($wpdb->use_mysqli) {
$mysql_client_version = mysqli_get_client_info();
} else {
$mysql_client_version = mysql_get_client_info();
}
if (false !== strpos($mysql_client_version, 'mysqlnd')) {
$mysql_client_version = preg_replace('/^\\D+([\\d.]+).*/', '$1', $mysql_client_version);
if (version_compare($mysql_client_version, '5.0.9', '<')) {
$result['status'] = 'recommended';
$result['label'] = __('utf8mb4 requires a newer client library');
$result['description'] .= sprintf('<p>%s</p>', sprintf(__('WordPress’ utf8mb4 support requires MySQL client library (%1$s) version %2$s or newer. Please contact your server administrator.'), 'mysqlnd', '5.0.9'));
}
} else {
if (version_compare($mysql_client_version, '5.5.3', '<')) {
$result['status'] = 'recommended';
$result['label'] = __('utf8mb4 requires a newer client library');
$result['description'] .= sprintf('<p>%s</p>', sprintf(__('WordPress’ utf8mb4 support requires MySQL client library (%1$s) version %2$s or newer. Please contact your server administrator.'), 'libmysql', '5.5.3'));
}
}
return $result;
}
public function get_test_dotorg_communication()
{
$result = array('label' => __('Can communicate with WordPress.org'), 'status' => '', 'badge' => array('label' => __('Security'), 'color' => 'blue'), 'description' => sprintf('<p>%s</p>', __('Communicating with the WordPress servers is used to check for new versions, and to both install and update WordPress core, themes or plugins.')), 'actions' => '', 'test' => 'dotorg_communication');
$wp_dotorg = wp_remote_get('https://api.wordpress.org', array('timeout' => 10));
if (!is_wp_error($wp_dotorg)) {
$result['status'] = 'good';
} else {
$result['status'] = 'critical';
$result['label'] = __('Could not reach WordPress.org');
$result['description'] .= sprintf('<p>%s</p>', sprintf('<span class="error"><span class="screen-reader-text">%s</span></span> %s', __('Error'), sprintf(__('Your site is unable to reach WordPress.org at %1$s, and returned the error: %2$s'), gethostbyname('api.wordpress.org'), $wp_dotorg->get_error_message())));
$result['actions'] = sprintf('<p><a href="%s" target="_blank" rel="noopener">%s <span class="screen-reader-text">%s</span><span aria-hidden="true" class="dashicons dashicons-external"></span></a></p>', esc_url(__('https://wordpress.org/support')), __('Get help resolving this issue.'), __('(opens in a new tab)'));
}
return $result;
}
public function get_test_is_in_debug_mode()
{
$result = array('label' => __('Your site is not set to output debug information'), 'status' => 'good', 'badge' => array('label' => __('Security'), 'color' => 'blue'), 'description' => sprintf('<p>%s</p>', __('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.')), 'actions' => sprintf('<p><a href="%s" target="_blank" rel="noopener">%s <span class="screen-reader-text">%s</span><span aria-hidden="true" class="dashicons dashicons-external"></span></a></p>', esc_url(__('https://wordpress.org/support/article/debugging-in-wordpress/')), __('Learn more about debugging in WordPress.'), __('(opens in a new tab)')), 'test' => 'is_in_debug_mode');
if (defined('WP_DEBUG') && WP_DEBUG) {
if (defined('WP_DEBUG_LOG') && WP_DEBUG_LOG) {
$result['label'] = __('Your site is set to log errors to a potentially public file.');
$result['status'] = 0 === strpos(ini_get('error_log'), ABSPATH) ? 'critical' : 'recommended';
$result['description'] .= sprintf('<p>%s</p>', sprintf(__('The value, %s, has been added to this website’s configuration file. This means any errors on the site will be written to a file which is potentially available to all users.'), '<code>WP_DEBUG_LOG</code>'));
}
if (defined('WP_DEBUG_DISPLAY') && WP_DEBUG_DISPLAY) {
$result['label'] = __('Your site is set to display errors to site visitors');
$result['status'] = 'critical';
if ($this->is_development_environment()) {
$result['status'] = 'recommended';
}
$result['description'] .= sprintf('<p>%s</p>', sprintf(__('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.'), '<code>WP_DEBUG_DISPLAY</code>', '<code>WP_DEBUG</code>'));
}
}
return $result;
}
public function get_test_https_status()
{
wp_update_https_detection_errors();
$default_update_url = wp_get_default_update_https_url();
$result = array('label' => __('Your website is using an active HTTPS connection'), 'status' => 'good', 'badge' => array('label' => __('Security'), 'color' => 'blue'), 'description' => sprintf('<p>%s</p>', __('An HTTPS connection is a more secure way of browsing the web. Many services now have HTTPS as a requirement. HTTPS allows you to take advantage of new features that can increase site speed, improve search rankings, and gain the trust of your visitors by helping to protect their online privacy.')), 'actions' => sprintf('<p><a href="%s" target="_blank" rel="noopener">%s<span class="screen-reader-text"> %s</span><span aria-hidden="true" class="dashicons dashicons-external"></span></a></p>', esc_url($default_update_url), __('Learn more about why you should use HTTPS'), __('(opens in a new tab)')), 'test' => 'https_status');
if (!wp_is_using_https()) {
$result['status'] = 'critical';
$result['label'] = __('Your website does not use HTTPS');
if (wp_is_site_url_using_https()) {
if (is_ssl()) {
$result['description'] = sprintf('<p>%s</p>', sprintf(__('You are accessing this website using HTTPS, but your <a href="%s">Site Address</a> is not set up to use HTTPS by default.'), esc_url(admin_url('options-general.php') . '#home')));
} else {
$result['description'] = sprintf('<p>%s</p>', sprintf(__('Your <a href="%s">Site Address</a> is not set up to use HTTPS.'), esc_url(admin_url('options-general.php') . '#home')));
}
} else {
if (is_ssl()) {
$result['description'] = sprintf('<p>%s</p>', sprintf(__('You are accessing this website using HTTPS, but your <a href="%1$s">WordPress Address</a> and <a href="%2$s">Site Address</a> are not set up to use HTTPS by default.'), esc_url(admin_url('options-general.php') . '#siteurl'), esc_url(admin_url('options-general.php') . '#home')));
} else {
$result['description'] = sprintf('<p>%s</p>', sprintf(__('Your <a href="%1$s">WordPress Address</a> and <a href="%2$s">Site Address</a> are not set up to use HTTPS.'), esc_url(admin_url('options-general.php') . '#siteurl'), esc_url(admin_url('options-general.php') . '#home')));
}
}
if (wp_is_https_supported()) {
$result['description'] .= sprintf('<p>%s</p>', __('HTTPS is already supported for your website.'));
if (defined('WP_HOME') || defined('WP_SITEURL')) {
$result['description'] .= sprintf('<p>%s</p>', sprintf(__('However, your WordPress Address is currently controlled by a PHP constant and therefore cannot be updated. You need to edit your %1$s and remove or update the definitions of %2$s and %3$s.'), '<code>wp-config.php</code>', '<code>WP_HOME</code>', '<code>WP_SITEURL</code>'));
} elseif (current_user_can('update_https')) {
$default_direct_update_url = add_query_arg('action', 'update_https', wp_nonce_url(admin_url('site-health.php'), 'wp_update_https'));
$direct_update_url = wp_get_direct_update_https_url();
if (!empty($direct_update_url)) {
$result['actions'] = sprintf('<p class="button-container"><a class="button button-primary" href="%1$s" target="_blank" rel="noopener">%2$s<span class="screen-reader-text"> %3$s</span><span aria-hidden="true" class="dashicons dashicons-external"></span></a></p>', esc_url($direct_update_url), __('Update your site to use HTTPS'), __('(opens in a new tab)'));
} else {
$result['actions'] = sprintf('<p class="button-container"><a class="button button-primary" href="%1$s">%2$s</a></p>', esc_url($default_direct_update_url), __('Update your site to use HTTPS'));
}
}
} else {
$update_url = wp_get_update_https_url();
if ($update_url !== $default_update_url) {
$result['description'] .= sprintf('<p><a href="%s" target="_blank" rel="noopener">%s<span class="screen-reader-text"> %s</span><span aria-hidden="true" class="dashicons dashicons-external"></span></a></p>', esc_url($update_url), __('Talk to your web host about supporting HTTPS for your website.'), __('(opens in a new tab)'));
} else {
$result['description'] .= sprintf('<p>%s</p>', __('Talk to your web host about supporting HTTPS for your website.'));
}
}
} elseif (!wp_is_https_supported()) {
$result['status'] = 'critical';
$result['label'] = __('There are problems with the HTTPS connection of your website');
$https_detection_errors = get_option('https_detection_errors');
if (!empty($https_detection_errors['ssl_verification_failed'])) {
$result['description'] = sprintf('<p>%s</p>', sprintf(__('Your <a href="%s">WordPress Address</a> is set up to use HTTPS, but the SSL certificate appears to be invalid.'), esc_url(admin_url('options-general.php') . '#siteurl')));
} else {
$result['description'] = sprintf('<p>%s</p>', sprintf(__('Your <a href="%s">WordPress Address</a> is set up to use HTTPS, but your website appears to be unavailable when using an HTTPS connection.'), esc_url(admin_url('options-general.php') . '#siteurl')));
}
$result['description'] .= sprintf('<p>%s</p>', __('Talk to your web host about resolving this HTTPS issue for your website.'));
}
return $result;
}
public function get_test_ssl_support()
{
$result = array('label' => '', 'status' => '', 'badge' => array('label' => __('Security'), 'color' => 'blue'), 'description' => sprintf('<p>%s</p>', __('Securely communicating between servers are needed for transactions such as fetching files, conducting sales on store sites, and much more.')), 'actions' => '', 'test' => 'ssl_support');
$supports_https = wp_http_supports(array('ssl'));
if ($supports_https) {
$result['status'] = 'good';
$result['label'] = __('Your site can communicate securely with other services');
} else {
$result['status'] = 'critical';
$result['label'] = __('Your site is unable to communicate securely with other services');
$result['description'] .= sprintf('<p>%s</p>', __('Talk to your web host about OpenSSL support for PHP.'));
}
return $result;
}
public function get_test_scheduled_events()
{
$result = array('label' => __('Scheduled events are running'), 'status' => 'good', 'badge' => array('label' => __('Performance'), 'color' => 'blue'), 'description' => sprintf('<p>%s</p>', __('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.')), 'actions' => '', 'test' => 'scheduled_events');
$this->wp_schedule_test_init();
if (is_wp_error($this->has_missed_cron())) {
$result['status'] = 'critical';
$result['label'] = __('It was not possible to check your scheduled events');
$result['description'] = sprintf('<p>%s</p>', sprintf(__('While trying to test your site’s scheduled events, the following error was returned: %s'), $this->has_missed_cron()->get_error_message()));
} elseif ($this->has_missed_cron()) {
$result['status'] = 'recommended';
$result['label'] = __('A scheduled event has failed');
$result['description'] = sprintf('<p>%s</p>', sprintf(__('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.'), $this->last_missed_cron));
} elseif ($this->has_late_cron()) {
$result['status'] = 'recommended';
$result['label'] = __('A scheduled event is late');
$result['description'] = sprintf('<p>%s</p>', sprintf(__('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.'), $this->last_late_cron));
}
return $result;
}
public function get_test_background_updates()
{
$result = array('label' => __('Background updates are working'), 'status' => 'good', 'badge' => array('label' => __('Security'), 'color' => 'blue'), 'description' => sprintf('<p>%s</p>', __('Background updates ensure that WordPress can auto-update if a security update is released for the version you are currently using.')), 'actions' => '', 'test' => 'background_updates');
if (!class_exists('WP_Site_Health_Auto_Updates')) {
require_once ABSPATH . 'wp-admin/includes/class-wp-site-health-auto-updates.php';
}
$automatic_updates = new WP_Site_Health_Auto_Updates();
$tests = $automatic_updates->run_tests();
$output = '<ul>';
foreach ($tests as $test) {
$severity_string = __('Passed');
if ('fail' === $test->severity) {
$result['label'] = __('Background updates are not working as expected');
$result['status'] = 'critical';
$severity_string = __('Error');
}
if ('warning' === $test->severity && 'good' === $result['status']) {
$result['label'] = __('Background updates may not be working properly');
$result['status'] = 'recommended';
$severity_string = __('Warning');
}
$output .= sprintf('<li><span class="dashicons %s"><span class="screen-reader-text">%s</span></span> %s</li>', esc_attr($test->severity), $severity_string, $test->description);
}
$output .= '</ul>';
if ('good' !== $result['status']) {
$result['description'] .= $output;
}
return $result;
}
public function get_test_plugin_theme_auto_updates()
{
$result = array('label' => __('Plugin and theme auto-updates appear to be configured correctly'), 'status' => 'good', 'badge' => array('label' => __('Security'), 'color' => 'blue'), 'description' => sprintf('<p>%s</p>', __('Plugin and theme auto-updates ensure that the latest versions are always installed.')), 'actions' => '', 'test' => 'plugin_theme_auto_updates');
$check_plugin_theme_updates = $this->detect_plugin_theme_auto_update_issues();
$result['status'] = $check_plugin_theme_updates->status;
if ('good' !== $result['status']) {
$result['label'] = __('Your site may have problems auto-updating plugins and themes');
$result['description'] .= sprintf('<p>%s</p>', $check_plugin_theme_updates->message);
}
return $result;
}
public function get_test_loopback_requests()
{
$result = array('label' => __('Your site can perform loopback requests'), 'status' => 'good', 'badge' => array('label' => __('Performance'), 'color' => 'blue'), 'description' => sprintf('<p>%s</p>', __('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.')), 'actions' => '', 'test' => 'loopback_requests');
$check_loopback = $this->can_perform_loopback();
$result['status'] = $check_loopback->status;
if ('good' !== $result['status']) {
$result['label'] = __('Your site could not complete a loopback request');
$result['description'] .= sprintf('<p>%s</p>', $check_loopback->message);
}
return $result;
}
public function get_test_http_requests()
{
$result = array('label' => __('HTTP requests seem to be working as expected'), 'status' => 'good', 'badge' => array('label' => __('Performance'), 'color' => 'blue'), 'description' => sprintf('<p>%s</p>', __('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.')), 'actions' => '', 'test' => 'http_requests');
$blocked = false;
$hosts = array();
if (defined('WP_HTTP_BLOCK_EXTERNAL') && WP_HTTP_BLOCK_EXTERNAL) {
$blocked = true;
}
if (defined('WP_ACCESSIBLE_HOSTS')) {
$hosts = explode(',', WP_ACCESSIBLE_HOSTS);
}
if ($blocked && 0 === count($hosts)) {
$result['status'] = 'critical';
$result['label'] = __('HTTP requests are blocked');
$result['description'] .= sprintf('<p>%s</p>', sprintf(__('HTTP requests have been blocked by the %s constant, with no allowed hosts.'), '<code>WP_HTTP_BLOCK_EXTERNAL</code>'));
}
if ($blocked && 0 < count($hosts)) {
$result['status'] = 'recommended';
$result['label'] = __('HTTP requests are partially blocked');
$result['description'] .= sprintf('<p>%s</p>', sprintf(__('HTTP requests have been blocked by the %1$s constant, with some allowed hosts: %2$s.'), '<code>WP_HTTP_BLOCK_EXTERNAL</code>', implode(',', $hosts)));
}
return $result;
}
public function get_test_rest_availability()
{
$result = array('label' => __('The REST API is available'), 'status' => 'good', 'badge' => array('label' => __('Performance'), 'color' => 'blue'), 'description' => sprintf('<p>%s</p>', __('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.')), 'actions' => '', 'test' => 'rest_availability');
$cookies = wp_unslash($_COOKIE);
$timeout = 10;
$headers = array('Cache-Control' => 'no-cache', 'X-WP-Nonce' => wp_create_nonce('wp_rest'));
$sslverify = apply_filters('https_local_ssl_verify', false);
if (isset($_SERVER['PHP_AUTH_USER']) && isset($_SERVER['PHP_AUTH_PW'])) {
$headers['Authorization'] = 'Basic ' . base64_encode(wp_unslash($_SERVER['PHP_AUTH_USER']) . ':' . wp_unslash($_SERVER['PHP_AUTH_PW']));
}
$url = rest_url('wp/v2/types/post');
$url = add_query_arg(array('context' => 'edit'), $url);
$r = wp_remote_get($url, compact('cookies', 'headers', 'timeout', 'sslverify'));
if (is_wp_error($r)) {
$result['status'] = 'critical';
$result['label'] = __('The REST API encountered an error');
$result['description'] .= sprintf('<p>%s</p>', sprintf('%s<br>%s', __('The REST API request failed due to an error.'), sprintf(__('Error: %1$s (%2$s)'), $r->get_error_message(), $r->get_error_code())));
} elseif (200 !== wp_remote_retrieve_response_code($r)) {
$result['status'] = 'recommended';
$result['label'] = __('The REST API encountered an unexpected result');
$result['description'] .= sprintf('<p>%s</p>', sprintf(__('The REST API call gave the following unexpected result: (%1$d) %2$s.'), wp_remote_retrieve_response_code($r), esc_html(wp_remote_retrieve_body($r))));
} else {
$json = json_decode(wp_remote_retrieve_body($r), true);
if (false !== $json && !isset($json['capabilities'])) {
$result['status'] = 'recommended';
$result['label'] = __('The REST API did not behave correctly');
$result['description'] .= sprintf('<p>%s</p>', sprintf(__('The REST API did not process the %s query parameter correctly.'), '<code>context</code>'));
}
}
return $result;
}
public function get_test_file_uploads()
{
$result = array('label' => __('Files can be uploaded.'), 'status' => 'good', 'badge' => array('label' => __('Performance'), 'color' => 'blue'), 'description' => sprintf('<p>%s</p>', sprintf(__('The %1$s directive in %2$s determines if uploading files is allowed on your site.'), '<code>file_uploads</code>', '<code>php.ini</code>')), 'actions' => '', 'test' => 'file_uploads');
if (!function_exists('ini_get')) {
$result['status'] = 'critical';
$result['description'] .= sprintf(__('The %s function has been disabled, some media settings are unavailable because of this.'), '<code>ini_get()</code>');
return $result;
}
if (empty(ini_get('file_uploads'))) {
$result['status'] = 'critical';
$result['description'] .= sprintf('<p>%s</p>', sprintf(__('%1$s is set to %2$s. You won\'t be able to upload files on your site.'), '<code>file_uploads</code>', '<code>0</code>'));
return $result;
}
$post_max_size = ini_get('post_max_size');
$upload_max_filesize = ini_get('upload_max_filesize');
if (wp_convert_hr_to_bytes($post_max_size) < wp_convert_hr_to_bytes($upload_max_filesize)) {
$result['label'] = sprintf(__('The "%1$s" value is smaller than "%2$s".'), 'post_max_size', 'upload_max_filesize');
$result['status'] = 'recommended';
if (0 === wp_convert_hr_to_bytes($post_max_size)) {
$result['description'] = sprintf('<p>%s</p>', sprintf(__('The setting for %1$s is currently configured as 0, this could cause some problems when trying to upload files through plugin or theme features that rely on various upload methods. It is recommended to configure this setting to a fixed value, ideally matching the value of %2$s, as some upload methods read the value 0 as either unlimited, or disabled.'), '<code>post_max_size</code>', '<code>upload_max_filesize</code>'));
} else {
$result['description'] = sprintf('<p>%s</p>', sprintf(__('The setting for %1$s is smaller than %2$s, this could cause some problems when trying to upload files.'), '<code>post_max_size</code>', '<code>upload_max_filesize</code>'));
}
return $result;
}
return $result;
}
public function get_test_authorization_header()
{
$result = array('label' => __('The Authorization header is working as expected.'), 'status' => 'good', 'badge' => array('label' => __('Security'), 'color' => 'blue'), 'description' => sprintf('<p>%s</p>', __('The Authorization header comes from the third-party applications you approve. Without it, those apps cannot connect to your site.')), 'actions' => '', 'test' => 'authorization_header');
if (!isset($_SERVER['PHP_AUTH_USER'], $_SERVER['PHP_AUTH_PW'])) {
$result['label'] = __('The authorization header is missing.');
} elseif ('user' !== $_SERVER['PHP_AUTH_USER'] || 'pwd' !== $_SERVER['PHP_AUTH_PW']) {
$result['label'] = __('The authorization header is invalid.');
} else {
return $result;
}
$result['status'] = 'recommended';
if (!function_exists('got_mod_rewrite')) {
require_once ABSPATH . 'wp-admin/includes/misc.php';
}
if (got_mod_rewrite()) {
$result['actions'] .= sprintf('<p><a href="%s">%s</a></p>', esc_url(admin_url('options-permalink.php')), __('Flush permalinks'));
} else {
$result['actions'] .= sprintf('<p><a href="%s" target="_blank" rel="noopener">%s <span class="screen-reader-text">%s</span><span aria-hidden="true" class="dashicons dashicons-external"></span></a></p>', __('https://developer.wordpress.org/rest-api/frequently-asked-questions/#why-is-authentication-not-working'), __('Learn how to configure the Authorization header.'), __('(opens in a new tab)'));
}
return $result;
}
public static function get_tests()
{
$tests = array('direct' => array('wordpress_version' => array('label' => __('WordPress Version'), 'test' => 'wordpress_version'), 'plugin_version' => array('label' => __('Plugin Versions'), 'test' => 'plugin_version'), 'theme_version' => array('label' => __('Theme Versions'), 'test' => 'theme_version'), 'php_version' => array('label' => __('PHP Version'), 'test' => 'php_version'), 'php_extensions' => array('label' => __('PHP Extensions'), 'test' => 'php_extensions'), 'php_default_timezone' => array('label' => __('PHP Default Timezone'), 'test' => 'php_default_timezone'), 'php_sessions' => array('label' => __('PHP Sessions'), 'test' => 'php_sessions'), 'sql_server' => array('label' => __('Database Server version'), 'test' => 'sql_server'), 'utf8mb4_support' => array('label' => __('MySQL utf8mb4 support'), 'test' => 'utf8mb4_support'), 'ssl_support' => array('label' => __('Secure communication'), 'test' => 'ssl_support'), 'scheduled_events' => array('label' => __('Scheduled events'), 'test' => 'scheduled_events'), 'http_requests' => array('label' => __('HTTP Requests'), 'test' => 'http_requests'), 'debug_enabled' => array('label' => __('Debugging enabled'), 'test' => 'is_in_debug_mode'), 'file_uploads' => array('label' => __('File uploads'), 'test' => 'file_uploads'), 'plugin_theme_auto_updates' => array('label' => __('Plugin and theme auto-updates'), 'test' => 'plugin_theme_auto_updates')), 'async' => array('dotorg_communication' => array('label' => __('Communication with WordPress.org'), 'test' => rest_url('wp-site-health/v1/tests/dotorg-communication'), 'has_rest' => true, 'async_direct_test' => array(WP_Site_Health::get_instance(), 'get_test_dotorg_communication')), 'background_updates' => array('label' => __('Background updates'), 'test' => rest_url('wp-site-health/v1/tests/background-updates'), 'has_rest' => true, 'async_direct_test' => array(WP_Site_Health::get_instance(), 'get_test_background_updates')), 'loopback_requests' => array('label' => __('Loopback request'), 'test' => rest_url('wp-site-health/v1/tests/loopback-requests'), 'has_rest' => true, 'async_direct_test' => array(WP_Site_Health::get_instance(), 'get_test_loopback_requests')), 'https_status' => array('label' => __('HTTPS status'), 'test' => rest_url('wp-site-health/v1/tests/https-status'), 'has_rest' => true, 'async_direct_test' => array(WP_Site_Health::get_instance(), 'get_test_https_status')), 'authorization_header' => array('label' => __('Authorization header'), 'test' => rest_url('wp-site-health/v1/tests/authorization-header'), 'has_rest' => true, 'headers' => array('Authorization' => 'Basic ' . base64_encode('user:pwd')), 'skip_cron' => true)));
if (function_exists('rest_url')) {
$tests['direct']['rest_availability'] = array('label' => __('REST API availability'), 'test' => 'rest_availability');
}
$tests = apply_filters('site_status_tests', $tests);
$tests = array_merge(array('direct' => array(), 'async' => array()), $tests);
return $tests;
}
public function admin_body_class($body_class)
{
$screen = get_current_screen();
if ('site-health' !== $screen->id) {
return $body_class;
}
$body_class .= ' site-health';
return $body_class;
}
private function wp_schedule_test_init()
{
$this->schedules = wp_get_schedules();
$this->get_cron_tasks();
}
private function get_cron_tasks()
{
$cron_tasks = _get_cron_array();
if (empty($cron_tasks)) {
$this->crons = new WP_Error('no_tasks', __('No scheduled events exist on this site.'));
return;
}
$this->crons = array();
foreach ($cron_tasks as $time => $cron) {
foreach ($cron as $hook => $dings) {
foreach ($dings as $sig => $data) {
$this->crons["{$hook}-{$sig}-{$time}"] = (object) array('hook' => $hook, 'time' => $time, 'sig' => $sig, 'args' => $data['args'], 'schedule' => $data['schedule'], 'interval' => isset($data['interval']) ? $data['interval'] : null);
}
}
}
}
public function has_missed_cron()
{
if (is_wp_error($this->crons)) {
return $this->crons;
}
foreach ($this->crons as $id => $cron) {
if ($cron->time - time() < $this->timeout_missed_cron) {
$this->last_missed_cron = $cron->hook;
return true;
}
}
return false;
}
public function has_late_cron()
{
if (is_wp_error($this->crons)) {
return $this->crons;
}
foreach ($this->crons as $id => $cron) {
$cron_offset = $cron->time - time();
if ($cron_offset >= $this->timeout_missed_cron && $cron_offset < $this->timeout_late_cron) {
$this->last_late_cron = $cron->hook;
return true;
}
}
return false;
}
function detect_plugin_theme_auto_update_issues()
{
$mock_plugin = (object) array('id' => 'w.org/plugins/a-fake-plugin', 'slug' => 'a-fake-plugin', 'plugin' => 'a-fake-plugin/a-fake-plugin.php', 'new_version' => '9.9', 'url' => 'https://wordpress.org/plugins/a-fake-plugin/', 'package' => 'https://downloads.wordpress.org/plugin/a-fake-plugin.9.9.zip', 'icons' => array('2x' => 'https://ps.w.org/a-fake-plugin/assets/icon-256x256.png', '1x' => 'https://ps.w.org/a-fake-plugin/assets/icon-128x128.png'), 'banners' => array('2x' => 'https://ps.w.org/a-fake-plugin/assets/banner-1544x500.png', '1x' => 'https://ps.w.org/a-fake-plugin/assets/banner-772x250.png'), 'banners_rtl' => array(), 'tested' => '5.5.0', 'requires_php' => '5.6.20', 'compatibility' => new stdClass());
$mock_theme = (object) array('theme' => 'a-fake-theme', 'new_version' => '9.9', 'url' => 'https://wordpress.org/themes/a-fake-theme/', 'package' => 'https://downloads.wordpress.org/theme/a-fake-theme.9.9.zip', 'requires' => '5.0.0', 'requires_php' => '5.6.20');
$test_plugins_enabled = wp_is_auto_update_forced_for_item('plugin', true, $mock_plugin);
$test_themes_enabled = wp_is_auto_update_forced_for_item('theme', true, $mock_theme);
$ui_enabled_for_plugins = wp_is_auto_update_enabled_for_type('plugin');
$ui_enabled_for_themes = wp_is_auto_update_enabled_for_type('theme');
$plugin_filter_present = has_filter('auto_update_plugin');
$theme_filter_present = has_filter('auto_update_theme');
if (!$test_plugins_enabled && $ui_enabled_for_plugins || !$test_themes_enabled && $ui_enabled_for_themes) {
return (object) array('status' => 'critical', 'message' => __('Auto-updates for plugins and/or themes appear to be disabled, but settings are still set to be displayed. This could cause auto-updates to not work as expected.'));
}
if (!$test_plugins_enabled && $plugin_filter_present && (!$test_themes_enabled && $theme_filter_present)) {
return (object) array('status' => 'recommended', 'message' => __('Auto-updates for plugins and themes appear to be disabled. This will prevent your site from receiving new versions automatically when available.'));
} elseif (!$test_plugins_enabled && $plugin_filter_present) {
return (object) array('status' => 'recommended', 'message' => __('Auto-updates for plugins appear to be disabled. This will prevent your site from receiving new versions automatically when available.'));
} elseif (!$test_themes_enabled && $theme_filter_present) {
return (object) array('status' => 'recommended', 'message' => __('Auto-updates for themes appear to be disabled. This will prevent your site from receiving new versions automatically when available.'));
}
return (object) array('status' => 'good', 'message' => __('There appear to be no issues with plugin and theme auto-updates.'));
}
function can_perform_loopback()
{
$body = array('site-health' => 'loopback-test');
$cookies = wp_unslash($_COOKIE);
$timeout = 10;
$headers = array('Cache-Control' => 'no-cache');
$sslverify = apply_filters('https_local_ssl_verify', false);
if (isset($_SERVER['PHP_AUTH_USER']) && isset($_SERVER['PHP_AUTH_PW'])) {
$headers['Authorization'] = 'Basic ' . base64_encode(wp_unslash($_SERVER['PHP_AUTH_USER']) . ':' . wp_unslash($_SERVER['PHP_AUTH_PW']));
}
$url = site_url('wp-cron.php');
$r = wp_remote_post($url, compact('body', 'cookies', 'headers', 'timeout', 'sslverify'));
if (is_wp_error($r)) {
return (object) array('status' => 'critical', 'message' => sprintf('%s<br>%s', __('The loopback request to your site failed, this means features relying on them are not currently working as expected.'), sprintf(__('Error: %1$s (%2$s)'), $r->get_error_message(), $r->get_error_code())));
}
if (200 !== wp_remote_retrieve_response_code($r)) {
return (object) array('status' => 'recommended', 'message' => sprintf(__('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.'), wp_remote_retrieve_response_code($r)));
}
return (object) array('status' => 'good', 'message' => __('The loopback request to your site completed successfully.'));
}
public function maybe_create_scheduled_event()
{
if (!wp_next_scheduled('wp_site_health_scheduled_check') && !wp_installing()) {
wp_schedule_event(time() + DAY_IN_SECONDS, 'weekly', 'wp_site_health_scheduled_check');
}
}
public function wp_cron_scheduled_check()
{
require_once trailingslashit(ABSPATH) . 'wp-admin/includes/admin.php';
$tests = WP_Site_Health::get_tests();
$results = array();
$site_status = array('good' => 0, 'recommended' => 0, 'critical' => 0);
if ($this->is_development_environment()) {
unset($tests['async']['https_status']);
}
foreach ($tests['direct'] as $test) {
if (is_string($test['test'])) {
$test_function = sprintf('get_test_%s', $test['test']);
if (method_exists($this, $test_function) && is_callable(array($this, $test_function))) {
$results[] = $this->perform_test(array($this, $test_function));
continue;
}
}
if (is_callable($test['test'])) {
$results[] = $this->perform_test($test['test']);
}
}
foreach ($tests['async'] as $test) {
if (!empty($test['skip_cron'])) {
continue;
}
if (!empty($test['async_direct_test']) && is_callable($test['async_direct_test'])) {
$results[] = $this->perform_test($test['async_direct_test']);
continue;
}
if (is_string($test['test'])) {
if (isset($test['has_rest']) && $test['has_rest']) {
$result_fetch = wp_remote_get($test['test'], array('body' => array('_wpnonce' => wp_create_nonce('wp_rest'))));
} else {
$result_fetch = wp_remote_post(admin_url('admin-ajax.php'), array('body' => array('action' => $test['test'], '_wpnonce' => wp_create_nonce('health-check-site-status'))));
}
if (!is_wp_error($result_fetch) && 200 === wp_remote_retrieve_response_code($result_fetch)) {
$result = json_decode(wp_remote_retrieve_body($result_fetch), true);
} else {
$result = false;
}
if (is_array($result)) {
$results[] = $result;
} else {
$results[] = array('status' => 'recommended', 'label' => __('A test is unavailable'));
}
}
}
foreach ($results as $result) {
if ('critical' === $result['status']) {
$site_status['critical']++;
} elseif ('recommended' === $result['status']) {
$site_status['recommended']++;
} else {
$site_status['good']++;
}
}
set_transient('health-check-site-status-result', wp_json_encode($site_status));
}
public function is_development_environment()
{
return in_array(wp_get_environment_type(), array('development', 'local'), true);
}
}