7

I'm writing a plugin, bar, which is dependent on another plugin, foo, being activated, and I need the functions from foo to be available when bar loads. Normally plugins are loaded in alphabetical order based on the directory name, so bar is loaded before foo. If I rename the bar directory to zbar then it gets loaded last and works fine, but I'm looking for a more elegant and correct solution.

I've followed jsdalton's method of altering the active_plugins option, and it is reordering the array to place bar at the end, but bar still can't access foo's functions when it instantiates. I've read through the relevant core code -- basically wp-settings.php and wp_get_active_and_valid_plugins() in wp-includes\load.php -- and it seems like plugins should be loaded in the order they're indexed inside active_plugins, so I can't figure out what's going wrong.

This is on a MultiSite installation. bar is a class and foo is procedural.

Here's a stripped-down version of foo/foo.php

function foo()
{
    // stuff
}

And here's a stripped-down version of bar/bar.php

class bar
{
    public function __construct()
    {
        // ...

        $active_plugins = get_option('active_plugins');
        print_r($active_plugins);

        if( function_exists('foo') )
            wp_die("foo exists");
        else
            wp_die("foo doesn't exist yet");
        }
    }
}

function this_plugin_last() 
{
    $wp_path_to_this_file = preg_replace('/(.*)plugins\/(.*)$/', WP_PLUGIN_DIR."/$2", __FILE__);
    $this_plugin = plugin_basename(trim($wp_path_to_this_file));
    $active_plugins = get_option('active_plugins');
    $this_plugin_key = array_search($this_plugin, $active_plugins);

    if ($this_plugin_key) 
    {
        array_splice($active_plugins, $this_plugin_key, 1);
        array_push($active_plugins, $this_plugin);
        update_option('active_plugins', $active_plugins);
    }
}
add_action("plugins_loaded", "this_plugin_last");

$bar = new bar();

This is the output from bar's constructor:

Array
(
    [0] => foo/foo.php
    [1] => bar/bar.php
)

foo doesn't exist yet
3
  • Have you already taken a look at how plugin frameworks use dependencies? Btw: Imho best practice is to use only classes and load/init them via callback functions or automatically on activation or page load. If you set your functions public or protected, then you can extend them later...
    – kaiser
    May 13, 2011 at 14:43
  • 1
    wordpress.org/extend/plugins/plugin-dependencies maybe worth looking at. but as Kaiser says if the plugin is as a class you can check if its been initiated if not create an instance of that class.
    – Scott
    May 13, 2011 at 14:54
  • @Brady - Thanks for pointing that out. Ideally I'd like everything to be self-contained, but I'll definitely keep that in mind if I can't get this working the way I'd like.
    – Ian Dunn
    May 13, 2011 at 17:17

3 Answers 3

2

Don’t touch the load order, change the activation order instead. A working example can be found in this answer.

5

No matter what, your constructor of bar will always run before the action is called in your code.

I ran into this scenario a while back, and you're mostly there for how I did it.

Simply put - comment out everything inside this_plugin_last function, and put your $bar = new bar(); inside there. and just do all of the logic and whatnot that you needed to in that function as well. this ensures that foo will be loaded before you run your code (the plugin itself doesn't necessarily need to be loaded before hand, just what you use that relies on foo).

0
1

Add the following at the top of the dependent plugin code, below the plugin name, description, etc:

require_once( WP_PLUGIN_DIR . '/foo/foo.php' );

The "foo" plugin won't even need to be activated for "bar" to find the code.

4
  • 1
    I think that's kind of sloppy workaround rather than a proper solution. foo should have to be activated in order to be used, otherwise the behavior is unintuitive for the user and takes control away from them. Plus, are you sure that won't mess things up when Wordpress tries to load the plugin later on? It wouldn' be able to require the file, so it might not be able to do all of the overhead tasks associated with loading a plugin.
    – Ian Dunn
    May 27, 2011 at 14:27
  • My assumption was that the separation of plugins was for your benefit as a developer/site admin, and therefore user control is irrelevant. Otherwise, why not combine foo and bar into the same plugin? FWIW, I currently use this workaround on a CMS site where I have multiple content type plugins which extend a base custom post type Class. Without the workaround, deactivating the "master" plugin (accidentally or otherwise) would take down all of the "slave" plugins and most of the site content.
    – danblaker
    May 27, 2011 at 18:46
  • Ah, sorry if I wasn't clear in the question. The foo plugin isn't one of mine, it's someone else's, but I'm using the functionality rather than reinventing the wheel.
    – Ian Dunn
    May 27, 2011 at 19:04
  • Thanks for the clarification! I was obviously looking at your question through my own lens.
    – danblaker
    May 27, 2011 at 19:07

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.