What's a reliable way to depend on another plugin?

Currently, the way I do it is, on the plugins_loaded hook, I let the world know that my plugin has loaded:add_action( &#

Currently, the way I do it is, on the plugins_loaded hook, I let the world know that my plugin has loaded:

add_action( 'plugins_loaded', function() {
    do_action( 'my_plugin_has_loaded' );
}, 10 );

And so, others can depend/only run when my_plugin_has_loaded fires, however, I see a lot of hooks plugin_loaded (5.1.0) and even some plugins firing their init before plugins_loaded. Is there a better way to make a plugin wait for another?

The problem I see with this approach is that I launch my own init on plugins_loaded, however, I also see a silver lining - plugins are meant to be done loading here, so, if there'd be any type of logic like this, it'd be here.


Issue #1 - Using class_exists:

  1. I can't force naming conventions as I would do for actions, such as always looking/hooking for plugin-$name%:init to ensure consistency through actions. If I know a plugin's name, then I can very easily predict it's init point so that I can run after, but if I don't, I have to know what class is its main controller, which leads me to the next point -
  2. If I rely on this way of checking, I am merely looking for the existence of a class, which, at best, lets me know a plugin is activated, but not if the plugin has finished its setup. With an action I can arbitrarily decide when a plugin has finished loading and initializing all it needs such that dependants can run.

  3. Continuing from (2), I am now forcing myself to write plugins in such a way that I'd always need a god-mode-controller class that runs all its stuff on __construct. People who will do class_exists( 'MyClass\From\Plugin\IWanna\DependOn' )will also inherently assume that I run everything on __construct, however, my plugin my have errors in initializing itself, but, because it's all run on __cosntruct, I can't debug that.

Issue #2 - Using TGMPA:

  1. Assume plugin A dependend on plugin B. If the user disables B, then A will throw errors. Sure, I can handle them, but that's exactly the point of the question, really - reverse this point I just said and you reach my problem: ensuring dependency while handling each case in which you interact with plugins. I need this to be completely off user-land territory.

Currently, the way I do it is, on the plugins_loaded hook, I let the world know that my plugin has loaded:

add_action( 'plugins_loaded', function() {
    do_action( 'my_plugin_has_loaded' );
}, 10 );

And so, others can depend/only run when my_plugin_has_loaded fires, however, I see a lot of hooks plugin_loaded (5.1.0) and even some plugins firing their init before plugins_loaded. Is there a better way to make a plugin wait for another?

The problem I see with this approach is that I launch my own init on plugins_loaded, however, I also see a silver lining - plugins are meant to be done loading here, so, if there'd be any type of logic like this, it'd be here.


Issue #1 - Using class_exists:

  1. I can't force naming conventions as I would do for actions, such as always looking/hooking for plugin-$name%:init to ensure consistency through actions. If I know a plugin's name, then I can very easily predict it's init point so that I can run after, but if I don't, I have to know what class is its main controller, which leads me to the next point -
  2. If I rely on this way of checking, I am merely looking for the existence of a class, which, at best, lets me know a plugin is activated, but not if the plugin has finished its setup. With an action I can arbitrarily decide when a plugin has finished loading and initializing all it needs such that dependants can run.

  3. Continuing from (2), I am now forcing myself to write plugins in such a way that I'd always need a god-mode-controller class that runs all its stuff on __construct. People who will do class_exists( 'MyClass\From\Plugin\IWanna\DependOn' )will also inherently assume that I run everything on __construct, however, my plugin my have errors in initializing itself, but, because it's all run on __cosntruct, I can't debug that.

Issue #2 - Using TGMPA:

  1. Assume plugin A dependend on plugin B. If the user disables B, then A will throw errors. Sure, I can handle them, but that's exactly the point of the question, really - reverse this point I just said and you reach my problem: ensuring dependency while handling each case in which you interact with plugins. I need this to be completely off user-land territory.
Share Improve this question edited May 24, 2020 at 7:22 Daniel Simmons asked May 19, 2020 at 7:07 Daniel SimmonsDaniel Simmons 1741 silver badge10 bronze badges 5
  • Have you considered taking a look at TGM Plugin Activation? – Johansson Commented May 24, 2020 at 2:50
  • @JackJohansson This is a user-land plugin. I need something that, by code (without user interaction) works. – Daniel Simmons Commented May 24, 2020 at 2:57
  • in my opinion best way to depend on another plugin is classes or functions. if the plugin uses a specific class or function to initiliase, then it would be easy way. e.g if your plugin depends on woocommerce you can easily check whether woocommerce is loaded or not by simply runing class_exists('WooCommerce'); – Raashid Din Commented May 24, 2020 at 6:45
  • @RaashidDin I can't create a naming convention that's predictable with class names because people prefer different naming conventions for these. With actions, however, I can always ensure a format of plugin\$plugin_name$:init. Also, while this is personal preference, it's easier to reason about do an action (init) on another action in an event-driven system rather than do an action if class exists. Additionally, when I check for the class WooCommerce, it only implies its existence, not its loading, if I go this way, then I can't check if the plugin has actually initialized. – Daniel Simmons Commented May 24, 2020 at 7:10
  • @JackJohansson I've updated the question with details that I realized were very good points once I saw some comments. – Daniel Simmons Commented May 24, 2020 at 7:20
Add a comment  | 

3 Answers 3

Reset to default 4 +300

Consider plugin A:

$A_message;

add_action('plugins_loaded', function() {
    do_action('plugin-A:init');
});

// Hooks allow B to access A (both during initialization of A and elsewhere in WordPress) without having to check if A exists.

add_filter('plugin-A:set', function($msg) {
    $A_message = $msg;
}, PHP_INT_MAX);

add_filter('plugin-A:get', function($msg) {
    return $A_message;
}, PHP_INT_MIN);

Now, consider plugin B:

add_action('plugin-A:init', function() {
    // We're 100% sure that A has loaded (if it exists)
    // Store what Cheech says in A.  (Using a filter allows us to not have to check if A exists).
    do_action('plugin-A:set', "Brent! Open the door!");
});

add_filter('the_title', function($title) {
    // Get something from A (and we don't have to check if it exists).
    // If A exists, return what Cheech says; if A does not exist, return what Chong says.
    $title = apply_filters('plugin-A:get', "Dave's not here, man!");
    return $title;
});

Most of this code sounds like it is nothing new to you. When Foo is loaded, it initializes the Bar plugin by way of bar_on_plugins_loaded() and foo_load_bar(). What is new here is that Foo does not need to do any fancy checks to see if Bar exists or not. This is because foo_load_bar() executes a hook that is defined by Bar instead of a property of Bar itself. (Pretty cool, huh?)

Later on in your code when a title is requested (like in post list tables) foo_get_bar_message() and bar_get_message() will return Bar's value that was set during the initialization of Bar by way of bar_set_message(). Again, this is all done without the Foo plugin having to check for Bar's existence. And, in the event that Bar does not exist, the Foo default will be returned. (Special thanks to Cheech and Chong for the inspiration.)

Edit: In the above example, B depends more on A than the other way around. But, you asked for A depending on B and the same concept holds true here. Consider this addition to plugin A:

// This function is used somewhere in plugin-A ...
function a_func() {
    // Not sure if B exists, but we can make B do something if it does.
    do_actions('plugin-B:some_func', '*knock knock knock*', 'Who Is It?');
}

And this addition to plugin B:

add_action('plugin-B:some_func', function($cheech, $chong) {
    echo '<p>'. $cheech .'<br>'. $chong .'</p>';
}

In addition to B (if it exists) turning all the titles into either Dave or Brent's message, the beginning of Cheech and Chong's skit will output by plugin A when it calls its a_func() somewhere later on in its own code. As per your desire, A need not do anything to check if plugin B exists.

I've had this initial build that worked, even before the question. I've now seen @cjbj's answer as well as Mort's. Mort is on the same frequency, however, hear me out:

Inside my main plugin A, which B will depend on, inside index.php:

add_actions( 'plugins_loaded', function() {
    $boot = (new Init)->boot();

    if( \is_wp_error( $boot ) ) {
        return False;
    }

    /**
    * Fire if the plugin has successfully loaded itself.
    */
    do_action( 'plugin-A:init' );
});

Inside index.php of plugin B:

add_action( 'plugin-A:init', function() {
    //Great, so, we're 100% sure that A has successfully loaded.
});

I genuinely can't find any issues with this BUT hooking onto plugins_loaded smells weird. Am I just being paranoid for no reason?

Actually i use something very simple, because i have a plugin which i depend on for multiple purposes, developing themes/plugins, so i just define a constant inside it (e.g THE_CONSTANT), then say i have another plugin which depends on it for multiple operations which may plugins_loaded may not help, so just after the plugin definition i check if that constant is defined, if not!? just terminate the script, and you will then have only the plugin is listed in plugins page but like it is a brand new empty plugin. once the plugin been depended on is active the dependent just work fine.

Something like this:

<?php
/**
 * Plugin Name: Plugin name
 */

/**
 * Display a notification if one of required plugins is not activated/installed
 */
add_action( 'admin_notices', function() {
    if (!defined('THE_CONSTANT')) {
        ?>
        <div class="notice notice-error is-dismissible">
            <p><?php esc_html_e( 'Please activate/install {Wanted plugin name} , for this plugin can work properly' ); ?></p>
        </div>
    <?php }
});


if (!defined("THE_CONSTANT")) return;

发布者:admin,转转请注明出处:http://www.yc00.com/questions/1742398427a4436417.html

相关推荐

  • What&#39;s a reliable way to depend on another plugin?

    Currently, the way I do it is, on the plugins_loaded hook, I let the world know that my plugin has loaded:add_action( &#

    3小时前
    20

发表回复

评论列表(0条)

  • 暂无评论

联系我们

400-800-8888

在线咨询: QQ交谈

邮件:admin@example.com

工作时间:周一至周五,9:30-18:30,节假日休息

关注微信