From 363da801f5a282955ab8310107c44d7ddcacd892 Mon Sep 17 00:00:00 2001 From: ryan Date: Fri, 29 Jan 2010 21:45:32 +0000 Subject: [PATCH] Integrate sitewide plugin handling into activate_plugins(), deactivate_plugins(), and plugins.php. fixes #11767 see #11644 git-svn-id: http://svn.automattic.com/wordpress/trunk@12903 1a063a9b-81f0-0310-95a4-ce76da25c4cd --- wp-admin/includes/ms.php | 264 ++--------------------------------- wp-admin/includes/plugin.php | 89 ++++++++++-- wp-admin/plugins.php | 46 ++++-- 3 files changed, 126 insertions(+), 273 deletions(-) diff --git a/wp-admin/includes/ms.php b/wp-admin/includes/ms.php index bfb011c2b4..d1099e92f9 100644 --- a/wp-admin/includes/ms.php +++ b/wp-admin/includes/ms.php @@ -742,280 +742,38 @@ function avoid_blog_page_permalink_collision( $data, $postarr ) { add_filter( 'wp_insert_post_data', 'avoid_blog_page_permalink_collision', 10, 2 ); /** - * activate_sitewide_plugin() - * - * Activates a plugin site wide (for all blogs on an installation) + * @deprecated */ function activate_sitewide_plugin() { - if ( !isset( $_GET['sitewide'] ) ) - return false; - - /* Add the plugin to the list of sitewide active plugins */ - $active_sitewide_plugins = maybe_unserialize( get_site_option( 'active_sitewide_plugins' ) ); - - /* Add the activated plugin to the list */ - $active_sitewide_plugins[ $_GET['plugin'] ] = time(); - - /* Write the updated option to the DB */ - if ( !update_site_option( 'active_sitewide_plugins', $active_sitewide_plugins ) ) - return false; - - return true; -} - -// @todo Throws warning if plugin is not set. Kinda janky. -//add_action( 'activate_' . $_GET['plugin'], 'activate_sitewide_plugin' ); - -/** - * deactivate_sitewide_plugin() - * - * Deactivates a plugin site wide (for all blogs on an installation) - */ -function deactivate_sitewide_plugin( $plugin = false ) { - if ( !$plugin ) - $plugin = $_GET['plugin']; - - /* Get the active sitewide plugins */ - $active_sitewide_plugins = (array) maybe_unserialize( get_site_option( 'active_sitewide_plugins' ) ); - - /* Remove the plugin we are deactivating from the list of active sitewide plugins */ - foreach ( $active_sitewide_plugins as $plugin_file => $activation_time ) { - if ( $plugin == $plugin_file ) - unset( $active_sitewide_plugins[ $plugin_file ] ); - } - - if ( !update_site_option( 'active_sitewide_plugins', $active_sitewide_plugins ) ) - wp_redirect( 'plugins.php?error=true' ); - - return true; -} -// @todo Throws warning if plugin is not set. Kinda janky. -//add_action( 'deactivate_' . $_GET['plugin'], 'deactivate_sitewide_plugin' ); -add_action( 'deactivate_invalid_plugin', 'deactivate_sitewide_plugin' ); - -/** - * add_sitewide_activate_row() - * - * Adds the "Activate plugin site wide" row for each plugin in the inactive plugins list. - */ -function add_sitewide_activate_row( $file, $plugin_data, $context ) { - if ( !is_super_admin() ) - return false; - - if ( 'sitewide-active' == $context ) - return false; - - if ( is_plugin_active( $file ) ) - return false; - - echo ''; - - echo '↑ ' . sprintf( __( 'Activate %s Site Wide' ), strip_tags( $plugin_data["Title"] ) ) . ''; - echo ''; -} -add_action( 'after_plugin_row', 'add_sitewide_activate_row', 9, 3 ); - -/** - * is_wpmu_sitewide_plugin() - * - * Checks for "Site Wide Only: true" in the plugin header to see if this should - * be activated as a site wide MU plugin. - */ -function is_wpmu_sitewide_plugin( $file ) { - /* Open the plugin file for reading to check if this is a ms-plugin. */ - $fp = @fopen( WP_PLUGIN_DIR . '/' . $file, 'r' ); - - /* Pull only the first 8kiB of the file in. */ - $plugin_data = @fread( $fp, 8192 ); - - /* PHP will close file handle, but we are good citizens. */ - @fclose($fp); - - if ( preg_match( '|Site Wide Only:(.*)true$|mi', $plugin_data ) ) - return true; - return false; } - /** - * list_activate_sitewide_plugins() - * - * Lists all the plugins that have been activated site wide. + * @deprecated */ -function list_activate_sitewide_plugins() { - $all_plugins = get_plugins(); - - if ( !is_super_admin() ) - return false; - - $active_sitewide_plugins = maybe_unserialize( get_site_option( 'active_sitewide_plugins') ); - $context = 'sitewide-active'; - - if ( $active_sitewide_plugins ) { -?> -

