From 1f1cf751e5130249ee06684399f001ae4479e650 Mon Sep 17 00:00:00 2001 From: Sergey Biryukov Date: Tue, 18 Jun 2019 03:23:53 +0000 Subject: [PATCH] Plugins: When validating plugin's WordPress and PHP requirements, check for `Requires at least` and `Requires PHP` headers in the plugin's main PHP file. This allows for blocking plugin activation if it requires a higher version of PHP or WordPress, and does not have a `readme.txt` file. If the headers are defined in both `readme.txt` and the main plugin file, precedence is given to the plugin file. Props afragen, Otto42, Ipstenu. Fixes #46938. git-svn-id: https://develop.svn.wordpress.org/trunk@45546 602fd350-edb4-49c9-b593-d223f7449a82 --- src/wp-admin/includes/plugin.php | 21 +++++++++++++++++---- 1 file changed, 17 insertions(+), 4 deletions(-) diff --git a/src/wp-admin/includes/plugin.php b/src/wp-admin/includes/plugin.php index 6244c3fd44..84faa068da 100644 --- a/src/wp-admin/includes/plugin.php +++ b/src/wp-admin/includes/plugin.php @@ -31,6 +31,8 @@ * Network: Optional. Specify "Network: true" to require that a plugin is activated * across all sites in an installation. This will prevent a plugin from being * activated on a single site when Multisite is enabled. + * Requires at least: Optional. Specify the minimum required WordPress version. + * Requires PHP: Optional. Specify the minimum required PHP version. * * / # Remove the space to close comment * * Some users have issues with opening large files and manipulating the contents @@ -46,6 +48,7 @@ * reading. * * @since 1.5.0 + * @since 5.3.0 Added support for `Requires at least` and `Requires PHP`. * * @param string $plugin_file Absolute path to the main plugin file. * @param bool $markup Optional. If the returned data should have HTML markup applied. @@ -63,6 +66,8 @@ * @type string $TextDomain Plugin textdomain. * @type string $DomainPath Plugins relative directory path to .mo files. * @type bool $Network Whether the plugin can only be activated network-wide. + * @type string $RequiresWP Minimum required version of WordPress. + * @type string $RequiresPHP Minimum required version of PHP. * } */ function get_plugin_data( $plugin_file, $markup = true, $translate = true ) { @@ -77,6 +82,8 @@ function get_plugin_data( $plugin_file, $markup = true, $translate = true ) { 'TextDomain' => 'Text Domain', 'DomainPath' => 'Domain Path', 'Network' => 'Network', + 'RequiresWP' => 'Requires at least', + 'RequiresPHP' => 'Requires PHP', // Site Wide Only is deprecated in favor of Network. '_sitewide' => 'Site Wide Only', ); @@ -1085,6 +1092,10 @@ function validate_plugin( $plugin ) { */ function validate_plugin_requirements( $plugin ) { $readme_file = WP_PLUGIN_DIR . '/' . dirname( $plugin ) . '/readme.txt'; + $plugin_data = array( + 'requires' => '', + 'requires_php' => '', + ); if ( file_exists( $readme_file ) ) { $plugin_data = get_file_data( @@ -1095,15 +1106,17 @@ function validate_plugin_requirements( $plugin ) { ), 'plugin' ); - } else { - return true; } + $plugin_data = array_merge( $plugin_data, get_plugin_data( WP_PLUGIN_DIR . '/' . $plugin ) ); + + // Check for headers in the plugin's PHP file, give precedence to the plugin headers. + $plugin_data['requires'] = ! empty( $plugin_data['RequiresWP'] ) ? $plugin_data['RequiresWP'] : $plugin_data['requires']; + $plugin_data['requires_php'] = ! empty( $plugin_data['RequiresPHP'] ) ? $plugin_data['RequiresPHP'] : $plugin_data['requires_php']; + $plugin_data['wp_compatible'] = is_wp_version_compatible( $plugin_data['requires'] ); $plugin_data['php_compatible'] = is_php_version_compatible( $plugin_data['requires_php'] ); - $plugin_data = array_merge( $plugin_data, get_plugin_data( WP_PLUGIN_DIR . '/' . $plugin ) ); - if ( ! $plugin_data['wp_compatible'] && ! $plugin_data['php_compatible'] ) { return new WP_Error( 'plugin_wp_php_incompatible',