Opened 12 months ago
Last modified 12 months ago
#60491 new defect (bug)
Fix handling of plugins with unmet requirements
Reported by: |
|
Owned by: | |
---|---|---|---|
Milestone: | Future Release | Priority: | normal |
Severity: | normal | Version: | 5.1 |
Component: | Plugins | Keywords: | needs-patch |
Focuses: | Cc: |
Description
There are several bugs/inconsistencies when WordPress handles plugins with unmet requirements.
- A plugin with unmet requirements cannot be installed or updated when using the UI, but this is possible to do/there are no checks when a plugin is installed or updated directly (with FTP, SSH, or git/svn).
- A plugin with unmet requirements cannot be activated if already installed (happens only when a plugins is installed/updated from FTP, SSH, or git/svn). But if the plugin is already activated, it is not deactivated and continues to load.
- The UX can be better. The warnings in wp-admin when a plugin has unmet requirements are somewhat inconsistent, and there are no email notifications if any of these errors occur automatically (for example a script is running on the server that uses svn or git to update plugins).
Attachments (3)
Change History (17)
@
12 months ago
An activated plugin with unmet requirements is still active/loaded. Also the background color under the notice needs fixing.
@
12 months ago
The error message at the top of the screen is missing initially and appears after the second reload.
#1
@
12 months ago
- Keywords needs-patch added
Most of these inconsistencies are (more or less) edge cases and happen only when a plugin is installed or updated directly, either using FTP or version control. A plugin with unmet requirements cannot be installed or updated through the WP UI as the API of the plugins repository on wp.org simply skips incompatible plugins.
Nevertheless thinking that the plugins API in WP should be fixed to behave consistently in these edge cases. The same behaviour should probably be implemented for plugin dependencies and in all other similar cases.
#2
@
12 months ago
The error message at the top of the screen is missing initially and appears after the second reload.
Just a note on this one:
The error message missing initially is because the plugin header was modified rather than the server's PHP version. On the initial load, the plugin_data
option storing the RequiresPHP
header will not be "fresh" (to avoid loading from the filesystem on every page load).
If the server's PHP version were to change, and the server restarted if necessary to load the different PHP version, then the notice would appear on the first load.
#3
follow-up:
↓ 8
@
12 months ago
The main difference between "not loaded" and "deactivated" in the context of #60457 is that deactivating performs a DB write to active_plugins
, whereas not loading just skips the require_once
.
We will have to remove the automatic deactivation of dependents with unmet dependencies, at least from the frontend.
Changing so that automatic deactivation is only performed on plugins.php
, for example, will involve relocating WP_Plugin_Dependencies::initialize()
to below require ABSPATH . WPINC . '/vars.php';
in wp-settings.php
. This means that $pagenow
is defined and can therefore be used in a guard.
#4
follow-up:
↓ 7
@
12 months ago
A plugin with unmet requirements cannot be updated when using the UI
That seems like an unnecessary restriction. What if the updated version doesn‘t have any dependencies anymore? Then you would have to uninstall and reinstall, which is weird.
#5
@
12 months ago
The requirements on Plugins > Add New
are taken from the WordPress.org Plugins API rather than from the install version's headers, so the removal of dependencies would be detected and the update should be possible in that case.
#7
in reply to:
↑ 4
@
12 months ago
Replying to swissspidy:
A plugin with unmet requirements cannot be updated when using the UI
That seems like an unnecessary restriction. What if the updated version doesn‘t have any dependencies anymore? Then you would have to uninstall and reinstall, which is weird.
This is handled by the wporg API. Think that if a plugin has had unmet requirements, but now all requirements are satisfied, it will be returned by the API as an available update (untested).
#8
in reply to:
↑ 3
@
12 months ago
Replying to costdev:
The main difference between "not loaded" and "deactivated" in the context of #60457 is that deactivating performs a DB write to
active_plugins
, whereas not loading just skips therequire_once
.
We will have to remove the automatic deactivation of dependents with unmet dependencies, at least from the frontend.
Right, makes sense.
Also perhaps that part of the plugins API can be a bit better/faster/simpler? For example what if WP was deciding when to initialize a plugin? So initialization of plugins would not happen automatically by just loading the plugin file? Then WP would be able to handle all the edge cases much better/faster, and also will be able to show more consistent warnings to the users? Worth exploring imho :)
This ticket was mentioned in Slack in #core-upgrade-install by costdev. View the logs.
12 months ago
#10
follow-up:
↓ 12
@
12 months ago
Should an active plugin with new unmet requirements remain active? It would seem that doing so might result in a fatal.
This ticket was mentioned in Slack in #cli by costdev. View the logs.
12 months ago
#12
in reply to:
↑ 10
@
12 months ago
Replying to afragen:
Should an active plugin with new unmet requirements remain active?
Seems not. It may throw a fatal error as you say, but imho a worse case is if the plugin continues to work to some extend but accumulates errors in the DB, or returns the wrong info on certain requests, or other hard to find/notice error.
The above screenshot shows that an activated plugin with unmet PHP requirement is still loaded which is a bug imho, and needs fixing.
#13
@
12 months ago
what if WP was deciding when to initialize a plugin
Thinking this is (probably) the best way forward for supporting all plugin requirements, current and future.
To be able to do this WP will need access to the plugin's meta (the headers) before it can decide to load/initialize the plugin or not. Seems there are two more or less straightforward ways to accomplish this:
- Store all of the plugin's meta in the DB, and update it when installing or updating a plugin (and maybe when activating to catch cases where a plugin was installed from FTP).
Advantages: Getting the plugins meta from the DB (or from persistent cache) will be super fast compared to "reading" the plugin's headers every time. Also this method will not need any changes to how plugin meta is currently stored in the plugin's main file (plugins headers).
Disadvantages: Edge case when updating an activated plugin outside of WP, through FTP or git/svn. That will bypass updating of the stored plugin meta and possibly result in loading a plugin with unmet requirements (like the case described above). Seems it's possible to solve this by storing the "last modified" time for the plugin's main file together with the plugin's meta, and check it every time to detect updates. As far as I see doing filemtime()
for about 30-40 files will not introduce a noticeable delay. On my test site these are super fast, take few nanoseconds per file.
- Introduce a new way to store the plugin's meta in the main plugin file. Seems an associative array would work well. This can be in addition to the current headers or instead of them. Something like:
$plugin_meta = array( plugin_name => 'My plugin', requires_at_least => '6.3', requires_PHP => '8.0', version => '1.2.345', init_callback => 'my_plugin_init', );
(Note the new init_callback
meta key.)
Then when WP is loading the main plugin file, it can do something like:
$plugin_meta = null; foreach ( $plugins as $plugin ) { if ( is_array( $plugin_meta ) ) { if ( // Check PHP version requirement if set // Check WP version requirement if set // Check for plugin dependencies if set // Check any other (new) requirements if set ) { if ( is_callable( $plugin_meta['init_callback'] ) ) { call_user_func( plugin_meta['init_callback'] ); } else { // Throw error depending on WP_Dev constants } } else { // Show a "plugin requirements not met" error/warning. // The error should also explain that the plugin has been disabled // until the problem is resolved. // (Note that the plugin is still activated at this point // but WP is not loading/initializing it) } } else { // Load the plugin the old way (existing code) } $plugin_meta = null; // The meta array needs to be reset for the next plugin }
Advantages: Fast and easy way to access the plugin's meta before initializing the plugin. This solves the edge case when an activated plugin is updated outside of WP, through FTP or git/svn.
Disadvantage: Requires the new $plugin_meta
var to be defined in the main plugin file.
Plugin with unmet requirements cannot be activated.