diff options
Diffstat (limited to '')
-rw-r--r-- | wp-admin/includes/plugin.php | 146 |
1 files changed, 111 insertions, 35 deletions
diff --git a/wp-admin/includes/plugin.php b/wp-admin/includes/plugin.php index f55bbd8..bcae273 100644 --- a/wp-admin/includes/plugin.php +++ b/wp-admin/includes/plugin.php @@ -45,6 +45,7 @@ * @since 1.5.0 * @since 5.3.0 Added support for `Requires at least` and `Requires PHP` headers. * @since 5.8.0 Added support for `Update URI` header. + * @since 6.5.0 Added support for `Requires Plugins` header. * * @param string $plugin_file Absolute path to the main plugin file. * @param bool $markup Optional. If the returned data should have HTML markup applied. @@ -53,39 +54,41 @@ * @return array { * Plugin data. Values will be empty if not supplied by the plugin. * - * @type string $Name Name of the plugin. Should be unique. - * @type string $PluginURI Plugin URI. - * @type string $Version Plugin version. - * @type string $Description Plugin description. - * @type string $Author Plugin author's name. - * @type string $AuthorURI Plugin author's website address (if set). - * @type string $TextDomain Plugin textdomain. - * @type string $DomainPath Plugin's 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. - * @type string $UpdateURI ID of the plugin for update purposes, should be a URI. - * @type string $Title Title of the plugin and link to the plugin's site (if set). - * @type string $AuthorName Plugin author's name. + * @type string $Name Name of the plugin. Should be unique. + * @type string $PluginURI Plugin URI. + * @type string $Version Plugin version. + * @type string $Description Plugin description. + * @type string $Author Plugin author's name. + * @type string $AuthorURI Plugin author's website address (if set). + * @type string $TextDomain Plugin textdomain. + * @type string $DomainPath Plugin's 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. + * @type string $UpdateURI ID of the plugin for update purposes, should be a URI. + * @type string $RequiresPlugins Comma separated list of dot org plugin slugs. + * @type string $Title Title of the plugin and link to the plugin's site (if set). + * @type string $AuthorName Plugin author's name. * } */ function get_plugin_data( $plugin_file, $markup = true, $translate = true ) { $default_headers = array( - 'Name' => 'Plugin Name', - 'PluginURI' => 'Plugin URI', - 'Version' => 'Version', - 'Description' => 'Description', - 'Author' => 'Author', - 'AuthorURI' => 'Author URI', - 'TextDomain' => 'Text Domain', - 'DomainPath' => 'Domain Path', - 'Network' => 'Network', - 'RequiresWP' => 'Requires at least', - 'RequiresPHP' => 'Requires PHP', - 'UpdateURI' => 'Update URI', + 'Name' => 'Plugin Name', + 'PluginURI' => 'Plugin URI', + 'Version' => 'Version', + 'Description' => 'Description', + 'Author' => 'Author', + 'AuthorURI' => 'Author URI', + 'TextDomain' => 'Text Domain', + 'DomainPath' => 'Domain Path', + 'Network' => 'Network', + 'RequiresWP' => 'Requires at least', + 'RequiresPHP' => 'Requires PHP', + 'UpdateURI' => 'Update URI', + 'RequiresPlugins' => 'Requires Plugins', // Site Wide Only is deprecated in favor of Network. - '_sitewide' => 'Site Wide Only', + '_sitewide' => 'Site Wide Only', ); $plugin_data = get_file_data( $plugin_file, $default_headers, 'plugin' ); @@ -478,14 +481,23 @@ function get_dropins() { } /** - * Returns drop-ins that WordPress uses. + * Returns drop-in plugins that WordPress uses. * * Includes Multisite drop-ins only when is_multisite() * * @since 3.0.0 - * @return array[] Key is file name. The value is an array, with the first value the - * purpose of the drop-in and the second value the name of the constant that must be - * true for the drop-in to be used, or true if no constant is required. + * + * @return array[] { + * Key is file name. The value is an array of data about the drop-in. + * + * @type array ...$0 { + * Data about the drop-in. + * + * @type string $0 The purpose of the drop-in. + * @type string|true $1 Name of the constant that must be true for the drop-in + * to be used, or true if no constant is required. + * } + * } */ function _get_dropins() { $dropins = array( @@ -1009,6 +1021,7 @@ function delete_plugins( $plugins, $deprecated = '' ) { foreach ( $translations as $translation => $data ) { $wp_filesystem->delete( WP_LANG_DIR . '/plugins/' . $plugin_slug . '-' . $translation . '.po' ); $wp_filesystem->delete( WP_LANG_DIR . '/plugins/' . $plugin_slug . '-' . $translation . '.mo' ); + $wp_filesystem->delete( WP_LANG_DIR . '/plugins/' . $plugin_slug . '-' . $translation . '.l10n.php' ); $json_translation_files = glob( WP_LANG_DIR . '/plugins/' . $plugin_slug . '-' . $translation . '-*.json' ); if ( $json_translation_files ) { @@ -1113,13 +1126,14 @@ function validate_plugin( $plugin ) { /** * Validates the plugin requirements for WordPress version and PHP version. * - * Uses the information from `Requires at least` and `Requires PHP` headers + * Uses the information from `Requires at least`, `Requires PHP` and `Requires Plugins` headers * defined in the plugin's main PHP file. * * @since 5.2.0 * @since 5.3.0 Added support for reading the headers from the plugin's * main PHP file, with `readme.txt` as a fallback. * @since 5.8.0 Removed support for using `readme.txt` as a fallback. + * @since 6.5.0 Added support for the 'Requires Plugins' header. * * @param string $plugin Path to the plugin file relative to the plugins directory. * @return true|WP_Error True if requirements are met, WP_Error on failure. @@ -1128,8 +1142,9 @@ function validate_plugin_requirements( $plugin ) { $plugin_headers = get_plugin_data( WP_PLUGIN_DIR . '/' . $plugin ); $requirements = array( - 'requires' => ! empty( $plugin_headers['RequiresWP'] ) ? $plugin_headers['RequiresWP'] : '', - 'requires_php' => ! empty( $plugin_headers['RequiresPHP'] ) ? $plugin_headers['RequiresPHP'] : '', + 'requires' => ! empty( $plugin_headers['RequiresWP'] ) ? $plugin_headers['RequiresWP'] : '', + 'requires_php' => ! empty( $plugin_headers['RequiresPHP'] ) ? $plugin_headers['RequiresPHP'] : '', + 'requires_plugins' => ! empty( $plugin_headers['RequiresPlugins'] ) ? $plugin_headers['RequiresPlugins'] : '', ); $compatible_wp = is_wp_version_compatible( $requirements['requires'] ); @@ -1184,6 +1199,62 @@ function validate_plugin_requirements( $plugin ) { ); } + WP_Plugin_Dependencies::initialize(); + + if ( WP_Plugin_Dependencies::has_unmet_dependencies( $plugin ) ) { + $dependency_names = WP_Plugin_Dependencies::get_dependency_names( $plugin ); + $unmet_dependencies = array(); + $unmet_dependency_names = array(); + + foreach ( $dependency_names as $dependency => $dependency_name ) { + $dependency_file = WP_Plugin_Dependencies::get_dependency_filepath( $dependency ); + + if ( false === $dependency_file ) { + $unmet_dependencies['not_installed'][ $dependency ] = $dependency_name; + $unmet_dependency_names[] = $dependency_name; + } elseif ( is_plugin_inactive( $dependency_file ) ) { + $unmet_dependencies['inactive'][ $dependency ] = $dependency_name; + $unmet_dependency_names[] = $dependency_name; + } + } + + $error_message = sprintf( + /* translators: 1: Plugin name, 2: Number of plugins, 3: A comma-separated list of plugin names. */ + _n( + '<strong>Error:</strong> %1$s requires %2$d plugin to be installed and activated: %3$s.', + '<strong>Error:</strong> %1$s requires %2$d plugins to be installed and activated: %3$s.', + count( $unmet_dependency_names ) + ), + $plugin_headers['Name'], + count( $unmet_dependency_names ), + implode( wp_get_list_item_separator(), $unmet_dependency_names ) + ); + + if ( is_multisite() ) { + if ( current_user_can( 'manage_network_plugins' ) ) { + $error_message .= ' ' . sprintf( + /* translators: %s: Link to the plugins page. */ + __( '<a href="%s">Manage plugins</a>.' ), + esc_url( network_admin_url( 'plugins.php' ) ) + ); + } else { + $error_message .= ' ' . __( 'Please contact your network administrator.' ); + } + } else { + $error_message .= ' ' . sprintf( + /* translators: %s: Link to the plugins page. */ + __( '<a href="%s">Manage plugins</a>.' ), + esc_url( admin_url( 'plugins.php' ) ) + ); + } + + return new WP_Error( + 'plugin_missing_dependencies', + "<p>{$error_message}</p>", + $unmet_dependencies + ); + } + return true; } @@ -2386,6 +2457,8 @@ function wp_add_privacy_policy_content( $plugin_name, $policy_text ) { * * @since 5.2.0 * + * @global WP_Paused_Extensions_Storage $_paused_plugins + * * @param string $plugin Path to the plugin file relative to the plugins directory. * @return bool True, if in the list of paused plugins. False, if not in the list. */ @@ -2408,6 +2481,8 @@ function is_plugin_paused( $plugin ) { * * @since 5.2.0 * + * @global WP_Paused_Extensions_Storage $_paused_plugins + * * @param string $plugin Path to the plugin file relative to the plugins directory. * @return array|false Array of error information as returned by `error_get_last()`, * or false if none was recorded. @@ -2482,7 +2557,8 @@ function resume_plugin( $plugin, $redirect = '' ) { * * @since 5.2.0 * - * @global string $pagenow The filename of the current screen. + * @global string $pagenow The filename of the current screen. + * @global WP_Paused_Extensions_Storage $_paused_plugins */ function paused_plugins_notice() { if ( 'plugins.php' === $GLOBALS['pagenow'] ) { |