Add Custom Tests to the WordPress Site Health Screen with site_status_tests

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.