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
:
- 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 –
-
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.
-
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:
- 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.
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.