diff -r 34716fd837a4 -r be944660c56a wp/wp-admin/js/site-health.js --- a/wp/wp-admin/js/site-health.js Tue Dec 15 15:52:01 2020 +0100 +++ b/wp/wp-admin/js/site-health.js Wed Sep 21 18:19:35 2022 +0200 @@ -6,13 +6,13 @@ /* global ajaxurl, ClipboardJS, SiteHealth, wp */ -jQuery( document ).ready( function( $ ) { +jQuery( function( $ ) { var __ = wp.i18n.__, _n = wp.i18n._n, sprintf = wp.i18n.sprintf, - data, clipboard = new ClipboardJS( '.site-health-copy-buttons .copy-button' ), + isStatusTab = $( '.health-check-body.health-check-status-tab' ).length, isDebugTab = $( '.health-check-body.health-check-debug-tab' ).length, pathsSizesSection = $( '#health-check-accordion-block-wp-paths-sizes' ), successTimeout; @@ -25,7 +25,7 @@ // Clear the selection and move focus back to the trigger. e.clearSelection(); // Handle ClipboardJS focus bug, see https://github.com/zenorocha/clipboard.js/issues/680 - triggerElement.focus(); + triggerElement.trigger( 'focus' ); // Show success visual feedback. clearTimeout( successTimeout ); @@ -67,6 +67,57 @@ } ); /** + * Validates the Site Health test result format. + * + * @since 5.6.0 + * + * @param {Object} issue + * + * @return {boolean} + */ + function validateIssueData( issue ) { + // Expected minimum format of a valid SiteHealth test response. + var minimumExpected = { + test: 'string', + label: 'string', + description: 'string' + }, + passed = true, + key, value, subKey, subValue; + + // If the issue passed is not an object, return a `false` state early. + if ( 'object' !== typeof( issue ) ) { + return false; + } + + // Loop over expected data and match the data types. + for ( key in minimumExpected ) { + value = minimumExpected[ key ]; + + if ( 'object' === typeof( value ) ) { + for ( subKey in value ) { + subValue = value[ subKey ]; + + if ( 'undefined' === typeof( issue[ key ] ) || + 'undefined' === typeof( issue[ key ][ subKey ] ) || + subValue !== typeof( issue[ key ][ subKey ] ) + ) { + passed = false; + } + } + } else { + if ( 'undefined' === typeof( issue[ key ] ) || + value !== typeof( issue[ key ] ) + ) { + passed = false; + } + } + } + + return passed; + } + + /** * Appends a new issue to the issue list. * * @since 5.2.0 @@ -78,11 +129,24 @@ issueWrapper = $( '#health-check-issues-' + issue.status ), heading, count; - + + /* + * Validate the issue data format before using it. + * If the output is invalid, discard it. + */ + if ( ! validateIssueData( issue ) ) { + return false; + } + SiteHealth.site_status.issues[ issue.status ]++; count = SiteHealth.site_status.issues[ issue.status ]; + // If no test name is supplied, append a placeholder for markup references. + if ( typeof issue.test === 'undefined' ) { + issue.test = issue.status + count; + } + if ( 'critical' === issue.status ) { heading = sprintf( _n( '%s critical issue', '%s critical issues', count ), @@ -119,10 +183,10 @@ var $progressLabel = $( '.site-health-progress-label', $wrapper ); var $circle = $( '.site-health-progress svg #bar' ); var totalTests = parseInt( SiteHealth.site_status.issues.good, 0 ) + - parseInt( SiteHealth.site_status.issues.recommended, 0 ) + - ( parseInt( SiteHealth.site_status.issues.critical, 0 ) * 1.5 ); + parseInt( SiteHealth.site_status.issues.recommended, 0 ) + + ( parseInt( SiteHealth.site_status.issues.critical, 0 ) * 1.5 ); var failedTests = ( parseInt( SiteHealth.site_status.issues.recommended, 0 ) * 0.5 ) + - ( parseInt( SiteHealth.site_status.issues.critical, 0 ) * 1.5 ); + ( parseInt( SiteHealth.site_status.issues.critical, 0 ) * 1.5 ); var val = 100 - Math.ceil( ( failedTests / totalTests ) * 100 ); if ( 0 === totalTests ) { @@ -142,7 +206,7 @@ val = 100; } - pct = ( ( 100 - val ) / 100 ) * c; + pct = ( ( 100 - val ) / 100 ) * c + 'px'; $circle.css( { strokeDashoffset: pct } ); @@ -166,7 +230,7 @@ wp.a11y.speak( __( 'All site health tests have finished running. There are items that should be addressed, and the results are now available on the page.' ) ); } - if ( ! isDebugTab ) { + if ( isStatusTab ) { $.post( ajaxurl, { @@ -206,15 +270,50 @@ this.completed = true; - $.post( - ajaxurl, - data, - function( response ) { + if ( 'undefined' !== typeof( this.has_rest ) && this.has_rest ) { + wp.apiRequest( { + url: wp.url.addQueryArgs( this.test, { _locale: 'user' } ), + headers: this.headers + } ) + .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 ) { /** This filter is documented in wp-admin/includes/class-wp-site-health.php */ appendIssue( wp.hooks.applyFilters( 'site_status_test_result', response.data ) ); + } ).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(); - } - ); + } ); + } return false; } ); @@ -225,7 +324,30 @@ } } - if ( 'undefined' !== typeof SiteHealth && ! isDebugTab ) { + /** + * 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': '
' + url + '
' + description + '
', + 'actions': '' + }; + + /** This filter is documented in wp-admin/includes/class-wp-site-health.php */ + appendIssue( wp.hooks.applyFilters( 'site_status_test_result', issue ) ); + } + + if ( 'undefined' !== typeof SiteHealth ) { if ( 0 === SiteHealth.site_status.direct.length && 0 === SiteHealth.site_status.async.length ) { recalculateProgression(); } else { @@ -243,32 +365,13 @@ } if ( 0 < SiteHealth.site_status.async.length ) { - 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(); - } - ); + maybeRunNextAsyncTest(); } else { recalculateProgression(); } } function getDirectorySizes() { - var data = { - action: 'health-check-get-sizes', - _wpnonce: SiteHealth.nonce.site_status_result - }; - var timestamp = ( new Date().getTime() ); // After 3 seconds announce that we're still waiting for directory sizes. @@ -276,20 +379,17 @@ wp.a11y.speak( __( 'Please wait...' ) ); }, 3000 ); - $.post( { - type: 'POST', - url: ajaxurl, - data: data, - dataType: 'json' + wp.apiRequest( { + path: '/wp-site-health/v1/directory-sizes' } ).done( function( response ) { - updateDirSizes( response.data || {} ); + updateDirSizes( response || {} ); } ).always( function() { var delay = ( new Date().getTime() ) - timestamp; $( '.health-check-wp-paths-sizes.spinner' ).css( 'visibility', 'hidden' ); recalculateProgression(); - if ( delay > 3000 ) { + if ( delay > 3000 ) { /* * We have announced that we're waiting. * Announce that we're ready after giving at least 3 seconds @@ -344,4 +444,9 @@ recalculateProgression(); } } + + // Trigger a class toggle when the extended menu button is clicked. + $( '.health-check-offscreen-nav-wrapper' ).on( 'click', function() { + $( this ).toggleClass( 'visible' ); + } ); } );