Make WordPress Core

Opened 6 months ago

Last modified 6 months ago

#63882 new defect (bug)

Plugins: Preflight activation to avoid WSOD when plugin code uses syntax incompatible with PHP runtime

Reported by: codad5's profile codad5 Owned by:
Milestone: Awaiting Review Priority: normal
Severity: major Version: 6.8.2
Component: Plugins Keywords: has-patch needs-testing
Focuses: sustainability, php-compatibility Cc:

Description

Problem


Activating a plugin whose code is valid only on newer PHP versions (for example, using false as a return type in PHP 8.3) on a site running an older PHP version (e.g. PHP 8.0) can produce a fatal parse error. Because the plugin can already be persisted as "active" before compatibility is verified, the site can end up in a broken/white-screen state that requires DB or filesystem access to recover.

Steps to reproduce


  1. On a site running PHP 8.0, install a plugin whose main file uses syntax valid in PHP 8.3 (e.g., function foo(): false {}).
  2. Attempt to activate the plugin via wp-admin → Plugins → Activate.
  3. The site will display a fatal parse error and the plugin will be in the active_plugins list, causing further loads to attempt to include it.

Expected


Plugin activation should perform a preflight check and not persist a plugin as active if its main file produces a fatal/parsing error. A failed activation should abort and leave the active_plugins option unchanged.

Proposed solution


Before updating active_plugins, preflight-load the plugin main file (sandboxed). If loading produces a fatal error (parse or otherwise), abort activation and show the error without saving the plugin as active. Implementation changes are proposed in:

  • src/wp-admin/includes/plugin.php (inside activate_plugin())
  • Unit tests added in tests/phpunit/tests/admin/includesPlugin.php

Patch/PR


A PR is available on GitHub and this ticket will include the patch. Please see linked PR for details.

Environment tested


  • WordPress: <trunk>
  • PHP: 8.3 (plugin syntax that causes repro)
  • OS: Windows 11
  • Browser: Google Chrome

Change History (2)

This ticket was mentioned in PR #9611 on WordPress/wordpress-develop by @codad5.


6 months ago
#1

  • Keywords has-unit-tests added

Trac ticket: https://core.trac.wordpress.org/ticket/63882

### Summary

Prevents sites from entering a fatal error (WSOD) when activating a plugin that uses PHP syntax incompatible with the current runtime. Before persisting the plugin as active, a preflight check safely includes the plugin file. If a parse error or exception occurs, activation is aborted and the error is displayed without saving the plugin to the database.

### Technical Changes

  • Introduced safe_plugin_activation_check() in plugin.php to sandbox plugin file loading, converting errors/exceptions into WP_Error.
  • Updated activate_plugin() to call safe_plugin_activation_check() before persisting the plugin.
  • Early returns with WP_Error if activation would trigger a fatal error.

### Tests

  • Added PHPUnit tests in tests/phpunit/tests/admin/includesPlugin.php.
  • Coverage includes:
  • Plugins with syntax errors.
  • Plugins throwing runtime exceptions.
  • Valid plugins activating successfully.

### Notes

  • Includes unit tests.
  • Follows WordPress PHP coding standards.
  • Happy to iterate on feedback and naming conventions.
  • Please allow edits by maintainers.

#2 @codad5
6 months ago

  • Keywords has-unit-tests removed

Hi! 👋

I’ve submitted a corresponding GitHub pull request for this patch:
👉 https://github.com/WordPress/wordpress-develop/pull/9611

The PR contains the code changes in src/wp-admin/includes/plugin.php along with unit tests.
Feedback and review would be much appreciated! 🙏

Props: codad5

Note: See TracTickets for help on using tickets.