diff --git a/wp-admin/includes/ajax-actions.php b/wp-admin/includes/ajax-actions.php
index 6f33849fd2..4952415149 100644
--- a/wp-admin/includes/ajax-actions.php
+++ b/wp-admin/includes/ajax-actions.php
@@ -3704,7 +3704,7 @@ function wp_ajax_install_plugin() {
// If installation request is coming from import page, do not return network activation link.
$plugins_url = ( 'import' === $pagenow ) ? admin_url( 'plugins.php' ) : network_admin_url( 'plugins.php' );
- if ( current_user_can( 'activate_plugins' ) && is_plugin_inactive( $install_status['file'] ) ) {
+ if ( current_user_can( 'activate_plugin', $install_status['file'] ) && is_plugin_inactive( $install_status['file'] ) ) {
$status['activateUrl'] = add_query_arg( array(
'_wpnonce' => wp_create_nonce( 'activate-plugin_' . $install_status['file'] ),
'action' => 'activate',
diff --git a/wp-admin/includes/class-plugin-installer-skin.php b/wp-admin/includes/class-plugin-installer-skin.php
index 778313f421..d179fde67f 100644
--- a/wp-admin/includes/class-plugin-installer-skin.php
+++ b/wp-admin/includes/class-plugin-installer-skin.php
@@ -71,7 +71,7 @@ class Plugin_Installer_Skin extends WP_Upgrader_Skin {
if ( ! $this->result || is_wp_error($this->result) ) {
unset( $install_actions['activate_plugin'], $install_actions['network_activate'] );
- } elseif ( ! current_user_can( 'activate_plugins' ) ) {
+ } elseif ( ! current_user_can( 'activate_plugin', $plugin_file ) ) {
unset( $install_actions['activate_plugin'] );
}
diff --git a/wp-admin/includes/class-plugin-upgrader-skin.php b/wp-admin/includes/class-plugin-upgrader-skin.php
index 105a6b9752..ba8c30fbc4 100644
--- a/wp-admin/includes/class-plugin-upgrader-skin.php
+++ b/wp-admin/includes/class-plugin-upgrader-skin.php
@@ -51,7 +51,7 @@ class Plugin_Upgrader_Skin extends WP_Upgrader_Skin {
'activate_plugin' => '' . __( 'Activate Plugin' ) . '',
'plugins_page' => '' . __( 'Return to Plugins page' ) . ''
);
- if ( $this->plugin_active || ! $this->result || is_wp_error( $this->result ) || ! current_user_can( 'activate_plugins' ) )
+ if ( $this->plugin_active || ! $this->result || is_wp_error( $this->result ) || ! current_user_can( 'activate_plugin', $this->plugin ) )
unset( $update_actions['activate_plugin'] );
/**
diff --git a/wp-admin/includes/class-wp-plugin-install-list-table.php b/wp-admin/includes/class-wp-plugin-install-list-table.php
index bf6cf3d71b..46eca16143 100644
--- a/wp-admin/includes/class-wp-plugin-install-list-table.php
+++ b/wp-admin/includes/class-wp-plugin-install-list-table.php
@@ -468,7 +468,7 @@ class WP_Plugin_Install_List_Table extends WP_List_Table {
case 'newer_installed':
if ( is_plugin_active( $status['file'] ) ) {
$action_links[] = '';
- } elseif ( current_user_can( 'activate_plugins' ) ) {
+ } elseif ( current_user_can( 'activate_plugin', $status['file'] ) ) {
$button_text = __( 'Activate' );
/* translators: %s: Plugin name */
$button_label = _x( 'Activate %s', 'plugin' );
diff --git a/wp-admin/includes/class-wp-plugins-list-table.php b/wp-admin/includes/class-wp-plugins-list-table.php
index 41b36d45d7..7073e79051 100644
--- a/wp-admin/includes/class-wp-plugins-list-table.php
+++ b/wp-admin/includes/class-wp-plugins-list-table.php
@@ -620,11 +620,15 @@ class WP_Plugins_List_Table extends WP_List_Table {
'network_only' => __( 'Network Only' ),
);
} elseif ( $is_active ) {
- /* translators: %s: plugin name */
- $actions['deactivate'] = '' . __( 'Deactivate' ) . '';
+ if ( current_user_can( 'deactivate_plugin', $plugin_file ) ) {
+ /* translators: %s: plugin name */
+ $actions['deactivate'] = '' . __( 'Deactivate' ) . '';
+ }
} else {
- /* translators: %s: plugin name */
- $actions['activate'] = '' . __( 'Activate' ) . '';
+ if ( current_user_can( 'activate_plugin', $plugin_file ) ) {
+ /* translators: %s: plugin name */
+ $actions['activate'] = '' . __( 'Activate' ) . '';
+ }
if ( ! is_multisite() && current_user_can( 'delete_plugins' ) ) {
/* translators: %s: plugin name */
diff --git a/wp-admin/plugins.php b/wp-admin/plugins.php
index 3d7ff016e5..e19f5849e9 100644
--- a/wp-admin/plugins.php
+++ b/wp-admin/plugins.php
@@ -29,8 +29,9 @@ if ( $action ) {
switch ( $action ) {
case 'activate':
- if ( ! current_user_can('activate_plugins') )
- wp_die(__('Sorry, you are not allowed to activate plugins for this site.'));
+ if ( ! current_user_can( 'activate_plugin', $plugin ) ) {
+ wp_die( __( 'Sorry, you are not allowed to activate this plugin.' ) );
+ }
if ( is_multisite() && ! is_network_admin() && is_network_only_plugin( $plugin ) ) {
wp_redirect( self_admin_url("plugins.php?plugin_status=$status&paged=$page&s=$s") );
@@ -88,6 +89,10 @@ if ( $action ) {
if ( is_plugin_active( $plugin ) || ( is_multisite() && is_network_only_plugin( $plugin ) ) ) {
unset( $plugins[ $i ] );
}
+ // Only activate plugins which the user can activate.
+ if ( ! current_user_can( 'activate_plugin', $plugin ) ) {
+ unset( $plugins[ $i ] );
+ }
}
}
@@ -146,8 +151,9 @@ if ( $action ) {
exit;
case 'error_scrape':
- if ( ! current_user_can('activate_plugins') )
- wp_die(__('Sorry, you are not allowed to activate plugins for this site.'));
+ if ( ! current_user_can( 'activate_plugin', $plugin ) ) {
+ wp_die( __( 'Sorry, you are not allowed to activate this plugin.' ) );
+ }
check_admin_referer('plugin-activation-error_' . $plugin);
@@ -167,8 +173,9 @@ if ( $action ) {
exit;
case 'deactivate':
- if ( ! current_user_can('activate_plugins') )
- wp_die(__('Sorry, you are not allowed to deactivate plugins for this site.'));
+ if ( ! current_user_can( 'deactivate_plugin', $plugin ) ) {
+ wp_die( __( 'Sorry, you are not allowed to deactivate this plugin.' ) );
+ }
check_admin_referer('deactivate-plugin_' . $plugin);
@@ -192,8 +199,9 @@ if ( $action ) {
exit;
case 'deactivate-selected':
- if ( ! current_user_can('activate_plugins') )
+ if ( ! current_user_can( 'deactivate_plugins' ) ) {
wp_die(__('Sorry, you are not allowed to deactivate plugins for this site.'));
+ }
check_admin_referer('bulk-plugins');
@@ -204,6 +212,14 @@ if ( $action ) {
} else {
$plugins = array_filter( $plugins, 'is_plugin_active' );
$plugins = array_diff( $plugins, array_filter( $plugins, 'is_plugin_active_for_network' ) );
+
+ foreach ( $plugins as $i => $plugin ) {
+ // Only deactivate plugins which the user can deactivate.
+ if ( ! current_user_can( 'deactivate_plugin', $plugin ) ) {
+ unset( $plugins[ $i ] );
+ }
+ }
+
}
if ( empty($plugins) ) {
wp_redirect( self_admin_url("plugins.php?plugin_status=$status&paged=$page&s=$s") );
diff --git a/wp-includes/capabilities.php b/wp-includes/capabilities.php
index 5993a77caf..0db4c425a6 100644
--- a/wp-includes/capabilities.php
+++ b/wp-includes/capabilities.php
@@ -407,7 +407,10 @@ function map_meta_cap( $cap, $user_id ) {
}
break;
case 'activate_plugins':
- $caps[] = $cap;
+ case 'deactivate_plugins':
+ case 'activate_plugin':
+ case 'deactivate_plugin':
+ $caps[] = 'activate_plugins';
if ( is_multisite() ) {
// update_, install_, and delete_ are handled above with is_super_admin().
$menu_perms = get_site_option( 'menu_items', array() );
diff --git a/wp-includes/version.php b/wp-includes/version.php
index e7b9a54372..7a106bf554 100644
--- a/wp-includes/version.php
+++ b/wp-includes/version.php
@@ -4,7 +4,7 @@
*
* @global string $wp_version
*/
-$wp_version = '4.9-alpha-41289';
+$wp_version = '4.9-alpha-41290';
/**
* Holds the WordPress DB revision, increments when changes are made to the WordPress DB schema.