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
This commit is contained in:
ryan 2010-01-29 21:45:32 +00:00
parent 227168b639
commit 363da801f5
3 changed files with 126 additions and 273 deletions

View File

@ -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)
* @deprecated
*/
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;
return;
}
// @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 '<tr><td colspan="5" style="background: #f5f5f5; text-align: right;">';
echo '<a href="' . wp_nonce_url( admin_url( 'plugins.php?action=activate&amp;sitewide=1&amp;plugin=' . $file ), 'activate-plugin_' . $file ) . '" title="' . __( 'Activate this plugin for all blogs across the entire network' ) . '">&uarr; ' . sprintf( __( 'Activate %s Site Wide' ), strip_tags( $plugin_data["Title"] ) ) . '</a>';
echo '</td></tr>';
}
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.
* @deprecated is_network_only_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;
return is_network_only_plugin( $file );
}
/**
* list_activate_sitewide_plugins()
*
* Lists all the plugins that have been activated site wide.
*/
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 ) {
?>
<h3><?php _e( 'Currently Active Site Wide Plugins' ) ?></h3>
<p><?php _e( 'Plugins that appear in the list below are activate for all blogs across this installation.' ) ?></p>
<table class="widefat" cellspacing="0" id="<?php echo $context ?>-plugins-table">
<thead>
<tr>
<th scope="col" class="manage-column check-column">&nbsp;</th>
<th scope="col" class="manage-column"><?php _e('Plugin'); ?></th>
<th scope="col" class="manage-column"><?php _e('Description'); ?></th>
</tr>
</thead>
<tfoot>
<tr>
<th scope="col" class="manage-column check-column">&nbsp;</th>
<th scope="col" class="manage-column"><?php _e('Plugin'); ?></th>
<th scope="col" class="manage-column"><?php _e('Description'); ?></th>
</tr>
</tfoot>
<tbody class="plugins">
<?php
foreach ( (array) $active_sitewide_plugins as $plugin_file => $activated_time ) {
$action_links = array();
$action_links[] = '<a href="' . wp_nonce_url( 'plugins.php?action=deactivate&amp;sitewide=1&amp;plugin=' . $plugin_file, 'deactivate-plugin_' . $plugin_file ) . '" title="' . __('Deactivate this plugin site wide') . '">' . __('Deactivate') . '</a>';
if ( current_user_can('edit_plugins') && is_writable(WP_PLUGIN_DIR . '/' . $plugin_file) )
$action_links[] = '<a href="plugin-editor.php?file=' . $plugin_file . '" title="' . __('Open this file in the Plugin Editor') . '" class="edit">' . __('Edit') . '</a>';
$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 "
<tr class='$context' style='background: #eef2ff;'>
<th scope='row' class='check-column'>&nbsp;</th>
<td class='plugin-title'><strong>{$plugin_data['Name']}</strong></td>
<td class='desc'><p>{$plugin_data['Description']}</p></td>
</tr>
<tr class='$context second' style='background: #eef2ff;'>
<td></td>
<td class='plugin-title'>";
echo '<div class="row-actions-visible">';
foreach ( $action_links as $action => $link ) {
$sep = end($action_links) == $link ? '' : ' | ';
echo "<span class='$action'>$link$sep</span>";
}
echo "</div></td>
<td class='desc'>";
$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 = '<a href="' . $plugin_data['AuthorURI'] . '" title="' . __( 'Visit author homepage' ) . '">' . $plugin_data['Author'] . '</a>';
$plugin_meta[] = sprintf( __('By %s'), $author );
}
if ( ! empty($plugin_data['PluginURI']) )
$plugin_meta[] = '<a href="' . $plugin_data['PluginURI'] . '" title="' . __( 'Visit plugin site' ) . '">' . __('Visit plugin site') . '</a>';
$plugin_meta = apply_filters('plugin_row_meta', $plugin_meta, $plugin_file, $plugin_data, $context);
echo implode(' | ', $plugin_meta);
echo "</td>
</tr>\n";
do_action( 'after_plugin_row', $plugin_file, $plugin_data, $context );
do_action( "after_plugin_row_$plugin_file", $plugin_file, $plugin_data, $context );
}
?>
</tbody>
</table>
<p><?php _e( 'Plugins that are enabled site wide can only be disabled by a site administrator.' ) ?></p>
<?php
}
}
add_action( 'pre_current_active_plugins', 'list_activate_sitewide_plugins' );
/**
* sitewide_filter_inactive_plugins_list()
*
* Filters the inactive plugins list so that it doesn't include plugins that have
* been activated site wide, and not for the specific blog.
*/
function sitewide_filter_inactive_plugins_list( $inactive_plugins ) {
$active_sitewide_plugins = (array) maybe_unserialize( get_site_option('active_sitewide_plugins') );
foreach ( $active_sitewide_plugins as $sitewide_plugin => $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;
}
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() {

View File

@ -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);
do_action( 'activate_plugin', trim( $plugin) );
if ( $network_wide ) {
$current[$plugin] = time();
update_site_option( 'active_sitewide_plugins', $current );
} else {
$current[] = $plugin;
sort($current);
do_action( 'activate_plugin', trim( $plugin) );
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 ) );
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 );
}
//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 ) {
}
}
if ( $do_blog )
update_option('active_plugins', $current);
if ( $do_network )
update_site_option( 'active_sitewide_plugins', $network_current );
}
/**

View File

@ -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 )
if ( $is_active_for_network && !is_super_admin() )
continue;
if ( $is_active ) {
if ( $is_active_for_network ) {
if ( is_super_admin() )
$actions[] = '<a href="' . wp_nonce_url('plugins.php?action=deactivate&amp;networkwide=1&amp;plugin=' . $plugin_file . '&amp;plugin_status=' . $context . '&amp;paged=' . $page, 'deactivate-plugin_' . $plugin_file) . '" title="' . __('Deactivate this plugin') . '">' . __('Network Deactivate') . '</a>';
} else {
$actions[] = '<a href="' . wp_nonce_url('plugins.php?action=deactivate&amp;plugin=' . $plugin_file . '&amp;plugin_status=' . $context . '&amp;paged=' . $page, 'deactivate-plugin_' . $plugin_file) . '" title="' . __('Deactivate this plugin') . '">' . __('Deactivate') . '</a>';
else
}
} else {
$actions[] = '<a href="' . wp_nonce_url('plugins.php?action=activate&amp;plugin=' . $plugin_file . '&amp;plugin_status=' . $context . '&amp;paged=' . $page, 'activate-plugin_' . $plugin_file) . '" title="' . __('Activate this plugin') . '" class="edit">' . __('Activate') . '</a>';
if ( is_multisite() && is_super_admin() )
$actions[] = '<a href="' . wp_nonce_url('plugins.php?action=activate&amp;networkwide=1&amp;plugin=' . $plugin_file . '&amp;plugin_status=' . $context . '&amp;paged=' . $page, 'activate-plugin_' . $plugin_file) . '" title="' . __('Activate this plugin for all sites in this network') . '" class="edit">' . __('Network Activate') . '</a>';
}
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[] = '<a href="plugin-editor.php?file=' . $plugin_file . '" title="' . __('Open this file in the Plugin Editor') . '" class="edit">' . __('Edit') . '</a>';
if ( ! $is_active && current_user_can('delete_plugins') )
@ -592,6 +612,10 @@ if ( ! empty($inactive_plugins) ) {
$class = ( 'inactive' == $status ) ? ' class="current"' : '';
$status_links[] = "<li><a href='plugins.php?plugin_status=inactive' $class>" . sprintf( _n( 'Inactive <span class="count">(%s)</span>', 'Inactive <span class="count">(%s)</span>', $total_inactive_plugins ), number_format_i18n( $total_inactive_plugins ) ) . '</a>';
}
if ( ! empty($network_plugins) ) {
$class = ( 'network' == $status ) ? ' class="current"' : '';
$status_links[] = "<li><a href='plugins.php?plugin_status=network' $class>" . sprintf( _n( 'Network <span class="count">(%s)</span>', 'Network <span class="count">(%s)</span>', $total_network_plugins ), number_format_i18n( $total_network_plugins ) ) . '</a>';
}
if ( ! empty($upgrade_plugins) ) {
$class = ( 'upgrade' == $status ) ? ' class="current"' : '';
$status_links[] = "<li><a href='plugins.php?plugin_status=upgrade' $class>" . sprintf( _n( 'Upgrade Available <span class="count">(%s)</span>', 'Upgrade Available <span class="count">(%s)</span>', $total_upgrade_plugins ), number_format_i18n( $total_upgrade_plugins ) ) . '</a>';