How to make a plugin require another plugin?

I’m building a plugin that adds extra functionality to a main plugin. Ideally in the plugins administration screen, the “activate” link should be disabled and an inline note should be added that tells the user to install and activate the main plugin first before he/she can use the current plugin.

Related posts

4 comments

  1. Thanks for the answers guys. Though both answers set me on the right path, none worked out of the box. So I’m sharing my solutions below.

    Method 1 – Using register_activation_hook:

    Create the Parent Plugin in plugins/parent-plugin/parent-plugin.php:

    <?php
    /*
    Plugin Name: Parent Plugin
    Description: Demo plugin with a dependent child plugin.
    Version: 1.0.0
    */
    

    Create the Child Plugin in plugins/child-plugin/child-plugin.php:

    <?php
    /*
    Plugin Name: Child Plugin
    Description: Parent Plugin should be installed and active to use this plugin.
    Version: 1.0.0
    */
    register_activation_hook( __FILE__, 'child_plugin_activate' );
    function child_plugin_activate(){
    
        // Require parent plugin
        if ( ! is_plugin_active( 'parent-plugin/parent-plugin.php' ) and current_user_can( 'activate_plugins' ) ) {
            // Stop activation redirect and show error
            wp_die('Sorry, but this plugin requires the Parent Plugin to be installed and active. <br><a href="' . admin_url( 'plugins.php' ) . '">&laquo; Return to Plugins</a>');
        }
    }
    

    Notice that I’m not using deactivate_plugins( $plugin ); as for some reason it does not work. So I used wp_die to cancel the activation redirection and inform the user.

    Advantage:

    • Simple solution and does not incur additional db hits compared to method 2

    Disadvantages:

    • wp_die screen is ugly
    • wp_die screen will STILL show up if you activated the Parent Plugin and Child Plugin at the same time using the checkboxes in the plugins admin screen.

    Method 2 – Using admin_init and admin_notices

    Create the Parent Plugin in plugins/parent-plugin/parent-plugin.php:

    <?php
    /*
    Plugin Name: Parent Plugin
    Description: Demo plugin with a dependent child plugin.
    Version: 1.0.0
    */
    

    Create the Child Plugin in plugins/child-plugin/child-plugin.php:

    <?php
    /*
    Plugin Name: Child Plugin
    Description: Parent Plugin should be installed and active to use this plugin.
    Version: 1.0.0
    */
    add_action( 'admin_init', 'child_plugin_has_parent_plugin' );
    function child_plugin_has_parent_plugin() {
        if ( is_admin() && current_user_can( 'activate_plugins' ) &&  !is_plugin_active( 'parent-plugin/parent-plugin.php' ) ) {
            add_action( 'admin_notices', 'child_plugin_notice' );
    
            deactivate_plugins( plugin_basename( __FILE__ ) ); 
    
            if ( isset( $_GET['activate'] ) ) {
                unset( $_GET['activate'] );
            }
        }
    }
    
    function child_plugin_notice(){
        ?><div class="error"><p>Sorry, but Child Plugin requires the Parent plugin to be installed and active.</p></div><?php
    }
    

    Advantage:

    • Works when you activate the Parent and Child plugin at the same time using checkboxes

    Disadvantage:

    • Incur additional db hits as the plugin is actually activated at first and deactivated once admin_init runs.

    As for my question regarding disabling the activate link, I could use:

    add_filter( 'plugin_action_links', 'disable_child_link', 10, 2 );
    function disable_child_link( $links, $file ) {
    
        if ( 'child-plugin/child-plugin.php' == $file and isset($links['activate']) )
            $links['activate'] = '<span>Activate</span>';
    
        return $links;
    }
    

    However, it turned out to be highly impractical as there is NO place to put this code. I could not put it on the parent plugin as the parent plugin should be active for this code to run. Certainly does not belong to child plugin or functions.php. So I’m scrapping this idea.

  2. Both of the suggested solutions have flaws.

    Method 1: As mentioned, wp_die() screen will STILL show up when the Parent Plugin and Child Plugin activated at the same time using the checkboxes in the plugins admin screen.

    Method 2: In some use-cases it’s not good since ‘admin_init’ is executed way after ‘plugins_loaded’ (https://codex.wordpress.org/Plugin_API/Action_Reference), and after the uninstallation hook (https://codex.wordpress.org/Function_Reference/register_uninstall_hook). So for example, if we do want the add-on to run some code on uninstallation whether the parent plugin is active or not, this approach will NOT work.

    Solution:

    First of all, we need to append the following code to the end of the parent plugin’s main PHP file:

    do_action( 'my_plugin_loaded' );
    

    This will dispatch an event/signal to all subscribers, telling that the core plugin was loaded.

    Then, the add-on’s class should look like the following:

    class My_Addon
    {
        static function init ()
        {
            register_activation_hook( __FILE__, array( __CLASS__, '_install' ) );
    
            if ( ! self::_is_parent_active_and_loaded() ) {
                return;
            }
        }
    
        #region Parent Plugin Check
    
        /**
         * Check if parent plugin is activated (not necessarly loaded).
         *
         * @author Vova Feldman (@svovaf)
         *
         * @return bool
         */
        static function _is_parent_activated()
        {
            $active_plugins_basenames = get_option( 'active_plugins' );
            foreach ( $active_plugins_basenames as $plugin_basename ) {
                if ( false !== strpos( $plugin_basename, '/my-plugin-main-file.php' ) ) {
                    return true;
                }
            }
    
            return false;
        }
    
        /**
         * Check if parent plugin is active and loaded.
         *
         * @author Vova Feldman (@svovaf)
         *
         * @return bool
         */
        static function _is_parent_active_and_loaded()
        {
            return class_exists( 'My_Plugin' );
        }
    
        /**
         *
         * @author Vova Feldman (@svovaf)
         */
        static function _install()
        {
            if ( ! self::_is_parent_active_and_loaded() ) {
                deactivate_plugins( basename( __FILE__ ) );
    
                // Message error + allow back link.
                wp_die( __( 'My Add-on requires My Plugin to be installed and activated.' ), __( 'Error' ), array( 'back_link' => true ) );
            }
        }
    
        #endregion Parent Plugin Check
    }
    
    if (My_Addon::_is_parent_active_and_loaded())
    {
        // If parent plugin already included, init add-on.
        My_Addon::init();
    }
    else if (My_Addon::_is_parent_activated())
    {
        // Init add-on only after the parent plugins is loaded.
        add_action( 'my_plugin_loaded', array( __CLASS__, 'init' ) );
    }
    else
    {
        // Even though the parent plugin is not activated, execute add-on for activation / uninstall hooks.
        My_Addon::init();
    }
    

    Hope it helps 🙂

  3. Try this out, it’s commented, so that should help you understand it.

    <?php
    register_activation_hook( __FILE__, 'myplugin_activate' ); // Register myplugin_activate on
    function myplugin_activate() {
        $plugin = plugin_basename( __FILE__ ); // 'myplugin'
        if ( is_plugin_active( 'plugin-directory/first-plugin.php' ) ) {
            // Plugin was active, do hook for 'myplugin'
        } else {
            // Plugin was not-active, uh oh, do not allow this plugin to activate
            deactivate_plugins( $plugin ); // Deactivate 'myplugin'
        }
    }
    ?> 
    

    If this throws out an error, you could also check the ‘option’ of ‘myplugin’ and set it to false or not activated.

  4. I think you need TGM Plugin Activation.

    TGM Plugin Activation is a PHP library that allows you to easily
    require or recommend plugins for your WordPress themes (and plugins).
    It allows your users to install, update and even automatically
    activate plugins in singular or bulk fashion using native WordPress
    classes, functions and interfaces. You can reference bundled plugins,
    plugins from the WordPress Plugin Repository or even plugins hosted
    elsewhere on the internet.

Comments are closed.