WordPress 5.1 introduced the Site Health screen (Tools → Site Health) — a diagnostic dashboard that runs checks on PHP version, WordPress version, active plugins, database performance, HTTPS status, file permissions, and more. WordPress 5.2 added a REST API backend for it so the checks run asynchronously. Plugin and theme developers can extend this system with custom tests using the site_status_tests filter, adding their own checks to the Site Health screen. Custom tests appear alongside WordPress’s built-in tests with the same pass/fail/warning status indicators. This is the correct place to surface actionable configuration requirements for a plugin — for example, checking that a required API key is configured, that a custom table exists and has the expected schema, that an external service is reachable, or that a required PHP extension is loaded.
Problem: Your plugin requires the PHP intl extension and a configured API key to function. When either is missing, features break silently. You want these requirements surfaced on the Site Health screen so administrators see them proactively.
Solution: Register custom tests with the site_status_tests filter. Each test returns an array with a status ('good', 'recommended', or 'critical'), a label, and a description.
<?php
// ── Register custom Site Health tests ────────────────────────────────────
add_filter( 'site_status_tests', 'register_my_plugin_health_tests' );
function register_my_plugin_health_tests( $tests ) {
// Direct tests run synchronously on page load
$tests['direct']['my_plugin_intl_extension'] = [
'label' => __( 'PHP intl extension', 'my-plugin' ),
'test' => 'my_plugin_test_intl_extension', // callable name
];
// Async tests run via REST API in the background
$tests['async']['my_plugin_api_connection'] = [
'label' => __( 'My Plugin API connectivity', 'my-plugin' ),
'test' => rest_url( 'my-plugin/v1/health-check' ),
'has_rest' => true,
'async_direct_test' => 'my_plugin_test_api_connection', // fallback callable
];
return $tests;
}
// ── Test: PHP intl extension ───────────────────────────────────────────
function my_plugin_test_intl_extension() {
if ( extension_loaded( 'intl' ) ) {
return [
'label' => __( 'PHP intl extension is available', 'my-plugin' ),
'status' => 'good',
'badge' => [ 'label' => 'My Plugin', 'color' => 'blue' ],
'description' => '<p>' . __( 'The intl extension is loaded and available.', 'my-plugin' ) . '</p>',
'test' => 'my_plugin_intl_extension',
];
}
return [
'label' => __( 'PHP intl extension is missing', 'my-plugin' ),
'status' => 'critical',
'badge' => [ 'label' => 'My Plugin', 'color' => 'red' ],
'description' => '<p>' . __( 'My Plugin requires the PHP intl extension. Contact your host to enable it.', 'my-plugin' ) . '</p>',
'actions' => '<a href="https://www.php.net/intl" target="_blank">' . __( 'Learn more', 'my-plugin' ) . '</a>',
'test' => 'my_plugin_intl_extension',
];
}
// ── Test: API key configured ────────────────────────────────────────────
function my_plugin_test_api_connection() {
$api_key = get_option( 'my_plugin_api_key', '' );
if ( empty( $api_key ) ) {
return [
'label' => __( 'My Plugin API key is not configured', 'my-plugin' ),
'status' => 'recommended',
'badge' => [ 'label' => 'My Plugin', 'color' => 'orange' ],
'description' => '<p>' . __( 'Enter your API key in My Plugin → Settings to enable all features.', 'my-plugin' ) . '</p>',
'actions' => '<a href="' . esc_url( admin_url( 'options-general.php?page=my-plugin' ) ) . '">' . __( 'Go to settings', 'my-plugin' ) . '</a>',
'test' => 'my_plugin_api_connection',
];
}
return [
'label' => __( 'My Plugin API key is configured', 'my-plugin' ),
'status' => 'good',
'badge' => [ 'label' => 'My Plugin', 'color' => 'blue' ],
'description' => '<p>' . __( 'API key found and ready.', 'my-plugin' ) . '</p>',
'test' => 'my_plugin_api_connection',
];
}
NOTE: The three valid status values are 'good' (green), 'recommended' (orange — improvement suggested), and 'critical' (red — something is broken or required). Use 'critical' only for genuinely broken states where plugin functionality is impaired, not for optional improvements. The badge colour is decorative only — it doesn't change the status logic. Use the 'actions' key to add a "Fix it" link that takes the administrator directly to where they can resolve the issue.