如何使一个插件需要另一个插件?


30

我正在构建一个向主插件添加额外功能的插件。理想情况下,在插件管理屏幕中,应禁用“激活”链接,并应添加一个内联注释,以告知用户先安装和激活主插件,然后才能使用当前插件。


1
怎么样使用is_plugin_active()呢?例如: if (is_plugin_active('path/to/plugin.php')) { // Do something }
TomC

Answers:


35

谢谢你们的答案。尽管这两个答案都使我走上了正确的道路,但没有一个是开箱即用的。因此,我在下面分享我的解决方案。

方法1-使用register_activation_hook:

在plugins / parent-plugin / parent-plugin.php中创建父插件:

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

在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>');
    }
}

请注意,deactivate_plugins( $plugin );由于某种原因,我没有使用它不起作用。因此,我使用wp_die取消了激活重定向并通知了用户。

优点:

  • 简单的解决方案,与方法2相比,不会产生额外的数据库命中

缺点:

  • wp_die屏幕很丑
  • 如果您使用插件管理屏幕中的复选框同时激活了父插件和子插件,则wp_die屏幕仍会显示。

方法2-使用admin_init和admin_notices

在plugins / parent-plugin / parent-plugin.php中创建父插件:

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

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

优点:

  • 当您使用复选框同时激活父级和子级插件时有效

坏处:

  • 由于该插件最初首先被激活,并且在admin_init运行后被停用,因此产生了额外的数据库命中。

关于禁用激活链接的问题,我可以使用:

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

但是,事实证明这是不切实际的,因为没有地方放置此代码。我无法将其放在父插件上,因为父插件应该处于活动状态才能运行此代码。当然不属于子插件或functions.php。所以我放弃了这个主意。


1
方法2效果很好!我用它来扩展别人的插件。
Collin Price

2

已评论,请尝试一下,这样可以帮助您理解。

<?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'
    }
}
?> 

如果抛出错误,您还可以检查“ myplugin”的“ option”并将其设置为false或未激活。


2

两种建议的解决方案都有缺陷。

方法1:如前所述,当使用插件管理屏幕中的复选框同时激活父插件和子插件时,wp_die()屏幕仍会显示。

方法2:在某些用例中,这不好,因为在“ plugins_loaded”(https://codex.wordpress.org/Plugin_API/Action_Reference)之后和卸载钩子(https:// codex。)之后执行了“ admin_init” 。 wordpress.org/Function_Reference/register_uninstall_hook)。因此,例如,如果我们确实希望插件在卸载时运行某些代码(无论父插件是否处于活动状态),则此方法将不起作用。

解:

首先,我们需要将以下代码附加到父插件的主PHP文件的末尾:

do_action( 'my_plugin_loaded' );

这将向所有订阅者发送事件/信号,告知核心插件已加载。

然后,加载项的类应如下所示:

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

希望能帮助到你 :)


4
这个答案也有缺陷。:-)假设您完全控制了父插件,可以在其中添加do_action('my_plugin_loaded'); 在其代码中。选定的答案将在父插件不受控制的情况下起作用(例如,父插件不是您自己的插件)
kosinix

谢谢,这正是我想要的。就我而言,我确实可以完全控制父插件,因此需要创建这种依赖关系。
cr0ybot

0

我认为您需要TGM插件激活

TGM插件激活是一个PHP库,可让您轻松地为WordPress主题(和插件)要求或推荐插件。它允许您的用户使用本机WordPress类,函数和界面以单例或批量方式安装,更新甚至自动激活插件。您可以引用捆绑的插件,来自WordPress插件存储库的插件,甚至可以引用Internet上其他位置托管的插件。


链接错误。正确的链接在这里
XedinUnknown
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.