Typically the plugins I write are not standalone but require other plugins such as WooCommerce to be enabled to work correctly. So before I run my plugin, I need to check if the plugin I depend on is activated. In a multisite environment this gets a bit more complicated.

If my own plugin is networkwide activated, then I require for the plugin I depend on to also be network activated. In theory it is possible for a plugin to be locally activated on all sites within the network, but if that’s the case then my assumption is that the admin will continue to follow the same logic and activate my plugin also locally.

If my plugin is locally activated, then the plugin I require can either be networkwide activated or locally. This gives the admin the choice to run the plugin I depend on networkwide, but my plugin only locally on a specific site.

To test if the plugin I need is activated I can use the following two WP functions:

is_plugin_active_for_network() does exactly this. It checks if the plugin is activated networkwide and returns TRUE if that’s the case. The WP codex shows in the source code how that’s done:

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;
}

is_plugin_active() confused me at first. My assumption was that this function checks if a plugin is locally activated but that’s not the case. This function multitasks and checks if a plugin is either networkwide or locally activated. Either will return TRUE. The WP codex source code shows how this works:

function is_plugin_active( $plugin ) {
    return in_array( $plugin, (array) get_option( 'active_plugins', array() ) ) 
    || is_plugin_active_for_network( $plugin );
}

Checking if Woo is enabled

Putting this in practice, this is the code I use in my plugin to check if WooCommerce is enabled:

// Makes sure the plugin is defined before trying to use it
 $need = false;
		
if ( ! function_exists( 'is_plugin_active_for_network' ) ) {
  require_once( ABSPATH . '/wp-admin/includes/plugin.php' );
}
	
// multisite && this plugin is locally activated - Woo can be network or locally activated 
if ( is_multisite() && is_plugin_active_for_network( plugin_basename(__FILE__) )  ) {
  // this plugin is network activated - Woo must be network activated 
    $need = is_plugin_active_for_network('woocommerce/woocommerce.php') ? false : true; 
// this plugin runs on a single site || is locally activated 
} else {
  $need =  is_plugin_active( 'woocommerce/woocommerce.php') ? false : true; 	
}
	
if ($need === true) {
  add_action( 'admin_notices', 'need_woocommerce' );
  return; 
}

And the error message function like the code below. Note that I added the “is-dismissible” class to enable the close icon top right of the warning message. For more details on how to structure WP Admin notices please see https://developer.wordpress.org/reference/hooks/admin_notices/.

function need_woocommerce() {
    ?>
   <div class="notice notice-error is-dismissible">
       <p>
           <?php echo sprintf( __('Stock Control for WooCommerce requires WooCommerce. 
Please install and activate the  %sWooCommerce%s plugin', 'foo'),
 '<a href="https://wordpress.org/extend/plugins/woocommerce/">', '</a>'); ?> 
       </p>
   </div>
   <?php
}

Database structure

If like me you like to head right over to the DB to see how Woo stores this data, this is the structure for storing networkwide and locally activated plugins.

Networkwide plugins are stored in the table “prefix_sitemeta” with meta_key “active_sitewide_plugins”, and the site_id of the primary site (in my case 1).

Image shows database table "sitemeta" with meta_key "active_sitewide_plugins"

Locally activated plugins are stored in the table “prefix_options” for the primary site; and “prefix_siteID_options” for the other sites with option_name “active_plugins”.

De-activtating plugin (dependency check)

UPDATE: March 2022. I’ve added this section on de-activating plugin and cleaned up the code above.

WordPress is currently trialling a feature plugin for dependency checking. Unfortunately the scope only applies to plugins in the WP plugin directory but WP has indicated that once it’s a stable feature it could be rolled out to all plugins. To follow the discussion see https://make.wordpress.org/core/2022/02/24/feature-project-plugin-dependencies/

For my own plugin I wanted to exented the functionality to de-activate the plugin if the required dependency (in my case WooCommerce) was not activated. This meant that the remainder of the plugin could rely on the WC class being available and I did not need to check in every function separately.

Adding a de-activation is simple. In the same code where I checked if Woo was activated and display an error message if not, I added a condition to de-activate. And I moved the run() command for my main plugin class into the if / else statement to only executie if dependencies are met. The resulting code looks like this:

$need = false; // do we need Woo?
$network = false; // is plugin activated at network level? 
          
 if ( ! function_exists( 'is_plugin_active_for_network' ) ) {
   require_once( ABSPATH . '/wp-admin/includes/plugin.php' );
 }
      
 // Multisite && this plugin is network activated - Woo must be network activated 
 if ( is_multisite() && is_plugin_active_for_network( plugin_basename(__FILE__) ) ) {
    $need = is_plugin_active_for_network('woocommerce/woocommerce.php') ? false : true; 
    $network = true; 
 // This plugin runs on a single site || is locally activated 
 } else {
   $need =  is_plugin_active( 'woocommerce/woocommerce.php') ? false : true;     
 }
      
 if ($need === true) {
    add_action( 'admin_notices',  'need_woocommerce' );
    deactivate_plugins( plugin_basename( __FILE__ ) , false, $network );
 } else {
    // Good to go!
    $plugin = new SCW_Stock_Control_For_WooCommerce();
    $plugin->run(); 
 }

deactivate_plugins() handles the de-activation of a single or multiple (array) of plugins. The second parameter sets if the function should prevent the calling of the deactivation hook, and the third parameter sets if the plugin should be disabled networkwide if multisite. For my code I’ve set the third parameter to a variable which is true if the plugin is networkwide activated. This approach could be extended to eg check PHP version compatibility, WordPress version compatibility etc.

PS: If you use namespaces then the add_action would look like this:

if ($need === true) {
    add_action( 'admin_notices',  __NAMESPACE__ . '\\need_woocommerce' );
    deactivate_plugins( plugin_basename( __FILE__ ) , false, $network );
 } 

One response to “How to check if WooCommerce is activated on WP multisite”

Leave a Reply

Your email address will not be published.