- -

- - - - - - - - - - - - - - - - - - - - $activated_time ) { - $action_links = array(); - $action_links[] = '' . __('Deactivate') . ''; - - if ( current_user_can('edit_plugins') && is_writable(WP_PLUGIN_DIR . '/' . $plugin_file) ) - $action_links[] = '' . __('Edit') . ''; - - $action_links = apply_filters( 'plugin_action_links', $action_links, $plugin_file, $plugin_data, $context ); - $action_links = apply_filters( "plugin_action_links_$plugin_file", $action_links, $plugin_file, $plugin_data, $context ); - - $plugin_data = $all_plugins[$plugin_file]; - - echo " - - - - - - - - - - \n"; - - do_action( 'after_plugin_row', $plugin_file, $plugin_data, $context ); - do_action( "after_plugin_row_$plugin_file", $plugin_file, $plugin_data, $context ); - } - ?> - -
 
 
 {$plugin_data['Name']}

{$plugin_data['Description']}

"; - echo '
'; - foreach ( $action_links as $action => $link ) { - $sep = end($action_links) == $link ? '' : ' | '; - echo "$link$sep"; - } - echo "
"; - $plugin_meta = array(); - if ( !empty($plugin_data['Version']) ) - $plugin_meta[] = sprintf(__('Version %s'), $plugin_data['Version']); - if ( !empty($plugin_data['Author']) ) { - $author = $plugin_data['Author']; - if ( !empty($plugin_data['AuthorURI']) ) - $author = '' . $plugin_data['Author'] . ''; - $plugin_meta[] = sprintf( __('By %s'), $author ); - } - if ( ! empty($plugin_data['PluginURI']) ) - $plugin_meta[] = '' . __('Visit plugin site') . ''; - - $plugin_meta = apply_filters('plugin_row_meta', $plugin_meta, $plugin_file, $plugin_data, $context); - echo implode(' | ', $plugin_meta); - echo "
- -

