diff --git a/inc/admin-pages/class-multisite-setup-admin-page.php b/inc/admin-pages/class-multisite-setup-admin-page.php index 10d994462..6a6d618eb 100644 --- a/inc/admin-pages/class-multisite-setup-admin-page.php +++ b/inc/admin-pages/class-multisite-setup-admin-page.php @@ -484,6 +484,17 @@ public function setup_install(): void { $installer = wu_request('installer', ''); $multisite_network_installer = Multisite_Network_Installer::get_instance(); $steps = $multisite_network_installer->get_steps(); + + /* + * Only handle installers that belong to the multisite network installer. + * Unknown step names fall through to the next wp_ajax handler (priority 10) + * which handles Core_Installer, Default_Content_Installer, etc. + * + * IMPORTANT: this must use `return` (not exit) so the Setup_Wizard_Admin_Page + * handler can process its own steps. But we must NOT let a known multisite + * step silently pass through — if handle() returns a non-WP_Error the step + * genuinely succeeded; only unknown steps should fall through. + */ if ( ! isset($steps[ $installer ])) { return; } @@ -492,6 +503,8 @@ public function setup_install(): void { if (is_wp_error($status)) { wp_send_json_error($status); + + exit; } wp_send_json_success(); diff --git a/inc/admin-pages/class-setup-wizard-admin-page.php b/inc/admin-pages/class-setup-wizard-admin-page.php index af873d272..6fa53152e 100644 --- a/inc/admin-pages/class-setup-wizard-admin-page.php +++ b/inc/admin-pages/class-setup-wizard-admin-page.php @@ -153,8 +153,11 @@ public function __construct() { /** * Handles the AJAX request to network-activate Ultimate Multisite. * - * Attempts to network-activate the plugin, returning a JSON response. - * On success the caller should reload the page so the checks refresh. + * Writes directly to the sitemeta table instead of using activate_plugin() + * because is_multisite() may return false when OPcache serves a stale + * wp-config.php. activate_plugin() silently falls back to single-site + * activation in that case. The direct sitemeta write guarantees reliable + * network activation regardless of bytecode caching state. * * @since 2.3.0 * @return void @@ -169,14 +172,10 @@ public function ajax_network_activate(): void { exit; } - if ( ! function_exists('activate_plugin')) { - require_once ABSPATH . 'wp-admin/includes/plugin.php'; - } - - $result = activate_plugin(WP_ULTIMO_PLUGIN_BASENAME, '', true); - - if (is_wp_error($result)) { - wp_send_json_error($result); + try { + Multisite_Network_Installer::get_instance()->_install_network_activate(); + } catch (\Throwable $e) { + wp_send_json_error(new \WP_Error('activation-failed', $e->getMessage())); exit; } diff --git a/inc/installers/class-base-installer.php b/inc/installers/class-base-installer.php index fa578b402..84013793b 100644 --- a/inc/installers/class-base-installer.php +++ b/inc/installers/class-base-installer.php @@ -99,7 +99,14 @@ public function handle($status, $installer, $wizard) { // phpcs:ignore Generic.C return new \WP_Error($installer, $e->getMessage()); } - $wpdb->query('COMMIT'); // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching + $committed = $wpdb->query('COMMIT'); // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching + + if (false === $committed) { + $error_msg = $wpdb->last_error ?: __('Transaction commit failed.', 'ultimate-multisite'); + wu_log_add(\WP_Ultimo::LOG_HANDLE, "Installer '{$installer}' commit failed: {$error_msg}", LogLevel::ERROR); + + return new \WP_Error($installer, $error_msg); + } return $status; }