Skip to content

GH#837: fix network activation reliability in multisite setup wizard#852

Merged
superdav42 merged 1 commit intomainfrom
feature/auto-20260414-093848
Apr 14, 2026
Merged

GH#837: fix network activation reliability in multisite setup wizard#852
superdav42 merged 1 commit intomainfrom
feature/auto-20260414-093848

Conversation

@superdav42
Copy link
Copy Markdown
Collaborator

Summary

Fixes a race condition in the Multisite Setup Wizard where the final Network Activate Plugin step would sometimes silently fall back to single-site activation instead of network-wide activation.

Root cause

_install_network_activate() in Multisite_Network_Installer called activate_plugin(WP_ULTIMO_PLUGIN_FILE, '', true) to perform network activation. WordPress's activate_plugin() checks is_multisite() internally and uses the active_sitewide_plugins sitemeta key only when multisite is active. If is_multisite() returns false, it falls back silently to single-site activation.

The MULTISITE constant is written to wp-config.php in the immediately-preceding step (_install_update_wp_config). Each wizard step runs in a separate AJAX request, but if OPcache or another PHP bytecode cache serves a stale wp-config.php in the next request, is_multisite() returns false in the network_activate step — producing the "appears to but doesn't, sometimes" behaviour from the issue.

A secondary bug: the early-return guard used is_plugin_active(WP_ULTIMO_PLUGIN_FILE) with the full absolute path instead of the plugin basename (WP_ULTIMO_PLUGIN_BASENAME), so the guard never fired.

Fix

Replace activate_plugin() with a direct write to the wp_sitemeta table, as the existing code comment already described as the intent. This bypasses the is_multisite() dependency entirely and guarantees reliable network activation regardless of bytecode caching.

Files changed

  • EDIT: inc/installers/class-multisite-network-installer.php — rewrites _install_network_activate() to write directly to {prefix}sitemeta via $wpdb->get_row / $wpdb->update / $wpdb->insert, using WP_ULTIMO_PLUGIN_BASENAME throughout
  • NEW: tests/WP_Ultimo/Installers/Multisite_Network_Installer_Test.php — 16 tests covering get_steps(), get_config(), check_network_tables_exist(), and all branches of _install_network_activate() including idempotency and existing-plugin preservation

Verification

WP_TESTS_DIR=/tmp/wordpress-tests-lib vendor/bin/phpunit \
  --filter Multisite_Network_Installer_Test --no-coverage --testdox
# OK (16 tests, 49 assertions)

vendor/bin/phpstan analyse inc/installers/class-multisite-network-installer.php --no-progress
# [OK] No errors

Resolves #837

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai bot commented Apr 14, 2026

Warning

Rate limit exceeded

@superdav42 has exceeded the limit for the number of commits that can be reviewed per hour. Please wait 39 minutes and 6 seconds before requesting another review.

Your organization is not enrolled in usage-based pricing. Contact your admin to enable usage-based pricing to continue reviews beyond the rate limit, or try again in 39 minutes and 6 seconds.

⌛ How to resolve this issue?

After the wait time has elapsed, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout.

Please see our FAQ for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: b4f2043d-3486-4a24-a097-7f1dae0c46ef

📥 Commits

Reviewing files that changed from the base of the PR and between bbcffc0 and f9ffe08.

📒 Files selected for processing (2)
  • inc/installers/class-multisite-network-installer.php
  • tests/WP_Ultimo/Installers/Multisite_Network_Installer_Test.php
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feature/auto-20260414-093848

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

…ation

The _install_network_activate() step in Multisite_Network_Installer relied
on activate_plugin() to network-activate the plugin. That function checks
is_multisite() internally and falls back to single-site activation when it
returns false. The MULTISITE constant is written to wp-config.php only in
the immediately-preceding step (_install_update_wp_config); if OPcache or
another PHP bytecode cache serves a stale wp-config.php in the next AJAX
request, is_multisite() returns false and the plugin ends up activated as
a single-site plugin instead of network-wide — matching the 'sometimes
fails' behaviour reported in GH#837.