- - $activated_time ) { - unset( $inactive_plugins[ $sitewide_plugin ] ); - } - - /* Now unset any sitewide only plugins if the user is not a site admin */ - if ( !is_super_admin() ) { - foreach ( $inactive_plugins as $plugin_name => $activated_time ) { - if ( is_wpmu_sitewide_plugin( $plugin_name ) ) - unset( $inactive_plugins[ $plugin_name ] ); - } - } - - return $inactive_plugins; +function is_wpmu_sitewide_plugin( $file ) { + return is_network_only_plugin( $file ); } -add_filter( 'all_plugins', 'sitewide_filter_inactive_plugins_list' ); /** - * sitewide_filter_active_plugins_list() - * - * Filters the active plugins list so that it doesn't include plugins that have - * been activated site wide instead of the specific blog. - */ -function sitewide_filter_active_plugins_list( $active_plugins ) { - $active_sitewide_plugins = (array) maybe_unserialize( get_site_option('active_sitewide_plugins') ); - - foreach ( $active_sitewide_plugins as $sitewide_plugin => $activated_time ) { - unset( $active_plugins[ $sitewide_plugin ] ); - } - - return $active_plugins; -} -add_filter( 'all_plugins', 'sitewide_filter_active_plugins_list' ); - -/** - * check_is_wpmu_plugin_on_activate() - * - * When a plugin is activated, this will check if it should be activated site wide - * only. + * @deprecated */ function check_is_wpmu_plugin_on_activate() { - /*** - * On plugin activation on a blog level, check to see if this is actually a - * site wide MU plugin. If so, deactivate and activate it site wide. - */ - if ( is_wpmu_sitewide_plugin( $_GET['plugin'] ) || isset( $_GET['sitewide'] ) ) { - deactivate_plugins( $_GET['plugin'], true ); - - /* Silently activate because the activate_* hook has already run. */ - if ( is_super_admin() ) { - $_GET['sitewide'] = true; - activate_sitewide_plugin( $_GET['plugin'], true ); - } - } + return; } -// @todo Throws warning if plugin is not set. Kinda janky. -//add_action( 'activate_' . $_GET['plugin'], 'check_is_wpmu_plugin_on_activate' ); /** - * check_wpmu_plugins_on_bulk_activate() + * @deprecated */ function check_wpmu_plugins_on_bulk_activate( $plugins ) { - if ( $plugins ) { - foreach ( $plugins as $plugin ) { - if ( is_wpmu_sitewide_plugin( $plugin ) ) { - deactivate_plugins( $plugin ); - - if ( is_super_admin() ) - activate_sitewide_plugin( $plugin ); - } - } - } + return; } function choose_primary_blog() { diff --git a/wp-admin/includes/plugin.php b/wp-admin/includes/plugin.php index a73bed751e..3466e291ab 100644 --- a/wp-admin/includes/plugin.php +++ b/wp-admin/includes/plugin.php @@ -262,6 +262,52 @@ function is_plugin_active( $plugin ) { return in_array( $plugin, apply_filters( 'active_plugins', get_option( 'active_plugins', array() ) ) ); } +/** + * Check whether the plugin is active for the entire network. + * + * @since 3.0.0 + * + * @param string $plugin Base plugin path from plugins directory. + * @return bool True, if active for the network, otherwise false. + */ +function is_plugin_active_for_network( $plugin ){ + if ( !is_multisite() ) + return false; + + $plugins = get_site_option( 'active_sitewide_plugins'); + if ( isset($plugins[$plugin]) ) + return true; + + return false; +} + +/** + * Checks for "Site Wide Only: true" in the plugin header to see if this should + * be activated as a network wide MU plugin. + * + * @since 3.0.0 + * + * @todo Use API for getting arbitrary plugin headers. + * + * @param $file Plugin to check + * $return bool True if plugin is network only, false otherwise. + */ +function is_network_only_plugin( $file ) { + /* Open the plugin file for reading to check if this is a ms-plugin. */ + $fp = @fopen( WP_PLUGIN_DIR . '/' . $file, 'r' ); + + /* Pull only the first 8kiB of the file in. */ + $plugin_data = @fread( $fp, 8192 ); + + /* PHP will close file handle, but we are good citizens. */ + @fclose($fp); + + if ( preg_match( '|Site Wide Only:(.*)true$|mi', $plugin_data ) ) + return true; + + return false; +} + /** * Attempts activation of plugin in a "sandbox" and redirects on success. * @@ -284,12 +330,19 @@ function is_plugin_active( $plugin ) { * * @param string $plugin Plugin path to main plugin file with plugin data. * @param string $redirect Optional. URL to redirect to. + * @param bool $network_wide Whether to enable the plugin for all sites in the network or just the current site. Multisite only. Default is false. * @return WP_Error|null WP_Error on invalid file or null on success. */ -function activate_plugin( $plugin, $redirect = '' ) { - $current = get_option( 'active_plugins', array() ); +function activate_plugin( $plugin, $redirect = '', $network_wide = false) { $plugin = plugin_basename( trim( $plugin ) ); + if ( is_multisite() && ( $network_wide || is_network_only_plugin($plugin) ) ) { + $network_wide = true; + $current = get_site_option( 'active_sitewide_plugins', array() ); + } else { + $current = get_option( 'active_plugins', array() ); + } + $valid = validate_plugin($plugin); if ( is_wp_error($valid) ) return $valid; @@ -299,10 +352,15 @@ function activate_plugin( $plugin, $redirect = '' ) { wp_redirect(add_query_arg('_error_nonce', wp_create_nonce('plugin-activation-error_' . $plugin), $redirect)); // we'll override this later if the plugin can be included without fatal error ob_start(); @include(WP_PLUGIN_DIR . '/' . $plugin); - $current[] = $plugin; - sort($current); do_action( 'activate_plugin', trim( $plugin) ); - update_option('active_plugins', $current); + if ( $network_wide ) { + $current[$plugin] = time(); + update_site_option( 'active_sitewide_plugins', $current ); + } else { + $current[] = $plugin; + sort($current); + update_option('active_plugins', $current); + } do_action( 'activate_' . trim( $plugin ) ); do_action( 'activated_plugin', trim( $plugin) ); ob_end_clean(); @@ -323,7 +381,9 @@ function activate_plugin( $plugin, $redirect = '' ) { * @param bool $silent Optional, default is false. Prevent calling deactivate hook. */ function deactivate_plugins( $plugins, $silent = false ) { + $network_current = get_site_option( 'active_sitewide_plugins', array() ); $current = get_option( 'active_plugins', array() ); + $do_blog = $do_network = false; foreach ( (array) $plugins as $plugin ) { $plugin = plugin_basename($plugin); @@ -332,10 +392,18 @@ function deactivate_plugins( $plugins, $silent = false ) { if ( ! $silent ) do_action( 'deactivate_plugin', trim( $plugin ) ); - $key = array_search( $plugin, (array) $current ); + if ( is_plugin_active_for_network($plugin) ) { + // Deactivate network wide + $do_network = true; + unset($network_current[$plugin]); + } else { + // Deactivate for this blog only + $do_blog = true; + $key = array_search( $plugin, (array) $current ); - if ( false !== $key ) - array_splice( $current, $key, 1 ); + if ( false !== $key ) + array_splice( $current, $key, 1 ); + } //Used by Plugin updater to internally deactivate plugin, however, not to notify plugins of the fact to prevent plugin output. if ( ! $silent ) { @@ -344,7 +412,10 @@ function deactivate_plugins( $plugins, $silent = false ) { } } - update_option('active_plugins', $current); + if ( $do_blog ) + update_option('active_plugins', $current); + if ( $do_network ) + update_site_option( 'active_sitewide_plugins', $network_current ); } /** diff --git a/wp-admin/plugins.php b/wp-admin/plugins.php index 00edbc26dd..c480ec47b0 100644 --- a/wp-admin/plugins.php +++ b/wp-admin/plugins.php @@ -27,7 +27,7 @@ $default_status = get_user_option('plugins_last_view'); if ( empty($default_status) ) $default_status = 'all'; $status = isset($_REQUEST['plugin_status']) ? $_REQUEST['plugin_status'] : $default_status; -if ( !in_array($status, array('all', 'active', 'inactive', 'recent', 'upgrade', 'search')) ) +if ( !in_array($status, array('all', 'active', 'inactive', 'recent', 'upgrade', 'network', 'search')) ) $status = 'all'; if ( $status != $default_status && 'search' != $status ) update_usermeta($current_user->ID, 'plugins_last_view', $status); @@ -38,6 +38,10 @@ $page = isset($_REQUEST['paged']) ? $_REQUEST['paged'] : 1; $_SERVER['REQUEST_URI'] = remove_query_arg(array('error', 'deleted', 'activate', 'activate-multi', 'deactivate', 'deactivate-multi', '_error_nonce'), $_SERVER['REQUEST_URI']); if ( !empty($action) ) { + $network_wide = false; + if ( isset($_GET['networkwide']) && is_multisite() && is_super_admin() ) + $network_wide = true; + switch ( $action ) { case 'activate': if ( ! current_user_can('activate_plugins') ) @@ -45,7 +49,7 @@ if ( !empty($action) ) { check_admin_referer('activate-plugin_' . $plugin); - $result = activate_plugin($plugin, 'plugins.php?error=true&plugin=' . $plugin); + $result = activate_plugin($plugin, 'plugins.php?error=true&plugin=' . $plugin, $network_wide); if ( is_wp_error( $result ) ) wp_die($result); @@ -71,7 +75,7 @@ if ( !empty($action) ) { exit; } - activate_plugins($plugins, 'plugins.php?error=true'); + activate_plugins($plugins, 'plugins.php?error=true', $network_wide); $recent = (array)get_option('recently_activated'); foreach ( $plugins as $plugin => $time) @@ -340,6 +344,7 @@ $inactive_plugins = array(); $recent_plugins = array(); $recently_activated = get_option('recently_activated', array()); $upgrade_plugins = array(); +$network_plugins = array(); set_transient( 'plugin_slugs', array_keys($all_plugins), 86400 ); @@ -353,12 +358,14 @@ $current = get_site_transient( 'update_plugins' ); foreach ( (array)$all_plugins as $plugin_file => $plugin_data) { - //Translate, Apply Markup, Sanitize HTML + // Translate, Apply Markup, Sanitize HTML $plugin_data = _get_plugin_data_markup_translate($plugin_file, $plugin_data, false, true); $all_plugins[ $plugin_file ] = $plugin_data; - //Filter into individual sections - if ( is_plugin_active($plugin_file) ) { + // Filter into individual sections + if ( is_plugin_active_for_network($plugin_file) && is_super_admin() ) { + $network_plugins[ $plugin_file ] = $plugin_data; + } elseif ( is_plugin_active($plugin_file) ) { $active_plugins[ $plugin_file ] = $plugin_data; } else { if ( isset( $recently_activated[ $plugin_file ] ) ) // Was the plugin recently activated? @@ -378,6 +385,7 @@ $total_inactive_plugins = count($inactive_plugins); $total_active_plugins = count($active_plugins); $total_recent_plugins = count($recent_plugins); $total_upgrade_plugins = count($upgrade_plugins); +$total_network_plugins = count($network_plugins); //Searching. if ( isset($_GET['s']) ) { @@ -408,7 +416,7 @@ if ( empty($$plugin_array_name) && $status != 'all' ) { $plugins = &$$plugin_array_name; -//Paging. +// Paging. $total_this_page = "total_{$status}_plugins"; $total_this_page = $$total_this_page; $plugins_per_page = (int) get_user_option( 'plugins_per_page' ); @@ -470,13 +478,25 @@ function print_plugins_table($plugins, $context = '') { foreach ( (array)$plugins as $plugin_file => $plugin_data) { $actions = array(); $is_active = is_plugin_active($plugin_file); + $is_active_for_network = is_plugin_active_for_network($plugin_file); - if ( $is_active ) - $actions[] = '' . __('Deactivate') . ''; - else + if ( $is_active_for_network && !is_super_admin() ) + continue; + + if ( $is_active ) { + if ( $is_active_for_network ) { + if ( is_super_admin() ) + $actions[] = '' . __('Network Deactivate') . ''; + } else { + $actions[] = '' . __('Deactivate') . ''; + } + } else { $actions[] = '' . __('Activate') . ''; + if ( is_multisite() && is_super_admin() ) + $actions[] = '' . __('Network Activate') . ''; + } - if ( current_user_can('edit_plugins') && is_writable(WP_PLUGIN_DIR . '/' . $plugin_file) ) + if ( !is_multisite() && current_user_can('edit_plugins') && is_writable(WP_PLUGIN_DIR . '/' . $plugin_file) ) $actions[] = '' . __('Edit') . ''; if ( ! $is_active && current_user_can('delete_plugins') ) @@ -592,6 +612,10 @@ if ( ! empty($inactive_plugins) ) { $class = ( 'inactive' == $status ) ? ' class="current"' : ''; $status_links[] = "
  • " . sprintf( _n( 'Inactive (%s)', 'Inactive (%s)', $total_inactive_plugins ), number_format_i18n( $total_inactive_plugins ) ) . ''; } +if ( ! empty($network_plugins) ) { + $class = ( 'network' == $status ) ? ' class="current"' : ''; + $status_links[] = "
  • " . sprintf( _n( 'Network (%s)', 'Network (%s)', $total_network_plugins ), number_format_i18n( $total_network_plugins ) ) . ''; +} if ( ! empty($upgrade_plugins) ) { $class = ( 'upgrade' == $status ) ? ' class="current"' : ''; $status_links[] = "
  • " . sprintf( _n( 'Upgrade Available (%s)', 'Upgrade Available (%s)', $total_upgrade_plugins ), number_format_i18n( $total_upgrade_plugins ) ) . '';