-
Notifications
You must be signed in to change notification settings - Fork 0
Multisite Support
The plugin supports both single-site and multisite WordPress installations. The main difference is in the uninstall phase: on a multisite network, data cleanup is performed for every blog in the network.
Cron, options, and transients are per-blog in WordPress architecture, so activation and deactivation do not require multisite-specific logic.
| Phase | Single-site | Multisite |
|---|---|---|
| Activation | Activator::activate() |
Identical (cron and options are per-blog) |
| Deactivation | Activator::deactivate() |
Identical |
| Uninstall | Uninstaller::uninstall_single() |
Uninstaller::uninstall_network() → iterates all blogs |
src/Core/Uninstaller.php
The uninstall() method automatically detects the installation type:
public function uninstall(): void {
if ( is_multisite() ) {
$this->uninstall_network();
} else {
$this->uninstall_single();
}
}uninstall_network() iterates over all blogs in the network:
private function uninstall_network(): void {
$blog_ids = get_sites( [ 'fields' => 'ids' ] );
foreach ( $blog_ids as $blog_id ) {
switch_to_blog( $blog_id );
$this->uninstall_single();
restore_current_blog();
}
}For each blog, the same cleanup as single-site is performed:
- Delete plugin options (
ops_health_activated_at,ops_health_version,ops_health_latest_results,ops_health_alert_settings,ops_health_alert_log) - Remove cron hook (
ops_health_run_checks) - Delete fixed transients (
ops_health_cron_check,ops_health_admin_notice,ops_health_alert_notice) - Delete dynamic cooldown transients via
$wpdbLIKE query (_transient_ops_health_alert_cooldown_%)
uninstall.php
When the Composer autoloader is unavailable (e.g., after a corrupted update), uninstall.php has an inline fallback with three branches:
1. vendor/autoload.php exists → uses Uninstaller class (handles multisite internally)
2. elseif is_multisite() → inline fallback with blog iteration
3. else → inline single-site fallback
The multisite fallback replicates the same pattern as Uninstaller::uninstall_network():
$ops_health_blog_ids = get_sites( [ 'fields' => 'ids' ] );
foreach ( $ops_health_blog_ids as $ops_health_blog_id ) {
switch_to_blog( $ops_health_blog_id );
ops_health_uninstall_single_site( $wpdb );
restore_current_blog();
}Note: variables in the fallback use the $ops_health_ prefix to comply with the WPCS PrefixAllGlobals rule.
tests/bootstrap.php supports the WP_TESTS_MULTISITE environment variable:
if ( getenv( 'WP_TESTS_MULTISITE' ) ) {
define( 'WP_TESTS_MULTISITE', true );
}When active, the WordPress Test Suite loads the environment as a multisite network.
| Command | Description |
|---|---|
composer test:integration:multisite |
Integration tests in multisite mode |
composer test:coverage:multisite |
Multisite integration coverage (clover XML) |
composer test:coverage |
3 suites: unit + integration + multisite |
tests/Integration/Core/UninstallerTest.php contains 3 multisite tests with guard:
if ( ! is_multisite() ) {
$this->markTestSkipped( 'Requires multisite.' );
}The multisite tests verify:
-
uninstall_network()iterates over all blogs - Options and transients are removed for each blog
-
restore_current_blog()restores the original context
The is_multisite() branch in uninstall() creates a condition that can only be 100% covered by combining:
-
Integration single-site: covers the
elsebranch (non-multisite) -
Integration multisite: covers the
ifbranch (multisite)
The clover XML reports are separate:
-
coverage/clover-integration.xml(single-site) -
coverage/clover-multisite.xml(multisite)
Codecov automatically merges the reports thanks to the carryforward: true configuration.