The fix writes directly to the sitemeta table (as the original code comment
already intended), bypassing activate_plugin() entirely. This guarantees
network activation regardless of whether the current PHP process has loaded
the new multisite constants.

Also fixes the early-return guard which used the full absolute path
(WP_ULTIMO_PLUGIN_FILE) instead of the plugin basename
(WP_ULTIMO_PLUGIN_BASENAME), causing is_plugin_active() to never match.

Adds Multisite_Network_Installer_Test with 16 tests (49 assertions) covering
get_steps(), get_config(), check_network_tables_exist(), and all branches
of _install_network_activate() including idempotency and existing-plugin
preservation.

Fixes #837
@superdav42 superdav42 force-pushed the feature/auto-20260414-093848 branch from 67c8750 to f9ffe08 Compare April 14, 2026 15:50
@superdav42 superdav42 merged commit d8e87dc into main Apr 14, 2026
5 of 7 checks passed
@superdav42
Copy link
Copy Markdown
Collaborator Author

Merge Summary

Issue: #837 — The multisite setup wizard does not network activate the plugin

Root cause: _install_network_activate() in Multisite_Network_Installer called activate_plugin(), which internally checks is_multisite(). The MULTISITE constant is written to wp-config.php only in the preceding step; if OPcache serves a stale copy on the next AJAX request, is_multisite() returns false and the plugin is activated single-site only — explaining the intermittent failure.

A secondary bug: the early-return guard used WP_ULTIMO_PLUGIN_FILE (full absolute path) instead of WP_ULTIMO_PLUGIN_BASENAME, so the guard never fired.

Fix: Replaced activate_plugin() with a direct write to the {prefix}sitemeta table, bypassing the is_multisite() dependency entirely. The implementation matches what the original code comment already described as the intent.

Changes:

  • inc/installers/class-multisite-network-installer.php — rewrote _install_network_activate()
  • tests/WP_Ultimo/Installers/Multisite_Network_Installer_Test.php — 16 new tests (49 assertions)

Verification: All 16 new tests pass; PHPStan reports no errors.


aidevops.sh v3.8.25 plugin for OpenCode v1.4.3 with claude-sonnet-4-6 spent 12m and 1,346 tokens on this as a headless worker. Overall, 1m since this issue was created.

@github-actions
Copy link
Copy Markdown

🔨 Build Complete - Ready for Testing!

📦 Download Build Artifact (Recommended)

Download the zip build, upload to WordPress and test:

🌐 Test in WordPress Playground (Very Experimental)

Click the link below to instantly test this PR in your browser - no installation needed!
Playground support for multisite is very limitied, hopefully it will get better in the future.

🚀 Launch in Playground

Login credentials: admin / password

@github-actions
Copy link
Copy Markdown

🔨 Build Complete - Ready for Testing!

📦 Download Build Artifact (Recommended)

Download the zip build, upload to WordPress and test:

🌐 Test in WordPress Playground (Very Experimental)

Click the link below to instantly test this PR in your browser - no installation needed!
Playground support for multisite is very limitied, hopefully it will get better in the future.

🚀 Launch in Playground

Login credentials: admin / password

@github-actions
Copy link
Copy Markdown

github-actions bot commented Apr 14, 2026

Performance Test Results

Performance test results for f8c57a4 are in 🛎️!

Note: the numbers in parentheses show the difference to the previous (baseline) test run. Differences below 2% or 0.5 in absolute values are not shown.

URL: /

Run DB Queries Memory Before Template Template WP Total LCP TTFB LCP - TTFB
0 41 37.79 MB 840.00 ms 168.50 ms (-5.50 ms / -3% ) 1050.50 ms 2108.00 ms 1992.45 ms 93.60 ms (+3.15 ms / +3% )
1 56 49.03 MB 968.50 ms (+52.50 ms / +5% ) 148.00 ms 1116.50 ms (+55.00 ms / +5% ) 2106.00 ms (+56.00 ms / +3% ) 2026.45 ms (+63.50 ms / +3% ) 81.60 ms

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

The multi-site settup wizard does not network activate the plugin

1 participant