Edit File by line
/home/barbar84/public_h.../wp-admin/js
File: site-health.js
/**
[0] Fix | Delete
* Interactions used by the Site Health modules in WordPress.
[1] Fix | Delete
*
[2] Fix | Delete
* @output wp-admin/js/site-health.js
[3] Fix | Delete
*/
[4] Fix | Delete
[5] Fix | Delete
/* global ajaxurl, ClipboardJS, SiteHealth, wp */
[6] Fix | Delete
[7] Fix | Delete
jQuery( document ).ready( function( $ ) {
[8] Fix | Delete
[9] Fix | Delete
var __ = wp.i18n.__,
[10] Fix | Delete
_n = wp.i18n._n,
[11] Fix | Delete
sprintf = wp.i18n.sprintf,
[12] Fix | Delete
clipboard = new ClipboardJS( '.site-health-copy-buttons .copy-button' ),
[13] Fix | Delete
isDebugTab = $( '.health-check-body.health-check-debug-tab' ).length,
[14] Fix | Delete
pathsSizesSection = $( '#health-check-accordion-block-wp-paths-sizes' ),
[15] Fix | Delete
successTimeout;
[16] Fix | Delete
[17] Fix | Delete
// Debug information copy section.
[18] Fix | Delete
clipboard.on( 'success', function( e ) {
[19] Fix | Delete
var triggerElement = $( e.trigger ),
[20] Fix | Delete
successElement = $( '.success', triggerElement.closest( 'div' ) );
[21] Fix | Delete
[22] Fix | Delete
// Clear the selection and move focus back to the trigger.
[23] Fix | Delete
e.clearSelection();
[24] Fix | Delete
// Handle ClipboardJS focus bug, see https://github.com/zenorocha/clipboard.js/issues/680
[25] Fix | Delete
triggerElement.trigger( 'focus' );
[26] Fix | Delete
[27] Fix | Delete
// Show success visual feedback.
[28] Fix | Delete
clearTimeout( successTimeout );
[29] Fix | Delete
successElement.removeClass( 'hidden' );
[30] Fix | Delete
[31] Fix | Delete
// Hide success visual feedback after 3 seconds since last success.
[32] Fix | Delete
successTimeout = setTimeout( function() {
[33] Fix | Delete
successElement.addClass( 'hidden' );
[34] Fix | Delete
// Remove the visually hidden textarea so that it isn't perceived by assistive technologies.
[35] Fix | Delete
if ( clipboard.clipboardAction.fakeElem && clipboard.clipboardAction.removeFake ) {
[36] Fix | Delete
clipboard.clipboardAction.removeFake();
[37] Fix | Delete
}
[38] Fix | Delete
}, 3000 );
[39] Fix | Delete
[40] Fix | Delete
// Handle success audible feedback.
[41] Fix | Delete
wp.a11y.speak( __( 'Site information has been copied to your clipboard.' ) );
[42] Fix | Delete
} );
[43] Fix | Delete
[44] Fix | Delete
// Accordion handling in various areas.
[45] Fix | Delete
$( '.health-check-accordion' ).on( 'click', '.health-check-accordion-trigger', function() {
[46] Fix | Delete
var isExpanded = ( 'true' === $( this ).attr( 'aria-expanded' ) );
[47] Fix | Delete
[48] Fix | Delete
if ( isExpanded ) {
[49] Fix | Delete
$( this ).attr( 'aria-expanded', 'false' );
[50] Fix | Delete
$( '#' + $( this ).attr( 'aria-controls' ) ).attr( 'hidden', true );
[51] Fix | Delete
} else {
[52] Fix | Delete
$( this ).attr( 'aria-expanded', 'true' );
[53] Fix | Delete
$( '#' + $( this ).attr( 'aria-controls' ) ).attr( 'hidden', false );
[54] Fix | Delete
}
[55] Fix | Delete
} );
[56] Fix | Delete
[57] Fix | Delete
// Site Health test handling.
[58] Fix | Delete
[59] Fix | Delete
$( '.site-health-view-passed' ).on( 'click', function() {
[60] Fix | Delete
var goodIssuesWrapper = $( '#health-check-issues-good' );
[61] Fix | Delete
[62] Fix | Delete
goodIssuesWrapper.toggleClass( 'hidden' );
[63] Fix | Delete
$( this ).attr( 'aria-expanded', ! goodIssuesWrapper.hasClass( 'hidden' ) );
[64] Fix | Delete
} );
[65] Fix | Delete
[66] Fix | Delete
/**
[67] Fix | Delete
* Validates the Site Health test result format.
[68] Fix | Delete
*
[69] Fix | Delete
* @since 5.6.0
[70] Fix | Delete
*
[71] Fix | Delete
* @param {Object} issue
[72] Fix | Delete
*
[73] Fix | Delete
* @return {boolean}
[74] Fix | Delete
*/
[75] Fix | Delete
function validateIssueData( issue ) {
[76] Fix | Delete
// Expected minimum format of a valid SiteHealth test response.
[77] Fix | Delete
var minimumExpected = {
[78] Fix | Delete
test: 'string',
[79] Fix | Delete
label: 'string',
[80] Fix | Delete
description: 'string'
[81] Fix | Delete
},
[82] Fix | Delete
passed = true,
[83] Fix | Delete
key, value, subKey, subValue;
[84] Fix | Delete
[85] Fix | Delete
// If the issue passed is not an object, return a `false` state early.
[86] Fix | Delete
if ( 'object' !== typeof( issue ) ) {
[87] Fix | Delete
return false;
[88] Fix | Delete
}
[89] Fix | Delete
[90] Fix | Delete
// Loop over expected data and match the data types.
[91] Fix | Delete
for ( key in minimumExpected ) {
[92] Fix | Delete
value = minimumExpected[ key ];
[93] Fix | Delete
[94] Fix | Delete
if ( 'object' === typeof( value ) ) {
[95] Fix | Delete
for ( subKey in value ) {
[96] Fix | Delete
subValue = value[ subKey ];
[97] Fix | Delete
[98] Fix | Delete
if ( 'undefined' === typeof( issue[ key ] ) ||
[99] Fix | Delete
'undefined' === typeof( issue[ key ][ subKey ] ) ||
[100] Fix | Delete
subValue !== typeof( issue[ key ][ subKey ] )
[101] Fix | Delete
) {
[102] Fix | Delete
passed = false;
[103] Fix | Delete
}
[104] Fix | Delete
}
[105] Fix | Delete
} else {
[106] Fix | Delete
if ( 'undefined' === typeof( issue[ key ] ) ||
[107] Fix | Delete
value !== typeof( issue[ key ] )
[108] Fix | Delete
) {
[109] Fix | Delete
passed = false;
[110] Fix | Delete
}
[111] Fix | Delete
}
[112] Fix | Delete
}
[113] Fix | Delete
[114] Fix | Delete
return passed;
[115] Fix | Delete
}
[116] Fix | Delete
[117] Fix | Delete
/**
[118] Fix | Delete
* Appends a new issue to the issue list.
[119] Fix | Delete
*
[120] Fix | Delete
* @since 5.2.0
[121] Fix | Delete
*
[122] Fix | Delete
* @param {Object} issue The issue data.
[123] Fix | Delete
*/
[124] Fix | Delete
function appendIssue( issue ) {
[125] Fix | Delete
var template = wp.template( 'health-check-issue' ),
[126] Fix | Delete
issueWrapper = $( '#health-check-issues-' + issue.status ),
[127] Fix | Delete
heading,
[128] Fix | Delete
count;
[129] Fix | Delete
[130] Fix | Delete
/*
[131] Fix | Delete
* Validate the issue data format before using it.
[132] Fix | Delete
* If the output is invalid, discard it.
[133] Fix | Delete
*/
[134] Fix | Delete
if ( ! validateIssueData( issue ) ) {
[135] Fix | Delete
return false;
[136] Fix | Delete
}
[137] Fix | Delete
[138] Fix | Delete
SiteHealth.site_status.issues[ issue.status ]++;
[139] Fix | Delete
[140] Fix | Delete
count = SiteHealth.site_status.issues[ issue.status ];
[141] Fix | Delete
[142] Fix | Delete
// If no test name is supplied, append a placeholder for markup references.
[143] Fix | Delete
if ( typeof issue.test === 'undefined' ) {
[144] Fix | Delete
issue.test = issue.status + count;
[145] Fix | Delete
}
[146] Fix | Delete
[147] Fix | Delete
if ( 'critical' === issue.status ) {
[148] Fix | Delete
heading = sprintf(
[149] Fix | Delete
_n( '%s critical issue', '%s critical issues', count ),
[150] Fix | Delete
'<span class="issue-count">' + count + '</span>'
[151] Fix | Delete
);
[152] Fix | Delete
} else if ( 'recommended' === issue.status ) {
[153] Fix | Delete
heading = sprintf(
[154] Fix | Delete
_n( '%s recommended improvement', '%s recommended improvements', count ),
[155] Fix | Delete
'<span class="issue-count">' + count + '</span>'
[156] Fix | Delete
);
[157] Fix | Delete
} else if ( 'good' === issue.status ) {
[158] Fix | Delete
heading = sprintf(
[159] Fix | Delete
_n( '%s item with no issues detected', '%s items with no issues detected', count ),
[160] Fix | Delete
'<span class="issue-count">' + count + '</span>'
[161] Fix | Delete
);
[162] Fix | Delete
}
[163] Fix | Delete
[164] Fix | Delete
if ( heading ) {
[165] Fix | Delete
$( '.site-health-issue-count-title', issueWrapper ).html( heading );
[166] Fix | Delete
}
[167] Fix | Delete
[168] Fix | Delete
$( '.issues', '#health-check-issues-' + issue.status ).append( template( issue ) );
[169] Fix | Delete
}
[170] Fix | Delete
[171] Fix | Delete
/**
[172] Fix | Delete
* Updates site health status indicator as asynchronous tests are run and returned.
[173] Fix | Delete
*
[174] Fix | Delete
* @since 5.2.0
[175] Fix | Delete
*/
[176] Fix | Delete
function recalculateProgression() {
[177] Fix | Delete
var r, c, pct;
[178] Fix | Delete
var $progress = $( '.site-health-progress' );
[179] Fix | Delete
var $wrapper = $progress.closest( '.site-health-progress-wrapper' );
[180] Fix | Delete
var $progressLabel = $( '.site-health-progress-label', $wrapper );
[181] Fix | Delete
var $circle = $( '.site-health-progress svg #bar' );
[182] Fix | Delete
var totalTests = parseInt( SiteHealth.site_status.issues.good, 0 ) +
[183] Fix | Delete
parseInt( SiteHealth.site_status.issues.recommended, 0 ) +
[184] Fix | Delete
( parseInt( SiteHealth.site_status.issues.critical, 0 ) * 1.5 );
[185] Fix | Delete
var failedTests = ( parseInt( SiteHealth.site_status.issues.recommended, 0 ) * 0.5 ) +
[186] Fix | Delete
( parseInt( SiteHealth.site_status.issues.critical, 0 ) * 1.5 );
[187] Fix | Delete
var val = 100 - Math.ceil( ( failedTests / totalTests ) * 100 );
[188] Fix | Delete
[189] Fix | Delete
if ( 0 === totalTests ) {
[190] Fix | Delete
$progress.addClass( 'hidden' );
[191] Fix | Delete
return;
[192] Fix | Delete
}
[193] Fix | Delete
[194] Fix | Delete
$wrapper.removeClass( 'loading' );
[195] Fix | Delete
[196] Fix | Delete
r = $circle.attr( 'r' );
[197] Fix | Delete
c = Math.PI * ( r * 2 );
[198] Fix | Delete
[199] Fix | Delete
if ( 0 > val ) {
[200] Fix | Delete
val = 0;
[201] Fix | Delete
}
[202] Fix | Delete
if ( 100 < val ) {
[203] Fix | Delete
val = 100;
[204] Fix | Delete
}
[205] Fix | Delete
[206] Fix | Delete
pct = ( ( 100 - val ) / 100 ) * c + 'px';
[207] Fix | Delete
[208] Fix | Delete
$circle.css( { strokeDashoffset: pct } );
[209] Fix | Delete
[210] Fix | Delete
if ( 1 > parseInt( SiteHealth.site_status.issues.critical, 0 ) ) {
[211] Fix | Delete
$( '#health-check-issues-critical' ).addClass( 'hidden' );
[212] Fix | Delete
}
[213] Fix | Delete
[214] Fix | Delete
if ( 1 > parseInt( SiteHealth.site_status.issues.recommended, 0 ) ) {
[215] Fix | Delete
$( '#health-check-issues-recommended' ).addClass( 'hidden' );
[216] Fix | Delete
}
[217] Fix | Delete
[218] Fix | Delete
if ( 80 <= val && 0 === parseInt( SiteHealth.site_status.issues.critical, 0 ) ) {
[219] Fix | Delete
$wrapper.addClass( 'green' ).removeClass( 'orange' );
[220] Fix | Delete
[221] Fix | Delete
$progressLabel.text( __( 'Good' ) );
[222] Fix | Delete
wp.a11y.speak( __( 'All site health tests have finished running. Your site is looking good, and the results are now available on the page.' ) );
[223] Fix | Delete
} else {
[224] Fix | Delete
$wrapper.addClass( 'orange' ).removeClass( 'green' );
[225] Fix | Delete
[226] Fix | Delete
$progressLabel.text( __( 'Should be improved' ) );
[227] Fix | Delete
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.' ) );
[228] Fix | Delete
}
[229] Fix | Delete
[230] Fix | Delete
if ( ! isDebugTab ) {
[231] Fix | Delete
$.post(
[232] Fix | Delete
ajaxurl,
[233] Fix | Delete
{
[234] Fix | Delete
'action': 'health-check-site-status-result',
[235] Fix | Delete
'_wpnonce': SiteHealth.nonce.site_status_result,
[236] Fix | Delete
'counts': SiteHealth.site_status.issues
[237] Fix | Delete
}
[238] Fix | Delete
);
[239] Fix | Delete
[240] Fix | Delete
if ( 100 === val ) {
[241] Fix | Delete
$( '.site-status-all-clear' ).removeClass( 'hide' );
[242] Fix | Delete
$( '.site-status-has-issues' ).addClass( 'hide' );
[243] Fix | Delete
}
[244] Fix | Delete
}
[245] Fix | Delete
}
[246] Fix | Delete
[247] Fix | Delete
/**
[248] Fix | Delete
* Queues the next asynchronous test when we're ready to run it.
[249] Fix | Delete
*
[250] Fix | Delete
* @since 5.2.0
[251] Fix | Delete
*/
[252] Fix | Delete
function maybeRunNextAsyncTest() {
[253] Fix | Delete
var doCalculation = true;
[254] Fix | Delete
[255] Fix | Delete
if ( 1 <= SiteHealth.site_status.async.length ) {
[256] Fix | Delete
$.each( SiteHealth.site_status.async, function() {
[257] Fix | Delete
var data = {
[258] Fix | Delete
'action': 'health-check-' + this.test.replace( '_', '-' ),
[259] Fix | Delete
'_wpnonce': SiteHealth.nonce.site_status
[260] Fix | Delete
};
[261] Fix | Delete
[262] Fix | Delete
if ( this.completed ) {
[263] Fix | Delete
return true;
[264] Fix | Delete
}
[265] Fix | Delete
[266] Fix | Delete
doCalculation = false;
[267] Fix | Delete
[268] Fix | Delete
this.completed = true;
[269] Fix | Delete
[270] Fix | Delete
if ( 'undefined' !== typeof( this.has_rest ) && this.has_rest ) {
[271] Fix | Delete
wp.apiRequest( {
[272] Fix | Delete
url: wp.url.addQueryArgs( this.test, { _locale: 'user' } ),
[273] Fix | Delete
headers: this.headers
[274] Fix | Delete
} )
[275] Fix | Delete
.done( function( response ) {
[276] Fix | Delete
/** This filter is documented in wp-admin/includes/class-wp-site-health.php */
[277] Fix | Delete
appendIssue( wp.hooks.applyFilters( 'site_status_test_result', response ) );
[278] Fix | Delete
} )
[279] Fix | Delete
.fail( function( response ) {
[280] Fix | Delete
var description;
[281] Fix | Delete
[282] Fix | Delete
if ( 'undefined' !== typeof( response.responseJSON ) && 'undefined' !== typeof( response.responseJSON.message ) ) {
[283] Fix | Delete
description = response.responseJSON.message;
[284] Fix | Delete
} else {
[285] Fix | Delete
description = __( 'No details available' );
[286] Fix | Delete
}
[287] Fix | Delete
[288] Fix | Delete
addFailedSiteHealthCheckNotice( this.url, description );
[289] Fix | Delete
} )
[290] Fix | Delete
.always( function() {
[291] Fix | Delete
maybeRunNextAsyncTest();
[292] Fix | Delete
} );
[293] Fix | Delete
} else {
[294] Fix | Delete
$.post(
[295] Fix | Delete
ajaxurl,
[296] Fix | Delete
data
[297] Fix | Delete
).done( function( response ) {
[298] Fix | Delete
/** This filter is documented in wp-admin/includes/class-wp-site-health.php */
[299] Fix | Delete
appendIssue( wp.hooks.applyFilters( 'site_status_test_result', response.data ) );
[300] Fix | Delete
} ).fail( function( response ) {
[301] Fix | Delete
var description;
[302] Fix | Delete
[303] Fix | Delete
if ( 'undefined' !== typeof( response.responseJSON ) && 'undefined' !== typeof( response.responseJSON.message ) ) {
[304] Fix | Delete
description = response.responseJSON.message;
[305] Fix | Delete
} else {
[306] Fix | Delete
description = __( 'No details available' );
[307] Fix | Delete
}
[308] Fix | Delete
[309] Fix | Delete
addFailedSiteHealthCheckNotice( this.url, description );
[310] Fix | Delete
} ).always( function() {
[311] Fix | Delete
maybeRunNextAsyncTest();
[312] Fix | Delete
} );
[313] Fix | Delete
}
[314] Fix | Delete
[315] Fix | Delete
return false;
[316] Fix | Delete
} );
[317] Fix | Delete
}
[318] Fix | Delete
[319] Fix | Delete
if ( doCalculation ) {
[320] Fix | Delete
recalculateProgression();
[321] Fix | Delete
}
[322] Fix | Delete
}
[323] Fix | Delete
[324] Fix | Delete
/**
[325] Fix | Delete
* Add the details of a failed asynchronous test to the list of test results.
[326] Fix | Delete
*
[327] Fix | Delete
* @since 5.6.0
[328] Fix | Delete
*/
[329] Fix | Delete
function addFailedSiteHealthCheckNotice( url, description ) {
[330] Fix | Delete
var issue;
[331] Fix | Delete
[332] Fix | Delete
issue = {
[333] Fix | Delete
'status': 'recommended',
[334] Fix | Delete
'label': __( 'A test is unavailable' ),
[335] Fix | Delete
'badge': {
[336] Fix | Delete
'color': 'red',
[337] Fix | Delete
'label': __( 'Unavailable' )
[338] Fix | Delete
},
[339] Fix | Delete
'description': '<p>' + url + '</p><p>' + description + '</p>',
[340] Fix | Delete
'actions': ''
[341] Fix | Delete
};
[342] Fix | Delete
[343] Fix | Delete
/** This filter is documented in wp-admin/includes/class-wp-site-health.php */
[344] Fix | Delete
appendIssue( wp.hooks.applyFilters( 'site_status_test_result', issue ) );
[345] Fix | Delete
}
[346] Fix | Delete
[347] Fix | Delete
if ( 'undefined' !== typeof SiteHealth && ! isDebugTab ) {
[348] Fix | Delete
if ( 0 === SiteHealth.site_status.direct.length && 0 === SiteHealth.site_status.async.length ) {
[349] Fix | Delete
recalculateProgression();
[350] Fix | Delete
} else {
[351] Fix | Delete
SiteHealth.site_status.issues = {
[352] Fix | Delete
'good': 0,
[353] Fix | Delete
'recommended': 0,
[354] Fix | Delete
'critical': 0
[355] Fix | Delete
};
[356] Fix | Delete
}
[357] Fix | Delete
[358] Fix | Delete
if ( 0 < SiteHealth.site_status.direct.length ) {
[359] Fix | Delete
$.each( SiteHealth.site_status.direct, function() {
[360] Fix | Delete
appendIssue( this );
[361] Fix | Delete
} );
[362] Fix | Delete
}
[363] Fix | Delete
[364] Fix | Delete
if ( 0 < SiteHealth.site_status.async.length ) {
[365] Fix | Delete
maybeRunNextAsyncTest();
[366] Fix | Delete
} else {
[367] Fix | Delete
recalculateProgression();
[368] Fix | Delete
}
[369] Fix | Delete
}
[370] Fix | Delete
[371] Fix | Delete
function getDirectorySizes() {
[372] Fix | Delete
var timestamp = ( new Date().getTime() );
[373] Fix | Delete
[374] Fix | Delete
// After 3 seconds announce that we're still waiting for directory sizes.
[375] Fix | Delete
var timeout = window.setTimeout( function() {
[376] Fix | Delete
wp.a11y.speak( __( 'Please wait...' ) );
[377] Fix | Delete
}, 3000 );
[378] Fix | Delete
[379] Fix | Delete
wp.apiRequest( {
[380] Fix | Delete
path: '/wp-site-health/v1/directory-sizes'
[381] Fix | Delete
} ).done( function( response ) {
[382] Fix | Delete
updateDirSizes( response || {} );
[383] Fix | Delete
} ).always( function() {
[384] Fix | Delete
var delay = ( new Date().getTime() ) - timestamp;
[385] Fix | Delete
[386] Fix | Delete
$( '.health-check-wp-paths-sizes.spinner' ).css( 'visibility', 'hidden' );
[387] Fix | Delete
recalculateProgression();
[388] Fix | Delete
[389] Fix | Delete
if ( delay > 3000 ) {
[390] Fix | Delete
/*
[391] Fix | Delete
* We have announced that we're waiting.
[392] Fix | Delete
* Announce that we're ready after giving at least 3 seconds
[393] Fix | Delete
* for the first announcement to be read out, or the two may collide.
[394] Fix | Delete
*/
[395] Fix | Delete
if ( delay > 6000 ) {
[396] Fix | Delete
delay = 0;
[397] Fix | Delete
} else {
[398] Fix | Delete
delay = 6500 - delay;
[399] Fix | Delete
}
[400] Fix | Delete
[401] Fix | Delete
window.setTimeout( function() {
[402] Fix | Delete
wp.a11y.speak( __( 'All site health tests have finished running.' ) );
[403] Fix | Delete
}, delay );
[404] Fix | Delete
} else {
[405] Fix | Delete
// Cancel the announcement.
[406] Fix | Delete
window.clearTimeout( timeout );
[407] Fix | Delete
}
[408] Fix | Delete
[409] Fix | Delete
$( document ).trigger( 'site-health-info-dirsizes-done' );
[410] Fix | Delete
} );
[411] Fix | Delete
}
[412] Fix | Delete
[413] Fix | Delete
function updateDirSizes( data ) {
[414] Fix | Delete
var copyButton = $( 'button.button.copy-button' );
[415] Fix | Delete
var clipboardText = copyButton.attr( 'data-clipboard-text' );
[416] Fix | Delete
[417] Fix | Delete
$.each( data, function( name, value ) {
[418] Fix | Delete
var text = value.debug || value.size;
[419] Fix | Delete
[420] Fix | Delete
if ( typeof text !== 'undefined' ) {
[421] Fix | Delete
clipboardText = clipboardText.replace( name + ': loading...', name + ': ' + text );
[422] Fix | Delete
}
[423] Fix | Delete
} );
[424] Fix | Delete
[425] Fix | Delete
copyButton.attr( 'data-clipboard-text', clipboardText );
[426] Fix | Delete
[427] Fix | Delete
pathsSizesSection.find( 'td[class]' ).each( function( i, element ) {
[428] Fix | Delete
var td = $( element );
[429] Fix | Delete
var name = td.attr( 'class' );
[430] Fix | Delete
[431] Fix | Delete
if ( data.hasOwnProperty( name ) && data[ name ].size ) {
[432] Fix | Delete
td.text( data[ name ].size );
[433] Fix | Delete
}
[434] Fix | Delete
} );
[435] Fix | Delete
}
[436] Fix | Delete
[437] Fix | Delete
if ( isDebugTab ) {
[438] Fix | Delete
if ( pathsSizesSection.length ) {
[439] Fix | Delete
getDirectorySizes();
[440] Fix | Delete
} else {
[441] Fix | Delete
recalculateProgression();
[442] Fix | Delete
}
[443] Fix | Delete
}
[444] Fix | Delete
} );
[445] Fix | Delete
[446] Fix | Delete
It is recommended that you Edit text format, this type of Fix handles quite a lot in one request
Function