2

I apologize for the weakness of my search-fu if this has been answered already.

I'm in the process of cleaning up and updating an aging multisite installation. One step in this is to identify and remove plugins that are no longer needed or just don't work. Unfortunately, most of these plugins were activated on a per-site basis and there are enough sites to make manual deactivation too impractical.

I could, of course, just delete the plugin directories and move on but since some of the plugins have deactivation/uninstall hooks I'd rather have the plugins clean up after themselves first.

Is there an elegant way of doing so? I guess I could look up the relevant functions and write a script to walk all sites and deactivate the plugins in question but if there's a better way I'd prefer that.

2 Answers 2

1

I went through with the "walk all blogs" plan. My code is crude but it works.

First, I took the plugin enumeration function from the Plugin Activation Status plugin. Since that plugin does nothing but list which plugin is active where it was a convenient place to get the functionality from.

My version of the function was cut down in scope and merely returns an associative array with the blog ID as the key and an array of plugin basenames as the value. Network-wide plugins are included under the "network" key.

// Note: Since the source plugin is licensed under GPLv2 or later, so is this snippet.
function parse_plugins() {
global $wpdb;

$blogs = $wpdb->get_col( "SELECT blog_id FROM {$wpdb->blogs} ORDER BY blog_id" );
$network_plugins = $wpdb->get_results( $wpdb->prepare( "SELECT site_id, meta_value FROM {$wpdb->sitemeta} WHERE meta_key=%s", 'active_sitewide_plugins' ) );

$active = array('network' => array());

foreach ( $network_plugins as $k => $val ) {

    $v = maybe_unserialize( $val->meta_value );

    if ( ! is_array( $v ) )
        continue;
    if ( count( v ) <= 0 )
        continue;

    $tmp = array_values( $v );
    /**
        * Some records are stored with the plugin name as the key & the timestamp 
        *       of activation as the value; others are stored with just the plugin 
        *       name as the value, with numeric keys
        */
    $v = is_numeric( $tmp[0] ) ? array_keys( $v ) : array_values( $v );
    $active['network'] = array_merge( $active['network'], $v );
}

/**
    * Retrieve all of the plugins active on individual sites
    */
foreach ( $blogs as $b ) {
    $wpdb->set_blog_id( $b );

    $plugins = maybe_unserialize( $wpdb->get_var( $wpdb->prepare( "SELECT option_value FROM {$wpdb->options} WHERE option_name=%s", 'active_plugins' ) ) );
    if ( ! is_array( $plugins ) )
        continue;
    $tmp = array_values( $plugins );
    if ( count( $tmp ) <= 0 )
        continue;
    /**
        * Some records are stored with the plugin name as the key & the timestamp 
        *       of activate as the value; others are stored with just the plugin 
        *       name as the value, with numeric keys
        */
    $plugins = is_numeric( $tmp[0] ) ? array_keys( $plugins ) : array_values( $plugins );
    $active[$b] = $plugins;
}

return $active;

}

Now that we know which plugin is active where we can walk the network and deactivate them.

function deactivate_all_the_plugins()
{
    $active_plugins = parse_plugins();

    // Add the basenames of all unwanted plugins here
    $target_plugins = array(
    'hello.php',
    'akismet/akismet.php',
    'some-other-plugin/other_plugin.php'
    );

    foreach ($active_plugins as $blog_id => $blog_plugins) {
        $plugins = array_intersect($target_plugins, $blog_plugins);

        if (!empty($plugins)) {
            if ($blog_id == 'network') {
                deactivate_plugins($plugins, false, true);
            }
            else {
                switch_to_blog($blog_id);
                deactivate_plugins($plugins, false, false);
                restore_current_blog();
            }
        }

        echo '<h1>'.$blog_id.'</h1>'; var_dump($plugins);
    }
}

I don't trigger uninstallation hooks here; the assumption is that the plugin will clean up sufficiently on deactivation. Also, I'm not certain on how to trigger them without actually running the "delete plugin" code and WordPress doesn't have the FTP credentials. Still, it's better than nothing.

0

For a little bit more overview the plugin WordPress-Multisite-Enhancements might help. This adds a column to view the activation in each site of the network. A screenshot will demonstrate the result. Screenshot of WordPress-Multisite-Enhancements with added column

Many plugins uninstall their data inside the database only if you delete the plugin on the UI of the back end. Only removing the folder deletes the plugin, but often not the database entries.

2
  • I know which blogs the plugins are active on (via a plugin similar to yours); what I need is to batch-disable/uninstall them. Thanks, though. Commented Jun 11, 2014 at 9:46
  • I have not a solution for this requirement. But I'm also interested for a solution.
    – bueltge
    Commented Jun 11, 2014 at 9:50

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.