<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head><meta http-equiv="content-type" content="text/html; charset=utf-8" />
<title>[49154] trunk: Site Health, REST API: Move async tests to REST API endpoints.</title>
</head>
<body>

<style type="text/css"><!--
#msg dl.meta { border: 1px #006 solid; background: #369; padding: 6px; color: #fff; }
#msg dl.meta dt { float: left; width: 6em; font-weight: bold; }
#msg dt:after { content:':';}
#msg dl, #msg dt, #msg ul, #msg li, #header, #footer, #logmsg { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt;  }
#msg dl a { font-weight: bold}
#msg dl a:link    { color:#fc3; }
#msg dl a:active  { color:#ff0; }
#msg dl a:visited { color:#cc6; }
h3 { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt; font-weight: bold; }
#msg pre { white-space: pre-line; overflow: auto; background: #ffc; border: 1px #fa0 solid; padding: 6px; }
#logmsg { background: #ffc; border: 1px #fa0 solid; padding: 1em 1em 0 1em; }
#logmsg p, #logmsg pre, #logmsg blockquote { margin: 0 0 1em 0; }
#logmsg p, #logmsg li, #logmsg dt, #logmsg dd { line-height: 14pt; }
#logmsg h1, #logmsg h2, #logmsg h3, #logmsg h4, #logmsg h5, #logmsg h6 { margin: .5em 0; }
#logmsg h1:first-child, #logmsg h2:first-child, #logmsg h3:first-child, #logmsg h4:first-child, #logmsg h5:first-child, #logmsg h6:first-child { margin-top: 0; }
#logmsg ul, #logmsg ol { padding: 0; list-style-position: inside; margin: 0 0 0 1em; }
#logmsg ul { text-indent: -1em; padding-left: 1em; }#logmsg ol { text-indent: -1.5em; padding-left: 1.5em; }
#logmsg > ul, #logmsg > ol { margin: 0 0 1em 0; }
#logmsg pre { background: #eee; padding: 1em; }
#logmsg blockquote { border: 1px solid #fa0; border-left-width: 10px; padding: 1em 1em 0 1em; background: white;}
#logmsg dl { margin: 0; }
#logmsg dt { font-weight: bold; }
#logmsg dd { margin: 0; padding: 0 0 0.5em 0; }
#logmsg dd:before { content:'\00bb';}
#logmsg table { border-spacing: 0px; border-collapse: collapse; border-top: 4px solid #fa0; border-bottom: 1px solid #fa0; background: #fff; }
#logmsg table th { text-align: left; font-weight: normal; padding: 0.2em 0.5em; border-top: 1px dotted #fa0; }
#logmsg table td { text-align: right; border-top: 1px dotted #fa0; padding: 0.2em 0.5em; }
#logmsg table thead th { text-align: center; border-bottom: 1px solid #fa0; }
#logmsg table th.Corner { text-align: left; }
#logmsg hr { border: none 0; border-top: 2px dashed #fa0; height: 1px; }
#header, #footer { color: #fff; background: #636; border: 1px #300 solid; padding: 6px; }
#patch { width: 100%; }
#patch h4 {font-family: verdana,arial,helvetica,sans-serif;font-size:10pt;padding:8px;background:#369;color:#fff;margin:0;}
#patch .propset h4, #patch .binary h4 {margin:0;}
#patch pre {padding:0;line-height:1.2em;margin:0;}
#patch .diff {width:100%;background:#eee;padding: 0 0 10px 0;overflow:auto;}
#patch .propset .diff, #patch .binary .diff  {padding:10px 0;}
#patch span {display:block;padding:0 10px;}
#patch .modfile, #patch .addfile, #patch .delfile, #patch .propset, #patch .binary, #patch .copfile {border:1px solid #ccc;margin:10px 0;}
#patch ins {background:#dfd;text-decoration:none;display:block;padding:0 10px;}
#patch del {background:#fdd;text-decoration:none;display:block;padding:0 10px;}
#patch .lines, .info {color:#888;background:#fff;}
--></style>
<div id="msg">
<dl class="meta" style="font-size: 105%">
<dt style="float: left; width: 6em; font-weight: bold">Revision</dt> <dd><a style="font-weight: bold" href="https://core.trac.wordpress.org/changeset/49154">49154</a><script type="application/ld+json">{"@context":"http://schema.org","@type":"EmailMessage","description":"Review this Commit","action":{"@type":"ViewAction","url":"https://core.trac.wordpress.org/changeset/49154","name":"Review Commit"}}</script></dd>
<dt style="float: left; width: 6em; font-weight: bold">Author</dt> <dd>TimothyBlynJacobs</dd>
<dt style="float: left; width: 6em; font-weight: bold">Date</dt> <dd>2020-10-15 01:58:28 +0000 (Thu, 15 Oct 2020)</dd>
</dl>

<pre style='padding-left: 1em; margin: 2em 0; border-left: 2px solid #ccc; line-height: 1.25; font-size: 105%; font-family: sans-serif'>Site Health, REST API: Move async tests to REST API endpoints.

This provides more flexibility when writing tests and benefits from running in a front-end context which is necessary for some tests like checking that updates are supported. Additionally, this provides a more robust interface for developers who want to integrate with Site Health tests.

Because the `wp/v2` endpoint is reserved for modeling core entities, site health is registered in its own `wp-site-health/v1` namespace.

The existing ajax actions have been maintained for backward compatibility.

Props Clorith, chrisvanpatten, afragen, pokhriyal, TimothyBlynJacobs.
Fixes <a href="https://core.trac.wordpress.org/ticket/48105">#48105</a>.</pre>

<h3>Modified Paths</h3>
<ul>
<li><a href="#trunksrcjs_enqueuesadminsitehealthjs">trunk/src/js/_enqueues/admin/site-health.js</a></li>
<li><a href="#trunksrcwpadminadminajaxphp">trunk/src/wp-admin/admin-ajax.php</a></li>
<li><a href="#trunksrcwpadminincludesajaxactionsphp">trunk/src/wp-admin/includes/ajax-actions.php</a></li>
<li><a href="#trunksrcwpadminincludesclasswpsitehealthautoupdatesphp">trunk/src/wp-admin/includes/class-wp-site-health-auto-updates.php</a></li>
<li><a href="#trunksrcwpadminincludesclasswpsitehealthphp">trunk/src/wp-admin/includes/class-wp-site-health.php</a></li>
<li><a href="#trunksrcwpincludesrestapiphp">trunk/src/wp-includes/rest-api.php</a></li>
<li><a href="#trunksrcwpincludesscriptloaderphp">trunk/src/wp-includes/script-loader.php</a></li>
<li><a href="#trunksrcwpsettingsphp">trunk/src/wp-settings.php</a></li>
<li><a href="#trunktestsphpunittestsrestapirestschemasetupphp">trunk/tests/phpunit/tests/rest-api/rest-schema-setup.php</a></li>
<li><a href="#trunktestsqunitfixtureswpapigeneratedjs">trunk/tests/qunit/fixtures/wp-api-generated.js</a></li>
</ul>

<h3>Added Paths</h3>
<ul>
<li><a href="#trunksrcwpincludesrestapiendpointsclasswprestsitehealthcontrollerphp">trunk/src/wp-includes/rest-api/endpoints/class-wp-rest-site-health-controller.php</a></li>
<li><a href="#trunktestsphpunittestsrestapirestsitehealthcontrollerphp">trunk/tests/phpunit/tests/rest-api/rest-site-health-controller.php</a></li>
</ul>

