diff --git a/assets/js/plugin-check-admin.js b/assets/js/plugin-check-admin.js index e75220958..a12a92ca3 100644 --- a/assets/js/plugin-check-admin.js +++ b/assets/js/plugin-check-admin.js @@ -756,6 +756,7 @@ ) { let isSuccessMessage = true; let aiStats = null; + const failedChecks = []; for ( let i = 0; i < checks.length; i++ ) { try { const results = await runCheck( @@ -811,15 +812,17 @@ ); } } - } catch { - // Ignore for now. + } catch ( error ) { + console.error( error ); + failedChecks.push( checks[ i ] ); } } renderFalsePositiveResults(); const resultsMessage = renderResultsMessage( isSuccessMessage, - aiStats + aiStats, + failedChecks ); // Announce the check results summary so screen-reader users know @@ -830,16 +833,35 @@ } } + /** + * Substitutes printf-style placeholders in a translated string. + * Handles both simple (%d, %s) and positional (%1$d, %2$s) placeholders. + * + * @since n.e.x.t + * + * @param {string} template The translated format string. + * @param {...(string|number)} args Replacement values. + * @return {string} Formatted string with placeholders replaced. + */ + function sprintfReplace( template, ...args ) { + let i = 0; + return template.replace( /%(\d+\$)?[ds]/g, function ( _match, pos ) { + const index = pos ? parseInt( pos, 10 ) - 1 : i++; + return args[ index ] !== undefined ? args[ index ] : _match; + } ); + } + /** * Renders result message. * * @since 1.0.0 * - * @param {boolean} isSuccessMessage Whether the message is a success message. - * @param {Object} aiStats AI statistics. + * @param {boolean} isSuccessMessage Whether the message is a success message. + * @param {?Object} aiStats AI statistics. + * @param {string[]} failedChecks Slugs of checks whose request did not complete. * @return {string} The rendered results message. */ - function renderResultsMessage( isSuccessMessage, aiStats ) { + function renderResultsMessage( isSuccessMessage, aiStats, failedChecks ) { // Count errors and warnings to determine notice severity and compose the message. const { errorCount, warningCount } = isSuccessMessage ? { errorCount: 0, warningCount: 0 } @@ -860,27 +882,6 @@ if ( isSuccessMessage ) { messageText = pluginCheck.successMessage; } else { - /** - * Substitutes printf-style placeholders in a translated string. - * Handles both simple (%d, %s) and positional (%1$d, %2$s) placeholders. - * - * @param {string} template The translated format string. - * @param {...string} args Replacement values. - * @return {string} Formatted string with placeholders replaced. - */ - function sprintfReplace( template, ...args ) { - let i = 0; - return template.replace( - /%(\d+\$)?[ds]/g, - function ( _match, pos ) { - const index = pos ? parseInt( pos, 10 ) - 1 : i++; - return args[ index ] !== undefined - ? args[ index ] - : _match; - } - ); - } - // Build the individual count parts with proper plural/singular forms. let errorPart = ''; if ( errorCount > 0 ) { @@ -926,6 +927,20 @@ } } + // A check whose request did not complete has no results, so the counts above cannot speak for it. + if ( failedChecks && failedChecks.length ) { + messageType = 'error'; + + const failedText = sprintfReplace( + pluginCheck.failedChecksMessage, + failedChecks.join( ', ' ) + ); + + messageText = isSuccessMessage + ? failedText + : messageText + ' ' + failedText; + } + if ( aiStats ) { const aiParts = []; const modelsUsed = [ diff --git a/includes/Admin/Admin_Page.php b/includes/Admin/Admin_Page.php index 3478c19e0..1e4ba718c 100644 --- a/includes/Admin/Admin_Page.php +++ b/includes/Admin/Admin_Page.php @@ -218,6 +218,8 @@ public function enqueue_scripts() { 'summaryBothTemplate' => __( '%1$s and %2$s found.', 'plugin-check' ), /* translators: %s: Formatted issue count string (e.g. "3 errors" or "2 warnings"). */ 'summarySingleTemplate' => __( '%s found.', 'plugin-check' ), + /* translators: %s: Comma-separated list of check slugs. */ + 'failedChecksMessage' => __( 'These checks could not be completed and their results are unknown: %s.', 'plugin-check' ), 'strings' => array( 'checkingPlugin' => __( 'Running plugin checks…', 'plugin-check' ), 'exportCsv' => __( 'Export CSV', 'plugin-check' ),