diff --git a/wp-admin/includes/class-wp-site-health.php b/wp-admin/includes/class-wp-site-health.php index 2e556f40a8..19491d2eed 100644 --- a/wp-admin/includes/class-wp-site-health.php +++ b/wp-admin/includes/class-wp-site-health.php @@ -135,6 +135,7 @@ class WP_Site_Health { 'test' => $test['test'], 'has_rest' => ( isset( $test['has_rest'] ) ? $test['has_rest'] : false ), 'completed' => false, + 'headers' => isset( $test['headers'] ) ? $test['headers'] : array(), ); } } @@ -2078,6 +2079,62 @@ class WP_Site_Health { return $result; } + /** + * Tests if the Authorization header has the expected values. + * + * @since 5.6.0 + * + * @return array + */ + 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( + '

%s

', + __( '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( + '

%s

', + esc_url( admin_url( 'options-permalink.php' ) ), + __( 'Flush permalinks' ) + ); + } else { + $result['actions'] .= sprintf( + '

%s %s

', + 'https://developer.wordpress.org/rest-api/frequently-asked-questions/#why-is-authentication-not-working', + __( 'Learn how to configure the Authorization header.' ), + /* translators: Accessibility text. */ + __( '(opens in a new tab)' ) + ); + } + + return $result; + } + /** * Return a set of tests that belong to the site status page. * @@ -2177,6 +2234,13 @@ class WP_Site_Health { 'has_rest' => true, 'async_direct_test' => array( WP_Site_Health::get_instance(), 'get_test_loopback_requests' ), ), + '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, + ), ), ); @@ -2203,6 +2267,7 @@ class WP_Site_Health { * * @since 5.2.0 * @since 5.6.0 Added the `async_direct_test` array key. + * Added the `skip_cron` array key. * * @param array $test_type { * An associative array, where the `$test_type` is either `direct` or @@ -2217,6 +2282,7 @@ class WP_Site_Health { * @type mixed $test A callable to perform a direct test, or a string AJAX action * to be called to perform an async test. * @type boolean $has_rest Optional. Denote if `$test` has a REST API endpoint. + * @type boolean $skip_cron Whether to skip this test when running as cron. * @type callable $async_direct_test A manner of directly calling the test marked as asynchronous, * as the scheduled event can not authenticate, and endpoints * may require authentication. @@ -2557,6 +2623,10 @@ class WP_Site_Health { } foreach ( $tests['async'] as $test ) { + if ( ! empty( $test['skip_cron'] ) ) { + continue; + } + // Local endpoints may require authentication, so asynchronous tests can pass a direct test runner as well. if ( ! empty( $test['async_direct_test'] ) && is_callable( $test['async_direct_test'] ) ) { // This test is callable, do so and continue to the next asynchronous check. diff --git a/wp-admin/js/site-health.js b/wp-admin/js/site-health.js index 54497464cd..3314f41e1e 100644 --- a/wp-admin/js/site-health.js +++ b/wp-admin/js/site-health.js @@ -212,7 +212,8 @@ jQuery( document ).ready( function( $ ) { if ( 'undefined' !== typeof( this.has_rest ) && this.has_rest ) { wp.apiRequest( { - url: this.test + url: this.test, + headers: this.headers } ) .done( function( response ) { /** This filter is documented in wp-admin/includes/class-wp-site-health.php */ diff --git a/wp-admin/js/site-health.min.js b/wp-admin/js/site-health.min.js index fecd022138..1333d7a01f 100644 --- a/wp-admin/js/site-health.min.js +++ b/wp-admin/js/site-health.min.js @@ -1,2 +1,2 @@ /*! This file is auto-generated */ -jQuery(document).ready(function(c){var a,t,s,h=wp.i18n.__,n=wp.i18n._n,o=wp.i18n.sprintf,i=new ClipboardJS(".site-health-copy-buttons .copy-button"),d=c(".health-check-body.health-check-debug-tab").length,l=c("#health-check-accordion-block-wp-paths-sizes");function r(e){var t,s,a=wp.template("health-check-issue"),i=c("#health-check-issues-"+e.status);SiteHealth.site_status.issues[e.status]++,s=SiteHealth.site_status.issues[e.status],void 0===e.test&&(e.test=e.status+s),"critical"===e.status?t=o(n("%s critical issue","%s critical issues",s),''+s+""):"recommended"===e.status?t=o(n("%s recommended improvement","%s recommended improvements",s),''+s+""):"good"===e.status&&(t=o(n("%s item with no issues detected","%s items with no issues detected",s),''+s+"")),t&&c(".site-health-issue-count-title",i).html(t),c(".issues","#health-check-issues-"+e.status).append(a(e))}function u(){var e,t,s=c(".site-health-progress"),a=s.closest(".site-health-progress-wrapper"),i=c(".site-health-progress-label",a),n=c(".site-health-progress svg #bar"),o=parseInt(SiteHealth.site_status.issues.good,0)+parseInt(SiteHealth.site_status.issues.recommended,0)+1.5*parseInt(SiteHealth.site_status.issues.critical,0),l=.5*parseInt(SiteHealth.site_status.issues.recommended,0)+1.5*parseInt(SiteHealth.site_status.issues.critical,0),r=100-Math.ceil(l/o*100);0!==o?(a.removeClass("loading"),e=n.attr("r"),r<0&&(r=0),100"+e+"

"+t+"

",actions:""},r(wp.hooks.applyFilters("site_status_test_result",s))}i.on("success",function(e){var t=c(e.trigger),s=c(".success",t.closest("div"));e.clearSelection(),t.focus(),clearTimeout(a),s.removeClass("hidden"),a=setTimeout(function(){s.addClass("hidden"),i.clipboardAction.fakeElem&&i.clipboardAction.removeFake&&i.clipboardAction.removeFake()},3e3),wp.a11y.speak(h("Site information has been copied to your clipboard."))}),c(".health-check-accordion").on("click",".health-check-accordion-trigger",function(){"true"===c(this).attr("aria-expanded")?(c(this).attr("aria-expanded","false"),c("#"+c(this).attr("aria-controls")).attr("hidden",!0)):(c(this).attr("aria-expanded","true"),c("#"+c(this).attr("aria-controls")).attr("hidden",!1))}),c(".site-health-view-passed").on("click",function(){var e=c("#health-check-issues-good");e.toggleClass("hidden"),c(this).attr("aria-expanded",!e.hasClass("hidden"))}),"undefined"==typeof SiteHealth||d||(0===SiteHealth.site_status.direct.length&&0===SiteHealth.site_status.async.length?u():SiteHealth.site_status.issues={good:0,recommended:0,critical:0},0'+s+""):"recommended"===e.status?t=o(n("%s recommended improvement","%s recommended improvements",s),''+s+""):"good"===e.status&&(t=o(n("%s item with no issues detected","%s items with no issues detected",s),''+s+"")),t&&h(".site-health-issue-count-title",i).html(t),h(".issues","#health-check-issues-"+e.status).append(a(e))}function u(){var e,t,s=h(".site-health-progress"),a=s.closest(".site-health-progress-wrapper"),i=h(".site-health-progress-label",a),n=h(".site-health-progress svg #bar"),o=parseInt(SiteHealth.site_status.issues.good,0)+parseInt(SiteHealth.site_status.issues.recommended,0)+1.5*parseInt(SiteHealth.site_status.issues.critical,0),l=.5*parseInt(SiteHealth.site_status.issues.recommended,0)+1.5*parseInt(SiteHealth.site_status.issues.critical,0),r=100-Math.ceil(l/o*100);0!==o?(a.removeClass("loading"),e=n.attr("r"),r<0&&(r=0),100"+e+"

"+t+"

",actions:""},r(wp.hooks.applyFilters("site_status_test_result",s))}i.on("success",function(e){var t=h(e.trigger),s=h(".success",t.closest("div"));e.clearSelection(),t.focus(),clearTimeout(a),s.removeClass("hidden"),a=setTimeout(function(){s.addClass("hidden"),i.clipboardAction.fakeElem&&i.clipboardAction.removeFake&&i.clipboardAction.removeFake()},3e3),wp.a11y.speak(c("Site information has been copied to your clipboard."))}),h(".health-check-accordion").on("click",".health-check-accordion-trigger",function(){"true"===h(this).attr("aria-expanded")?(h(this).attr("aria-expanded","false"),h("#"+h(this).attr("aria-controls")).attr("hidden",!0)):(h(this).attr("aria-expanded","true"),h("#"+h(this).attr("aria-controls")).attr("hidden",!1))}),h(".site-health-view-passed").on("click",function(){var e=h("#health-check-issues-good");e.toggleClass("hidden"),h(this).attr("aria-expanded",!e.hasClass("hidden"))}),"undefined"==typeof SiteHealth||d||(0===SiteHealth.site_status.direct.length&&0===SiteHealth.site_status.async.length?u():SiteHealth.site_status.issues={good:0,recommended:0,critical:0},0namespace, + sprintf( + '/%s/%s', + $this->rest_base, + 'authorization-header' + ), + array( + array( + 'methods' => 'GET', + 'callback' => array( $this, 'test_authorization_header' ), + 'permission_callback' => function () { + return $this->validate_request_permission( 'authorization_header' ); + }, + ), + 'schema' => array( $this, 'get_public_item_schema' ), + ) + ); + register_rest_route( $this->namespace, sprintf( @@ -177,6 +196,17 @@ class WP_REST_Site_Health_Controller extends WP_REST_Controller { return $this->site_health->get_test_loopback_requests(); } + /** + * Checks that the authorization header is valid. + * + * @since 5.6.0 + * + * @return array + */ + public function test_authorization_header() { + return $this->site_health->get_test_authorization_header(); + } + /** * Gets the current directory sizes for this install. * diff --git a/wp-includes/version.php b/wp-includes/version.php index e0b1af5164..51ea30e4a7 100644 --- a/wp-includes/version.php +++ b/wp-includes/version.php @@ -13,7 +13,7 @@ * * @global string $wp_version */ -$wp_version = '5.6-beta1-49333'; +$wp_version = '5.6-beta1-49334'; /** * Holds the WordPress DB revision, increments when changes are made to the WordPress DB schema.