</div>
<div id="patch">
<h3>Diff</h3>
<a id="trunksrcjs_enqueuesadminsitehealthjs"></a>
<div class="modfile"><h4 style="background-color: #eee; color: inherit; margin: 1em 0; padding: 1.3em; font-size: 115%">Modified: trunk/src/js/_enqueues/admin/site-health.js</h4>
<pre class="diff"><span>
<span class="info" style="display: block; padding: 0 10px; color: #888">--- trunk/src/js/_enqueues/admin/site-health.js       2020-10-15 00:14:51 UTC (rev 49153)
+++ trunk/src/js/_enqueues/admin/site-health.js 2020-10-15 01:58:28 UTC (rev 49154)
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -11,7 +11,6 @@
</span><span class="cx" style="display: block; padding: 0 10px">        var __ = wp.i18n.__,
</span><span class="cx" style="display: block; padding: 0 10px">                _n = wp.i18n._n,
</span><span class="cx" style="display: block; padding: 0 10px">                sprintf = wp.i18n.sprintf,
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-                data,
</del><span class="cx" style="display: block; padding: 0 10px">                 clipboard = new ClipboardJS( '.site-health-copy-buttons .copy-button' ),
</span><span class="cx" style="display: block; padding: 0 10px">                isDebugTab = $( '.health-check-body.health-check-debug-tab' ).length,
</span><span class="cx" style="display: block; padding: 0 10px">                pathsSizesSection = $( '#health-check-accordion-block-wp-paths-sizes' ),
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -78,11 +77,16 @@
</span><span class="cx" style="display: block; padding: 0 10px">                        issueWrapper = $( '#health-check-issues-' + issue.status ),
</span><span class="cx" style="display: block; padding: 0 10px">                        heading,
</span><span class="cx" style="display: block; padding: 0 10px">                        count;
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-                
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+
</ins><span class="cx" style="display: block; padding: 0 10px">                 SiteHealth.site_status.issues[ issue.status ]++;
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">                count = SiteHealth.site_status.issues[ issue.status ];
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+                // If no test name is supplied, append a placeholder for markup references.
+               if ( typeof issue.test === 'undefined' ) {
+                       issue.test = issue.status + count;
+               }
+
</ins><span class="cx" style="display: block; padding: 0 10px">                 if ( 'critical' === issue.status ) {
</span><span class="cx" style="display: block; padding: 0 10px">                        heading = sprintf(
</span><span class="cx" style="display: block; padding: 0 10px">                                _n( '%s critical issue', '%s critical issues', count ),
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -119,10 +123,10 @@
</span><span class="cx" style="display: block; padding: 0 10px">                var $progressLabel = $( '.site-health-progress-label', $wrapper );
</span><span class="cx" style="display: block; padding: 0 10px">                var $circle = $( '.site-health-progress svg #bar' );
</span><span class="cx" style="display: block; padding: 0 10px">                var totalTests = parseInt( SiteHealth.site_status.issues.good, 0 ) +
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-                                parseInt( SiteHealth.site_status.issues.recommended, 0 ) +
-                               ( parseInt( SiteHealth.site_status.issues.critical, 0 ) * 1.5 );
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+                 parseInt( SiteHealth.site_status.issues.recommended, 0 ) +
+                       ( parseInt( SiteHealth.site_status.issues.critical, 0 ) * 1.5 );
</ins><span class="cx" style="display: block; padding: 0 10px">                 var failedTests = ( parseInt( SiteHealth.site_status.issues.recommended, 0 ) * 0.5 ) +
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-                                ( parseInt( SiteHealth.site_status.issues.critical, 0 ) * 1.5 );
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+                 ( parseInt( SiteHealth.site_status.issues.critical, 0 ) * 1.5 );
</ins><span class="cx" style="display: block; padding: 0 10px">                 var val = 100 - Math.ceil( ( failedTests / totalTests ) * 100 );
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">                if ( 0 === totalTests ) {
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -206,15 +210,49 @@
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">                                this.completed = true;
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-                                $.post(
-                                       ajaxurl,
-                                       data,
-                                       function( response ) {
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+                         if ( 'undefined' !== typeof( this.has_rest ) && this.has_rest ) {
+                                       wp.apiRequest( {
+                                               url: this.test
+                                       } )
+                                               .done( function( response ) {
+                                                       /** This filter is documented in wp-admin/includes/class-wp-site-health.php */
+                                                       appendIssue( wp.hooks.applyFilters( 'site_status_test_result', response ) );
+                                               } )
+                                               .fail( function( response ) {
+                                                       var description;
+
+                                                       if ( 'undefined' !== typeof( response.responseJSON ) && 'undefined' !== typeof( response.responseJSON.message ) ) {
+                                                               description = response.responseJSON.message;
+                                                       } else {
+                                                               description = __( 'No details available' );
+                                                       }
+
+                                                       addFailedSiteHealthCheckNotice( this.url, description );
+                                               } )
+                                               .always( function() {
+                                                       maybeRunNextAsyncTest();
+                                               } );
+                               } else {
+                                       $.post(
+                                               ajaxurl,
+                                               data
+                                       ).done( function( response ) {
</ins><span class="cx" style="display: block; padding: 0 10px">                                                 /** This filter is documented in wp-admin/includes/class-wp-site-health.php */
</span><span class="cx" style="display: block; padding: 0 10px">                                                appendIssue( wp.hooks.applyFilters( 'site_status_test_result', response.data ) );
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+                                        } ).fail( function( response ) {
+                                               var description;
+
+                                               if ( 'undefined' !== typeof( response.responseJSON ) && 'undefined' !== typeof( response.responseJSON.message ) ) {
+                                                       description = response.responseJSON.message;
+                                               } else {
+                                                       description = __( 'No details available' );
+                                               }
+
+                                               addFailedSiteHealthCheckNotice( this.url, description );
+                                       } ).always( function() {
</ins><span class="cx" style="display: block; padding: 0 10px">                                                 maybeRunNextAsyncTest();
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-                                        }
-                               );
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+                                 } );
+                               }
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">                                return false;
</span><span class="cx" style="display: block; padding: 0 10px">                        } );
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -225,6 +263,29 @@
</span><span class="cx" style="display: block; padding: 0 10px">                }
</span><span class="cx" style="display: block; padding: 0 10px">        }
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+        /**
+        * Add the details of a failed asynchronous test to the list of test results.
+        *
+        * @since 5.6.0
+        */
+       function addFailedSiteHealthCheckNotice( url, description ) {
+               var issue;
+
+               issue = {
+                       'status': 'recommended',
+                       'label': __( 'A test is unavailable' ),
+                       'badge': {
+                               'color': 'red',
+                               'label': __( 'Unavailable' )
+                       },
+                       'description': '<p>' + url + '</p><p>' + description + '</p>',
+                       'actions': ''
+               };
+
+               /** This filter is documented in wp-admin/includes/class-wp-site-health.php */
+               appendIssue( wp.hooks.applyFilters( 'site_status_test_result', issue ) );
+       }
+
</ins><span class="cx" style="display: block; padding: 0 10px">         if ( 'undefined' !== typeof SiteHealth && ! isDebugTab ) {
</span><span class="cx" style="display: block; padding: 0 10px">                if ( 0 === SiteHealth.site_status.direct.length && 0 === SiteHealth.site_status.async.length ) {
</span><span class="cx" style="display: block; padding: 0 10px">                        recalculateProgression();
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -243,21 +304,7 @@
</span><span class="cx" style="display: block; padding: 0 10px">                }
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">                if ( 0 < SiteHealth.site_status.async.length ) {
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-                        data = {
-                               'action': 'health-check-' + SiteHealth.site_status.async[0].test.replace( '_', '-' ),
-                               '_wpnonce': SiteHealth.nonce.site_status
-                       };
-
-                       SiteHealth.site_status.async[0].completed = true;
-
-                       $.post(
-                               ajaxurl,
-                               data,
-                               function( response ) {
-                                       appendIssue( response.data );
-                                       maybeRunNextAsyncTest();
-                               }
-                       );
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+                 maybeRunNextAsyncTest();
</ins><span class="cx" style="display: block; padding: 0 10px">                 } else {
</span><span class="cx" style="display: block; padding: 0 10px">                        recalculateProgression();
</span><span class="cx" style="display: block; padding: 0 10px">                }
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -264,11 +311,6 @@
</span><span class="cx" style="display: block; padding: 0 10px">        }
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">        function getDirectorySizes() {
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-                var data = {
-                       action: 'health-check-get-sizes',
-                       _wpnonce: SiteHealth.nonce.site_status_result
-               };
-
</del><span class="cx" style="display: block; padding: 0 10px">                 var timestamp = ( new Date().getTime() );
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">                // After 3 seconds announce that we're still waiting for directory sizes.
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -276,13 +318,10 @@
</span><span class="cx" style="display: block; padding: 0 10px">                        wp.a11y.speak( __( 'Please wait...' ) );
</span><span class="cx" style="display: block; padding: 0 10px">                }, 3000 );
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-                $.post( {
-                       type: 'POST',
-                       url: ajaxurl,
-                       data: data,
-                       dataType: 'json'
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+         wp.apiRequest( {
+                       path: '/wp-site-health/v1/directory-sizes'
</ins><span class="cx" style="display: block; padding: 0 10px">                 } ).done( function( response ) {
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-                        updateDirSizes( response.data || {} );
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+                 updateDirSizes( response || {} );
</ins><span class="cx" style="display: block; padding: 0 10px">                 } ).always( function() {
</span><span class="cx" style="display: block; padding: 0 10px">                        var delay = ( new Date().getTime() ) - timestamp;
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -289,7 +328,7 @@
</span><span class="cx" style="display: block; padding: 0 10px">                        $( '.health-check-wp-paths-sizes.spinner' ).css( 'visibility', 'hidden' );
</span><span class="cx" style="display: block; padding: 0 10px">                        recalculateProgression();
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-                        if ( delay > 3000  ) {
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+                 if ( delay > 3000 ) {
</ins><span class="cx" style="display: block; padding: 0 10px">                                 /*
</span><span class="cx" style="display: block; padding: 0 10px">                                 * We have announced that we're waiting.
</span><span class="cx" style="display: block; padding: 0 10px">                                 * Announce that we're ready after giving at least 3 seconds
</span></span></pre></div>
<a id="trunksrcwpadminadminajaxphp"></a>
<div class="modfile"><h4 style="background-color: #eee; color: inherit; margin: 1em 0; padding: 1.3em; font-size: 115%">Modified: trunk/src/wp-admin/admin-ajax.php</h4>
<pre class="diff"><span>
<span class="info" style="display: block; padding: 0 10px; color: #888">--- trunk/src/wp-admin/admin-ajax.php 2020-10-15 00:14:51 UTC (rev 49153)
+++ trunk/src/wp-admin/admin-ajax.php   2020-10-15 01:58:28 UTC (rev 49154)
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -143,7 +143,15 @@
</span><span class="cx" style="display: block; padding: 0 10px"> );
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px"> // Deprecated.
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-$core_actions_post_deprecated = array( 'wp-fullscreen-save-post', 'press-this-save-post', 'press-this-add-category' );
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+$core_actions_post_deprecated = array(
+       'wp-fullscreen-save-post',
+       'press-this-save-post',
+       'press-this-add-category',
+       'health-check-dotorg-communication',
+       'health-check-is-in-debug-mode',
+       'health-check-background-updates',
+       'health-check-loopback-requests',
+);
</ins><span class="cx" style="display: block; padding: 0 10px"> $core_actions_post            = array_merge( $core_actions_post, $core_actions_post_deprecated );
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px"> // Register core Ajax calls.
</span></span></pre></div>
<a id="trunksrcwpadminincludesajaxactionsphp"></a>
<div class="modfile"><h4 style="background-color: #eee; color: inherit; margin: 1em 0; padding: 1.3em; font-size: 115%">Modified: trunk/src/wp-admin/includes/ajax-actions.php</h4>
<pre class="diff"><span>
<span class="info" style="display: block; padding: 0 10px; color: #888">--- trunk/src/wp-admin/includes/ajax-actions.php      2020-10-15 00:14:51 UTC (rev 49153)
+++ trunk/src/wp-admin/includes/ajax-actions.php        2020-10-15 01:58:28 UTC (rev 49154)
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -5142,8 +5142,21 @@
</span><span class="cx" style="display: block; padding: 0 10px">  * Ajax handler for site health checks on server communication.
</span><span class="cx" style="display: block; padding: 0 10px">  *
</span><span class="cx" style="display: block; padding: 0 10px">  * @since 5.2.0
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+ * @deprecated 5.6.0 Use WP_REST_Site_Health_Controller::test_dotorg_communication()
+ * @see WP_REST_Site_Health_Controller::test_dotorg_communication()
</ins><span class="cx" style="display: block; padding: 0 10px">  */
</span><span class="cx" style="display: block; padding: 0 10px"> function wp_ajax_health_check_dotorg_communication() {
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+        _doing_it_wrong(
+               'wp_ajax_health_check_dotorg_communication',
+               sprintf(
+               // translators: 1: The Site Health action that is no longer used by core. 2: The new function that replaces it.
+                       __( 'The Site Health check for %1$s has been replaced with %2$s.' ),
+                       'wp_ajax_health_check_dotorg_communication',
+                       'WP_REST_Site_Health_Controller::test_dotorg_communication'
+               ),
+               '5.6.0'
+       );
+
</ins><span class="cx" style="display: block; padding: 0 10px">         check_ajax_referer( 'health-check-site-status' );
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">        if ( ! current_user_can( 'view_site_health_checks' ) ) {
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -5162,8 +5175,21 @@
</span><span class="cx" style="display: block; padding: 0 10px">  * Ajax handler for site health checks on background updates.
</span><span class="cx" style="display: block; padding: 0 10px">  *
</span><span class="cx" style="display: block; padding: 0 10px">  * @since 5.2.0
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+ * @deprecated 5.6.0 Use WP_REST_Site_Health_Controller::test_background_updates()
+ * @see WP_REST_Site_Health_Controller::test_background_updates()
</ins><span class="cx" style="display: block; padding: 0 10px">  */
</span><span class="cx" style="display: block; padding: 0 10px"> function wp_ajax_health_check_background_updates() {
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+        _doing_it_wrong(
+               'wp_ajax_health_check_background_updates',
+               sprintf(
+               // translators: 1: The Site Health action that is no longer used by core. 2: The new function that replaces it.
+                       __( 'The Site Health check for %1$s has been replaced with %2$s.' ),
+                       'wp_ajax_health_check_background_updates',
+                       'WP_REST_Site_Health_Controller::test_background_updates'
+               ),
+               '5.6.0'
+       );
+
</ins><span class="cx" style="display: block; padding: 0 10px">         check_ajax_referer( 'health-check-site-status' );
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">        if ( ! current_user_can( 'view_site_health_checks' ) ) {
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -5182,8 +5208,21 @@
</span><span class="cx" style="display: block; padding: 0 10px">  * Ajax handler for site health checks on loopback requests.
</span><span class="cx" style="display: block; padding: 0 10px">  *
</span><span class="cx" style="display: block; padding: 0 10px">  * @since 5.2.0
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+ * @deprecated 5.6.0 Use WP_REST_Site_Health_Controller::test_loopback_requests()
+ * @see WP_REST_Site_Health_Controller::test_loopback_requests()
</ins><span class="cx" style="display: block; padding: 0 10px">  */
</span><span class="cx" style="display: block; padding: 0 10px"> function wp_ajax_health_check_loopback_requests() {
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+        _doing_it_wrong(
+               'wp_ajax_health_check_loopback_requests',
+               sprintf(
+               // translators: 1: The Site Health action that is no longer used by core. 2: The new function that replaces it.
+                       __( 'The Site Health check for %1$s has been replaced with %2$s.' ),
+                       'wp_ajax_health_check_loopback_requests',
+                       'WP_REST_Site_Health_Controller::test_loopback_requests'
+               ),
+               '5.6.0'
+       );
+
</ins><span class="cx" style="display: block; padding: 0 10px">         check_ajax_referer( 'health-check-site-status' );
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">        if ( ! current_user_can( 'view_site_health_checks' ) ) {
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -5219,8 +5258,21 @@
</span><span class="cx" style="display: block; padding: 0 10px">  * Ajax handler for site health check to get directories and database sizes.
</span><span class="cx" style="display: block; padding: 0 10px">  *
</span><span class="cx" style="display: block; padding: 0 10px">  * @since 5.2.0
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+ * @deprecated 5.6.0 Use WP_REST_Site_Health_Controller::get_directory_sizes()
+ * @see WP_REST_Site_Health_Controller::get_directory_sizes()
</ins><span class="cx" style="display: block; padding: 0 10px">  */
</span><span class="cx" style="display: block; padding: 0 10px"> function wp_ajax_health_check_get_sizes() {
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+        _doing_it_wrong(
+               'wp_ajax_health_check_get_sizes',
+               sprintf(
+               // translators: 1: The Site Health action that is no longer used by core. 2: The new function that replaces it.
+                       __( 'The Site Health check for %1$s has been replaced with %2$s.' ),
+                       'wp_ajax_health_check_get_sizes',
+                       'WP_REST_Site_Health_Controller::get_directory_sizes'
+               ),
+               '5.6.0'
+       );
+
</ins><span class="cx" style="display: block; padding: 0 10px">         check_ajax_referer( 'health-check-site-status-result' );
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">        if ( ! current_user_can( 'view_site_health_checks' ) || is_multisite() ) {
</span></span></pre></div>
<a id="trunksrcwpadminincludesclasswpsitehealthautoupdatesphp"></a>
<div class="modfile"><h4 style="background-color: #eee; color: inherit; margin: 1em 0; padding: 1.3em; font-size: 115%">Modified: trunk/src/wp-admin/includes/class-wp-site-health-auto-updates.php</h4>
<pre class="diff"><span>
<span class="info" style="display: block; padding: 0 10px; color: #888">--- trunk/src/wp-admin/includes/class-wp-site-health-auto-updates.php 2020-10-15 00:14:51 UTC (rev 49153)
+++ trunk/src/wp-admin/includes/class-wp-site-health-auto-updates.php   2020-10-15 01:58:28 UTC (rev 49154)
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -90,49 +90,10 @@
</span><span class="cx" style="display: block; padding: 0 10px">         * @return array The test results.
</span><span class="cx" style="display: block; padding: 0 10px">         */
</span><span class="cx" style="display: block; padding: 0 10px">        public function test_wp_version_check_attached() {
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-                if ( ! is_main_site() ) {
-                       return;
-               }
-
-               $cookies = wp_unslash( $_COOKIE );
-               $timeout = 10;
-               $headers = array(
-                       'Cache-Control' => 'no-cache',
-               );
-               /** This filter is documented in wp-includes/class-wp-http-streams.php */
-               $sslverify = apply_filters( 'https_local_ssl_verify', false );
-
-               // Include Basic auth in loopback requests.
-               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 = add_query_arg(
-                       array(
-                               'health-check-test-wp_version_check' => true,
-                       ),
-                       admin_url( 'site-health.php' )
-               );
-
-               $test = wp_remote_get( $url, compact( 'cookies', 'headers', 'timeout', 'sslverify' ) );
-
-               if ( is_wp_error( $test ) ) {
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+         if ( ! has_filter( 'wp_version_check', 'wp_version_check' ) ) {
</ins><span class="cx" style="display: block; padding: 0 10px">                         return array(
</span><span class="cx" style="display: block; padding: 0 10px">                                'description' => sprintf(
</span><span class="cx" style="display: block; padding: 0 10px">                                        /* translators: %s: Name of the filter used. */
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-                                        __( 'Could not confirm that the %s filter is available.' ),
-                                       '<code>wp_version_check()</code>'
-                               ),
-                               'severity'    => 'warning',
-                       );
-               }
-
-               $response = wp_remote_retrieve_body( $test );
-
-               if ( 'yes' !== $response ) {
-                       return array(
-                               'description' => sprintf(
-                                       /* translators: %s: Name of the filter used. */
</del><span class="cx" style="display: block; padding: 0 10px">                                         __( 'A plugin has prevented updates by disabling %s.' ),
</span><span class="cx" style="display: block; padding: 0 10px">                                        '<code>wp_version_check()</code>'
</span><span class="cx" style="display: block; padding: 0 10px">                                ),
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -310,6 +271,11 @@
</span><span class="cx" style="display: block; padding: 0 10px">         * @return array The test results.
</span><span class="cx" style="display: block; padding: 0 10px">         */
</span><span class="cx" style="display: block; padding: 0 10px">        function test_check_wp_filesystem_method() {
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+                // Make sure the `request_filesystem_credentials` function is available during our REST call.
+               if ( ! function_exists( 'request_filesystem_credentials' ) ) {
+                       require_once ABSPATH . '/wp-admin/includes/file.php';
+               }
+
</ins><span class="cx" style="display: block; padding: 0 10px">                 $skin    = new Automatic_Upgrader_Skin;
</span><span class="cx" style="display: block; padding: 0 10px">                $success = $skin->request_filesystem_credentials( false, ABSPATH );
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -356,6 +322,11 @@
</span><span class="cx" style="display: block; padding: 0 10px">                        return false;
</span><span class="cx" style="display: block; padding: 0 10px">                }
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+                // Make sure the `get_core_checksums` function is available during our REST call.
+               if ( ! function_exists( 'get_core_checksums' ) ) {
+                       require_once ABSPATH . '/wp-admin/includes/update.php';
+               }
+
</ins><span class="cx" style="display: block; padding: 0 10px">                 $checksums = get_core_checksums( $wp_version, 'en_US' );
</span><span class="cx" style="display: block; padding: 0 10px">                $dev       = ( false !== strpos( $wp_version, '-' ) );
</span><span class="cx" style="display: block; padding: 0 10px">                // Get the last stable version's files and test against that.
</span></span></pre></div>
<a id="trunksrcwpadminincludesclasswpsitehealthphp"></a>
<div class="modfile"><h4 style="background-color: #eee; color: inherit; margin: 1em 0; padding: 1.3em; font-size: 115%">Modified: trunk/src/wp-admin/includes/class-wp-site-health.php</h4>
<pre class="diff"><span>
<span class="info" style="display: block; padding: 0 10px; color: #888">--- trunk/src/wp-admin/includes/class-wp-site-health.php      2020-10-15 00:14:51 UTC (rev 49153)
+++ trunk/src/wp-admin/includes/class-wp-site-health.php        2020-10-15 01:58:28 UTC (rev 49154)
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -133,6 +133,7 @@
</span><span class="cx" style="display: block; padding: 0 10px">                                if ( is_string( $test['test'] ) ) {
</span><span class="cx" style="display: block; padding: 0 10px">                                        $health_check_js_variables['site_status']['async'][] = array(
</span><span class="cx" style="display: block; padding: 0 10px">                                                'test'      => $test['test'],
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+                                                'has_rest'  => ( isset( $test['has_rest'] ) ? $test['has_rest'] : false ),
</ins><span class="cx" style="display: block; padding: 0 10px">                                                 'completed' => false,
</span><span class="cx" style="display: block; padding: 0 10px">                                        );
</span><span class="cx" style="display: block; padding: 0 10px">                                }
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -2080,6 +2081,7 @@
</span><span class="cx" style="display: block; padding: 0 10px">         * experiences.
</span><span class="cx" style="display: block; padding: 0 10px">         *
</span><span class="cx" style="display: block; padding: 0 10px">         * @since 5.2.0
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+         * @since 5.6.0 Added support for `has_rest` and `permissions`.
</ins><span class="cx" style="display: block; padding: 0 10px">          *
</span><span class="cx" style="display: block; padding: 0 10px">         * @return array The list of tests to run.
</span><span class="cx" style="display: block; padding: 0 10px">         */
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -2153,16 +2155,19 @@
</span><span class="cx" style="display: block; padding: 0 10px">                        ),
</span><span class="cx" style="display: block; padding: 0 10px">                        'async'  => array(
</span><span class="cx" style="display: block; padding: 0 10px">                                'dotorg_communication' => array(
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-                                        'label' => __( 'Communication with WordPress.org' ),
-                                       'test'  => 'dotorg_communication',
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+                                 'label'    => __( 'Communication with WordPress.org' ),
+                                       'test'     => rest_url( 'wp-site-health/v1/tests/dotorg-communication' ),
+                                       'has_rest' => true,
</ins><span class="cx" style="display: block; padding: 0 10px">                                 ),
</span><span class="cx" style="display: block; padding: 0 10px">                                'background_updates'   => array(
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-                                        'label' => __( 'Background updates' ),
-                                       'test'  => 'background_updates',
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+                                 'label'    => __( 'Background updates' ),
+                                       'test'     => rest_url( 'wp-site-health/v1/tests/background-updates' ),
+                                       'has_rest' => true,
</ins><span class="cx" style="display: block; padding: 0 10px">                                 ),
</span><span class="cx" style="display: block; padding: 0 10px">                                'loopback_requests'    => array(
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-                                        'label' => __( 'Loopback request' ),
-                                       'test'  => 'loopback_requests',
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+                                 'label'    => __( 'Loopback request' ),
+                                       'test'     => rest_url( 'wp-site-health/v1/tests/loopback-requests' ),
+                                       'has_rest' => true,
</ins><span class="cx" style="display: block; padding: 0 10px">                                 ),
</span><span class="cx" style="display: block; padding: 0 10px">                        ),
</span><span class="cx" style="display: block; padding: 0 10px">                );
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -2199,9 +2204,10 @@
</span><span class="cx" style="display: block; padding: 0 10px">                 *         Plugins and themes are encouraged to prefix test identifiers with their slug
</span><span class="cx" style="display: block; padding: 0 10px">                 *         to avoid any collisions between tests.
</span><span class="cx" style="display: block; padding: 0 10px">                 *
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-                 *         @type string $label A friendly label for your test to identify it by.
-                *         @type mixed  $test  A callable to perform a direct test, or a string Ajax action to be called
-                *                             to perform an async test.
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+          *         @type string  $label       A friendly label for your test to identify it by.
+                *         @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.
</ins><span class="cx" style="display: block; padding: 0 10px">                  *     }
</span><span class="cx" style="display: block; padding: 0 10px">                 * }
</span><span class="cx" style="display: block; padding: 0 10px">                 */
</span></span></pre></div>
<a id="trunksrcwpincludesrestapiendpointsclasswprestsitehealthcontrollerphp"></a>
<div class="addfile"><h4 style="background-color: #eee; color: inherit; margin: 1em 0; padding: 1.3em; font-size: 115%">Added: trunk/src/wp-includes/rest-api/endpoints/class-wp-rest-site-health-controller.php</h4>
<pre class="diff"><span>
<span class="info" style="display: block; padding: 0 10px; color: #888">--- trunk/src/wp-includes/rest-api/endpoints/class-wp-rest-site-health-controller.php                         (rev 0)
+++ trunk/src/wp-includes/rest-api/endpoints/class-wp-rest-site-health-controller.php   2020-10-15 01:58:28 UTC (rev 49154)
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -0,0 +1,293 @@
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+<?php
+/**
+ * REST API: WP_REST_Site_Health_Controller class
+ *
+ * @package WordPress
+ * @subpackage REST_API
+ * @since 5.6.0
+ */
+
+/**
+ * Core class for interacting with Site Health tests.
+ *
+ * @since 5.6.0
+ *
+ * @see WP_REST_Controller
+ */
+class WP_REST_Site_Health_Controller extends WP_REST_Controller {
+
+       /**
+        * An instance of the site health class.
+        *
+        * @since 5.6.0
+        *
+        * @var WP_Site_Health
+        */
+       private $site_health;
+
+       /**
+        * Site Health controller constructor.
+        *
+        * @since 5.6.0
+        *
+        * @param WP_Site_Health $site_health An instance of the site health class.
+        */
+       public function __construct( $site_health ) {
+               $this->namespace = 'wp-site-health/v1';
+               $this->rest_base = 'tests';
+
+               $this->site_health = $site_health;
+       }
+
+       /**
+        * Registers API routes.
+        *
+        * @since 5.6.0
+        *
+        * @see register_rest_route()
+        */
+       public function register_routes() {
+               register_rest_route(
+                       $this->namespace,
+                       sprintf(
+                               '/%s/%s',
+                               $this->rest_base,
+                               'background-updates'
+                       ),
+                       array(
+                               array(
+                                       'methods'             => 'GET',
+                                       'callback'            => array( $this, 'test_background_updates' ),
+                                       'permission_callback' => function () {
+                                               return $this->validate_request_permission( 'background_updates' );
+                                       },
+                               ),
+                               'schema' => array( $this, 'get_public_item_schema' ),
+                       )
+               );
+
+               register_rest_route(
+                       $this->namespace,
+                       sprintf(
+                               '/%s/%s',
+                               $this->rest_base,
+                               'loopback-requests'
+                       ),
+                       array(
+                               array(
+                                       'methods'             => 'GET',
+                                       'callback'            => array( $this, 'test_loopback_requests' ),
+                                       'permission_callback' => function () {
+                                               return $this->validate_request_permission( 'loopback_requests' );
+                                       },
+                               ),
+                               'schema' => array( $this, 'get_public_item_schema' ),
+                       )
+               );
+
+               register_rest_route(
+                       $this->namespace,
+                       sprintf(
+                               '/%s/%s',
+                               $this->rest_base,
+                               'dotorg-communication'
+                       ),
+                       array(
+                               array(
+                                       'methods'             => 'GET',
+                                       'callback'            => array( $this, 'test_dotorg_communication' ),
+                                       'permission_callback' => function () {
+                                               return $this->validate_request_permission( 'dotorg_communication' );
+                                       },
+                               ),
+                               'schema' => array( $this, 'get_public_item_schema' ),
+                       )
+               );
+
+               register_rest_route(
+                       $this->namespace,
+                       sprintf(
+                               '/%s',
+                               'directory-sizes'
+                       ),
+                       array(
+                               'methods'             => 'GET',
+                               'callback'            => array( $this, 'get_directory_sizes' ),
+                               'permission_callback' => function() {
+                                       return $this->validate_request_permission( 'debug_enabled' ) && ! is_multisite();
+                               },
+                       )
+               );
+       }
+
+       /**
+        * Validates if the current user can request this REST endpoint.
+        *
+        * @since 5.6.0
+        *
+        * @param string $check The endpoint check being ran.
+        * @return bool
+        */
+       protected function validate_request_permission( $check ) {
+               $default_capability = 'view_site_health_checks';
+
+               /**
+                * Filters the capability needed to run a given Site Health check.
+                *
+                * @since 5.6.0
+                *
+                * @param string $default_capability The default capability required for this check.
+                * @param string $check              The Site Health check being performed.
+                */
+               $capability = apply_filters( "site_health_test_rest_capability_{$check}", $default_capability, $check );
+
+               return current_user_can( $capability );
+       }
+
+       /**
+        * Checks if background updates work as expected.
+        *
+        * @since 5.6.0
+        *
+        * @return array
+        */
+       public function test_background_updates() {
+               return $this->site_health->get_test_background_updates();
+       }
+
+       /**
+        * Checks that the site can reach the WordPress.org API.
+        *
+        * @since 5.6.0
+        *
+        * @return array
+        */
+       public function test_dotorg_communication() {
+               return $this->site_health->get_test_dotorg_communication();
+       }
+
+       /**
+        * Checks that loopbacks can be performed.
+        *
+        * @since 5.6.0
+        *
+        * @return array
+        */
+       public function test_loopback_requests() {
+               return $this->site_health->get_test_loopback_requests();
+       }
+
+       /**
+        * Gets the current directory sizes for this install.
+        *
+        * @since 5.6.0
+        *
+        * @return array|WP_Error
+        */
+       public function get_directory_sizes() {
+               if ( ! class_exists( 'WP_Debug_Data' ) ) {
+                       require_once( ABSPATH . 'wp-admin/includes/class-wp-debug-data.php' );
+               }
+
+               $sizes_data = WP_Debug_Data::get_sizes();
+               $all_sizes  = array( 'raw' => 0 );
+
+               foreach ( $sizes_data as $name => $value ) {
+                       $name = sanitize_text_field( $name );
+                       $data = array();
+
+                       if ( isset( $value['size'] ) ) {
+                               if ( is_string( $value['size'] ) ) {
+                                       $data['size'] = sanitize_text_field( $value['size'] );
+                               } else {
+                                       $data['size'] = (int) $value['size'];
+                               }
+                       }
+
+                       if ( isset( $value['debug'] ) ) {
+                               if ( is_string( $value['debug'] ) ) {
+                                       $data['debug'] = sanitize_text_field( $value['debug'] );
+                               } else {
+                                       $data['debug'] = (int) $value['debug'];
+                               }
+                       }
+
+                       if ( ! empty( $value['raw'] ) ) {
+                               $data['raw'] = (int) $value['raw'];
+                       }
+
+                       $all_sizes[ $name ] = $data;
+               }
+
+               if ( isset( $all_sizes['total_size']['debug'] ) && 'not available' === $all_sizes['total_size']['debug'] ) {
+                       return new WP_Error( 'not_available', __( 'Directory sizes could not be returned.' ), array( 'status' => 500 ) );
+               }
+
+               return $all_sizes;
+       }
+
+       /**
+        * Gets the schema for each site health test.
+        *
+        * @since 5.6.0
+        *
+        * @return array The test schema.
+        */
+       public function get_item_schema() {
+               if ( $this->schema ) {
+                       return $this->schema;
+               }
+
+               $this->schema = array(
+                       '$schema'    => 'http://json-schema.org/draft-04/schema#',
+                       'title'      => 'wp-site-health-test',
+                       'type'       => 'object',
+                       'properties' => array(
+                               'test'        => array(
+                                       'type'        => 'string',
+                                       'description' => __( 'The name of the test being run.' ),
+                                       'readonly'    => true,
+                               ),
+                               'label'       => array(
+                                       'type'        => 'string',
+                                       'description' => __( 'A label describing the test.' ),
+                                       'readonly'    => true,
+                               ),
+                               'status'      => array(
+                                       'type'        => 'string',
+                                       'description' => __( 'The status of the test.' ),
+                                       'enum'        => array( 'good', 'recommended', 'critical' ),
+                                       'readonly'    => true,
+                               ),
+                               'badge'       => array(
+                                       'type'        => 'object',
+                                       'description' => __( 'The category this test is grouped in.' ),
+                                       'properties'  => array(
+                                               'label' => array(
+                                                       'type'     => 'string',
+                                                       'readonly' => true,
+                                               ),
+                                               'color' => array(
+                                                       'type'     => 'string',
+                                                       'enum'     => array( 'blue', 'orange', 'red', 'green', 'purple', 'gray' ),
+                                                       'readonly' => true,
+                                               ),
+                                       ),
+                                       'readonly'    => true,
+                               ),
+                               'description' => array(
+                                       'type'        => 'string',
+                                       'description' => __( 'A more descriptive explanation of what the test looks for, and why it is important for the user.' ),
+                                       'readonly'    => true,
+                               ),
+                               'actions'     => array(
+                                       'type'        => 'string',
+                                       'description' => __( 'HTML containing an action to direct the user to where they can resolve the issue.' ),
+                                       'readonly'    => true,
+                               ),
+                       ),
+               );
+
+               return $this->schema;
+       }
+}
</ins><span class="cx" style="display: block; padding: 0 10px">Property changes on: trunk/src/wp-includes/rest-api/endpoints/class-wp-rest-site-health-controller.php
</span><span class="cx" style="display: block; padding: 0 10px">___________________________________________________________________
</span></span></pre></div>
<a id="svneolstyle"></a>
<div class="addfile"><h4 style="background-color: #eee; color: inherit; margin: 1em 0; padding: 1.3em; font-size: 115%">Added: svn:eol-style</h4></div>
<ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+native
</ins><span class="cx" style="display: block; padding: 0 10px">\ No newline at end of property
</span><a id="trunksrcwpincludesrestapiphp"></a>
<div class="modfile"><h4 style="background-color: #eee; color: inherit; margin: 1em 0; padding: 1.3em; font-size: 115%">Modified: trunk/src/wp-includes/rest-api.php</h4>
<pre class="diff"><span>
<span class="info" style="display: block; padding: 0 10px; color: #888">--- trunk/src/wp-includes/rest-api.php        2020-10-15 00:14:51 UTC (rev 49153)
+++ trunk/src/wp-includes/rest-api.php  2020-10-15 01:58:28 UTC (rev 49154)
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -316,6 +316,11 @@
</span><span class="cx" style="display: block; padding: 0 10px">        // Block Directory.
</span><span class="cx" style="display: block; padding: 0 10px">        $controller = new WP_REST_Block_Directory_Controller();
</span><span class="cx" style="display: block; padding: 0 10px">        $controller->register_routes();
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+
+       // Site Health
+       $site_health = WP_Site_Health::get_instance();
+       $controller = new WP_REST_Site_Health_Controller( $site_health );
+       $controller->register_routes();
</ins><span class="cx" style="display: block; padding: 0 10px"> }
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px"> /**
</span></span></pre></div>
<a id="trunksrcwpincludesscriptloaderphp"></a>
<div class="modfile"><h4 style="background-color: #eee; color: inherit; margin: 1em 0; padding: 1.3em; font-size: 115%">Modified: trunk/src/wp-includes/script-loader.php</h4>
<pre class="diff"><span>
<span class="info" style="display: block; padding: 0 10px; color: #888">--- trunk/src/wp-includes/script-loader.php   2020-10-15 00:14:51 UTC (rev 49153)
+++ trunk/src/wp-includes/script-loader.php     2020-10-15 01:58:28 UTC (rev 49154)
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -1286,7 +1286,7 @@
</span><span class="cx" style="display: block; padding: 0 10px">                $scripts->add( 'plugin-install', "/wp-admin/js/plugin-install$suffix.js", array( 'jquery', 'jquery-ui-core', 'thickbox' ), false, 1 );
</span><span class="cx" style="display: block; padding: 0 10px">                $scripts->set_translations( 'plugin-install' );
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-                $scripts->add( 'site-health', "/wp-admin/js/site-health$suffix.js", array( 'clipboard', 'jquery', 'wp-util', 'wp-a11y' ), false, 1 );
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+         $scripts->add( 'site-health', "/wp-admin/js/site-health$suffix.js", array( 'clipboard', 'jquery', 'wp-util', 'wp-a11y', 'wp-api-request' ), false, 1 );
</ins><span class="cx" style="display: block; padding: 0 10px">                 $scripts->set_translations( 'site-health' );
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">                $scripts->add( 'privacy-tools', "/wp-admin/js/privacy-tools$suffix.js", array( 'jquery', 'wp-a11y' ), false, 1 );
</span></span></pre></div>
<a id="trunksrcwpsettingsphp"></a>
<div class="modfile"><h4 style="background-color: #eee; color: inherit; margin: 1em 0; padding: 1.3em; font-size: 115%">Modified: trunk/src/wp-settings.php</h4>
<pre class="diff"><span>
<span class="info" style="display: block; padding: 0 10px; color: #888">--- trunk/src/wp-settings.php 2020-10-15 00:14:51 UTC (rev 49153)
+++ trunk/src/wp-settings.php   2020-10-15 01:58:28 UTC (rev 49154)
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -261,6 +261,7 @@
</span><span class="cx" style="display: block; padding: 0 10px"> require ABSPATH . WPINC . '/rest-api/endpoints/class-wp-rest-plugins-controller.php';
</span><span class="cx" style="display: block; padding: 0 10px"> require ABSPATH . WPINC . '/rest-api/endpoints/class-wp-rest-block-directory-controller.php';
</span><span class="cx" style="display: block; padding: 0 10px"> require ABSPATH . WPINC . '/rest-api/endpoints/class-wp-rest-application-passwords-controller.php';
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+require ABSPATH . WPINC . '/rest-api/endpoints/class-wp-rest-site-health-controller.php';
</ins><span class="cx" style="display: block; padding: 0 10px"> require ABSPATH . WPINC . '/rest-api/fields/class-wp-rest-meta-fields.php';
</span><span class="cx" style="display: block; padding: 0 10px"> require ABSPATH . WPINC . '/rest-api/fields/class-wp-rest-comment-meta-fields.php';
</span><span class="cx" style="display: block; padding: 0 10px"> require ABSPATH . WPINC . '/rest-api/fields/class-wp-rest-post-meta-fields.php';
</span></span></pre></div>
<a id="trunktestsphpunittestsrestapirestschemasetupphp"></a>
<div class="modfile"><h4 style="background-color: #eee; color: inherit; margin: 1em 0; padding: 1.3em; font-size: 115%">Modified: trunk/tests/phpunit/tests/rest-api/rest-schema-setup.php</h4>
<pre class="diff"><span>
<span class="info" style="display: block; padding: 0 10px; color: #888">--- trunk/tests/phpunit/tests/rest-api/rest-schema-setup.php  2020-10-15 00:14:51 UTC (rev 49153)
+++ trunk/tests/phpunit/tests/rest-api/rest-schema-setup.php    2020-10-15 01:58:28 UTC (rev 49154)
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -132,6 +132,11 @@
</span><span class="cx" style="display: block; padding: 0 10px">                        '/wp/v2/plugins',
</span><span class="cx" style="display: block; padding: 0 10px">                        '/wp/v2/plugins/(?P<plugin>[^.\/]+(?:\/[^.\/]+)?)',
</span><span class="cx" style="display: block; padding: 0 10px">                        '/wp/v2/block-directory/search',
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+                        '/wp-site-health/v1',
+                       '/wp-site-health/v1/tests/background-updates',
+                       '/wp-site-health/v1/tests/loopback-requests',
+                       '/wp-site-health/v1/tests/dotorg-communication',
+                       '/wp-site-health/v1/directory-sizes',
</ins><span class="cx" style="display: block; padding: 0 10px">                 );
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">                $this->assertSameSets( $expected_routes, $routes );
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -141,7 +146,8 @@
</span><span class="cx" style="display: block; padding: 0 10px">                return (
</span><span class="cx" style="display: block; padding: 0 10px">                        '/' === $route ||
</span><span class="cx" style="display: block; padding: 0 10px">                        preg_match( '#^/oembed/1\.0(/.+)?$#', $route ) ||
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-                        preg_match( '#^/wp/v2(/.+)?$#', $route )
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+                 preg_match( '#^/wp/v2(/.+)?$#', $route ) ||
+                       preg_match( '#^/wp-site-health/v1(/.+)?$#', $route )
</ins><span class="cx" style="display: block; padding: 0 10px">                 );
</span><span class="cx" style="display: block; padding: 0 10px">        }
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span></span></pre></div>
<a id="trunktestsphpunittestsrestapirestsitehealthcontrollerphp"></a>
<div class="addfile"><h4 style="background-color: #eee; color: inherit; margin: 1em 0; padding: 1.3em; font-size: 115%">Added: trunk/tests/phpunit/tests/rest-api/rest-site-health-controller.php</h4>
<pre class="diff"><span>
<span class="info" style="display: block; padding: 0 10px; color: #888">--- trunk/tests/phpunit/tests/rest-api/rest-site-health-controller.php                                (rev 0)
+++ trunk/tests/phpunit/tests/rest-api/rest-site-health-controller.php  2020-10-15 01:58:28 UTC (rev 49154)
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -0,0 +1,95 @@
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+<?php
+/**
+ * Unit tests covering the site health controller.
+ *
+ * Also generates the fixture data used by the wp-api.js QUnit tests.
+ *
+ * @package    WordPress
+ * @subpackage REST API
+ * @since      5.6.0
+ */
+
+/**
+ * @group restapi
+ */
+class WP_Test_REST_Site_Health_Controller extends WP_Test_REST_TestCase {
+
+       /**
+        * Subscriber user ID.
+        *
+        * @since 5.6.0
+        *
+        * @var int
+        */
+       private static $subscriber;
+
+       /**
+        * Administrator user id.
+        *
+        * @since 5.6.0
+        *
+        * @var int
+        */
+       private static $admin;
+
+       /**
+        * Set up class test fixtures.
+        *
+        * @since 5.6.0
+        *
+        * @param WP_UnitTest_Factory $factory WordPress unit test factory.
+        */
+       public static function wpSetUpBeforeClass( $factory ) {
+               self::$subscriber = $factory->user->create(
+                       array(
+                               'role' => 'subscriber',
+                       )
+               );
+               self::$admin      = $factory->user->create(
+                       array(
+                               'role' => 'administrator',
+                       )
+               );
+       }
+
+       /**
+        * Clean up test fixtures.
+        *
+        * @since 5.6.0
+        */
+       public static function wpTearDownAfterClass() {
+               self::delete_user( self::$subscriber );
+               self::delete_user( self::$admin );
+       }
+
+       public function test_logged_out() {
+               $response = rest_do_request( '/wp-site-health/v1/tests/dotorg-communication' );
+               $this->assertErrorResponse( 'rest_forbidden', $response, 401 );
+       }
+
+       public function test_insufficient_caps() {
+               wp_set_current_user( self::$subscriber );
+               $response = rest_do_request( '/wp-site-health/v1/tests/dotorg-communication' );
+               $this->assertErrorResponse( 'rest_forbidden', $response, 403 );
+       }
+
+       public function test_custom_capability() {
+               wp_set_current_user( self::$admin );
+
+               add_filter(
+                       'site_health_test_rest_capability_dotorg_communication',
+                       static function () {
+                               return 'a_custom_capability';
+                       }
+               );
+
+               $response = rest_do_request( '/wp-site-health/v1/tests/dotorg-communication' );
+               $this->assertErrorResponse( 'rest_forbidden', $response, 403 );
+       }
+
+       public function test() {
+               wp_set_current_user( self::$admin );
+               $response = rest_do_request( '/wp-site-health/v1/tests/dotorg-communication' );
+               $this->assertEquals( 'dotorg_communication', $response->get_data()['test'] );
+       }
+}
</ins><span class="cx" style="display: block; padding: 0 10px">Property changes on: trunk/tests/phpunit/tests/rest-api/rest-site-health-controller.php
</span><span class="cx" style="display: block; padding: 0 10px">___________________________________________________________________
</span></span></pre></div>
<a id="svneolstyle"></a>
<div class="addfile"><h4 style="background-color: #eee; color: inherit; margin: 1em 0; padding: 1.3em; font-size: 115%">Added: svn:eol-style</h4></div>
<ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+native
</ins><span class="cx" style="display: block; padding: 0 10px">\ No newline at end of property
</span><a id="trunktestsqunitfixtureswpapigeneratedjs"></a>
<div class="modfile"><h4 style="background-color: #eee; color: inherit; margin: 1em 0; padding: 1.3em; font-size: 115%">Modified: trunk/tests/qunit/fixtures/wp-api-generated.js</h4>
<pre class="diff"><span>
<span class="info" style="display: block; padding: 0 10px; color: #888">--- trunk/tests/qunit/fixtures/wp-api-generated.js    2020-10-15 00:14:51 UTC (rev 49153)
+++ trunk/tests/qunit/fixtures/wp-api-generated.js      2020-10-15 01:58:28 UTC (rev 49154)
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -14,7 +14,8 @@
</span><span class="cx" style="display: block; padding: 0 10px">     "timezone_string": "",
</span><span class="cx" style="display: block; padding: 0 10px">     "namespaces": [
</span><span class="cx" style="display: block; padding: 0 10px">         "oembed/1.0",
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        "wp/v2"
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+        "wp/v2",
+        "wp-site-health/v1"
</ins><span class="cx" style="display: block; padding: 0 10px">     ],
</span><span class="cx" style="display: block; padding: 0 10px">     "authentication": [],
</span><span class="cx" style="display: block; padding: 0 10px">     "routes": {
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -5058,6 +5059,120 @@
</span><span class="cx" style="display: block; padding: 0 10px">                     }
</span><span class="cx" style="display: block; padding: 0 10px">                 ]
</span><span class="cx" style="display: block; padding: 0 10px">             }
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+        },
+        "/wp-site-health/v1": {
+            "namespace": "wp-site-health/v1",
+            "methods": [
+                "GET"
+            ],
+            "endpoints": [
+                {
+                    "methods": [
+                        "GET"
+                    ],
+                    "args": {
+                        "namespace": {
+                            "required": false,
+                            "default": "wp-site-health/v1"
+                        },
+                        "context": {
+                            "required": false,
+                            "default": "view"
+                        }
+                    }
+                }
+            ],
+            "_links": {
+                "self": [
+                    {
+                        "href": "http://example.org/index.php?rest_route=/wp-site-health/v1"
+                    }
+                ]
+            }
+        },
+        "/wp-site-health/v1/tests/background-updates": {
+            "namespace": "wp-site-health/v1",
+            "methods": [
+                "GET"
+            ],
+            "endpoints": [
+                {
+                    "methods": [
+                        "GET"
+                    ],
+                    "args": []
+                }
+            ],
+            "_links": {
+                "self": [
+                    {
+                        "href": "http://example.org/index.php?rest_route=/wp-site-health/v1/tests/background-updates"
+                    }
+                ]
+            }
+        },
+        "/wp-site-health/v1/tests/loopback-requests": {
+            "namespace": "wp-site-health/v1",
+            "methods": [
+                "GET"
+            ],
+            "endpoints": [
+                {
+                    "methods": [
+                        "GET"
+                    ],
+                    "args": []
+                }
+            ],
+            "_links": {
+                "self": [
+                    {
+                        "href": "http://example.org/index.php?rest_route=/wp-site-health/v1/tests/loopback-requests"
+                    }
+                ]
+            }
+        },
+        "/wp-site-health/v1/tests/dotorg-communication": {
+            "namespace": "wp-site-health/v1",
+            "methods": [
+                "GET"
+            ],
+            "endpoints": [
+                {
+                    "methods": [
+                        "GET"
+                    ],
+                    "args": []
+                }
+            ],
+            "_links": {
+                "self": [
+                    {
+                        "href": "http://example.org/index.php?rest_route=/wp-site-health/v1/tests/dotorg-communication"
+                    }
+                ]
+            }
+        },
+        "/wp-site-health/v1/directory-sizes": {
+            "namespace": "wp-site-health/v1",
+            "methods": [
+                "GET"
+            ],
+            "endpoints": [
+                {
+                    "methods": [
+                        "GET"
+                    ],
+                    "args": []
+                }
+            ],
+            "_links": {
+                "self": [
+                    {
+                        "href": "http://example.org/index.php?rest_route=/wp-site-health/v1/directory-sizes"
+                    }
+                ]
+            }
</ins><span class="cx" style="display: block; padding: 0 10px">         }
</span><span class="cx" style="display: block; padding: 0 10px">     }
</span><span class="cx" style="display: block; padding: 0 10px"> };
</span></span></pre>
</div>
</div>

</body>
</html>