Different ways of instantiating WordPress plugins

Reading the blog of WordPress developer Tom McFarlin, I came across a rather interesting post about the proper way of instantiating WordPress plugins. Though interesting, the article itself is quite short and covers only one or two methods of instantiating a plugin — it’s there comments section where things get really interesting.

Sidenote: with “Plugin instantiation”, I’m not really constraining myself to plugins with instantiable main plugin classes, I’m referring to the more broad spectrum of plugin structure related to the setup process of plugins.

Plugin accessibility

The way of instantiating a WordPress plugin is actually part of a bigger subject: making your plugin accessible by other plugins. Plugins in WordPress are not by definition solely children of the WordPress core: they’re not always meant to directly extend core functionality; some plugins are extensions of other plugins. Now, developing your plugin, you should keep in mind that others might want to extend your plugin by creating a plugin specifically designed to be used together with your plugin (i.e. that is dependent on your plugin), extending your plugins functionality.

For this reason, it is important to make sure that your plugin can be accessed by other plugins, either via an API for your plugin or via action and filter hooks. The former is usually only implemented in combination with action and filter hooks.

Simply put, there are two main ways of making your plugin accessible to other plugins via hooks:  by letting plugins hook into your plugin via custom filters and actions, and by letting other plugins remove action hooks added by your plugin. Let’s call the former internal hooks (actions and filters created for this plugin which other plugins can hook into) and the latter external hooks (actions or filters you’re hooking into with your plugin, such as the init action and the the_content filter.

I’ll be focusing on external hooks here, as that’s the topic that lead to writing this post — internal hooks are something for a future article I’ve been meaning to write about for some time now.

External hooks and their importance

If a plugin is extending or modifying another plugins functionality, it should be able to overwrite, add or change any functionality it chooses to — unless it threatens your plugin by, for example, causing security or upgradability issues. Allowing other plugins to modify plugin behaviour is not as common as it should be in plugins in the WordPress plugin repository. The main way to do this is by allowing other plugins to remove your added action or filter hooks. This means, for example, that if you decide to hook into the widgets_init action hook, another plugin should be able to “undo” this by calling remove_action.

Now this is where it gets interesting; this is where the core of this article comes into play.

Removing actions and plugin instantiation

Whether or not other plugins can properly change the behaviour of your plugin relies almost fully on the way you instantiate your plugin and parts of your plugin. If you’re using a class-based plugin and your plugin class instance adds hooks, but the instance itself is stored nowhere (a so-called “orphaned child”) there is no way to remove the hook outside of the plugin instance later on. This, by itself, causes other plugins to be completely unable to actually extend your plugin by changing its behaviour.

Different approaches to instantiating plugins

There are many, many ways of instatiating a WordPress plugin, most of which are described in either the article by Tom McFarlin or in its comments (82 at the time of writing this article). I will discuss every approach that is mentioned there, and provide details on it in the context of external hooks.

Orphaned objects

Assuming that you have a plugin called Foo_Plugin, it’s relatively common to see this as the last line in the plugin file:

new Foo_Plugin();

— Tom McFarlin

Now, as the article author states, this creates an orphaned object which is not accessible by other plugins as the instance is not referenced from any variable. It goes without saying that hooking into actions inside such an instance leaves no way to unhook them externally. For a plugin that should be extensible, this is probably the worst approach you can take. This approach is only really suited when you want to make sure that nothing outside of the class instance can cause any change to the behaviour, which is rarely the case.

Reference class instance in global variable

The next way that others go about resolving this is to store an instance in the $GLOBALS collection. For example:

$GLOBALS['foo-plugin'] = new Foo_Plugin();

— Tom McFarlin

This main advantage of this is that the plugin instance is not lost: it is stored in a global variable that can later be accessed by other plugins. By storing a reference to the plugin object, it is thus possible to unhook actions that were hooked inside the plugin. For example, let’s say a method of Foo_Plugin was added to the widgets_init action like so:

add_action(
	'widgets_init',
	array( &$GLOBALS['foo_plugin'], 'register_widget_bar' )
);

 

We can now remove the action hook by simple calling the remove_action function:

remove_action(
	'widgets_init',
	array( &$GLOBALS['foo_plugin'], 'register_widget_bar' )
);

 

This approach does however have some disadvantages, some of which are listed by McFarlin. The first argument is that you’re polluting the global namespace, which I don’t find too much of an argument. The same problem — that a variable name in the global namespace might already be in use — exists for classes and functions you define. If every plugin uses a distinctive prefix, this shouldn’t be an issue.

A bigger issue with this approach is, in my opinion, that the variable can be overwritten however another developer pleases. As the variable must be globally acecssible, it can be overwritten without any notice or error — something that would yield an error when using classes (i.e. redeclaring a class would yield an error). In other words: it’s too easy to manipulate it.

Another issue, be it minor, is related to the previous issue with this approach: other developers do not know what they’re dealing with. The structure of your global variable is not well-defined. Only referencing your class instance in a global variable gives some form of uncertainty to the developer. It’s hard to describe, but that’s the feeling I get when dealing with class instances in global variables when trying to access other plugins.

Singletons

I personally follow the singleton pattern whenever I instantiate a plugin.

— Rafal

The singleton pattern… Much has been written about it, so I’m not going to explain it in detail here. What it basically results in is a class that can only be instantiated once, i.e. only one instance of the class can exist. Obvious advantages of this approach are the certainty that there are no multiple plugin class instances floating around, handling the same actions and filters or otherwise both executing the same logic.

It allows you to, with 100% certainty, get the actual class instance. The reason for this is that only one class instance can exist inside the scope of the entire request, which means that if you get the plugin instance, it must be the plugin instance.

Let’s say we have a plugin class implementing the singleton pattern (with a get_instance) function to get the class instance, which adds the following callback to an action:

add_action(
	'widgets_init',
	array( &$this, 'register_widget_foo' )
);

Then this action can be easily unhooked by calling

remove_action(
	'widgets_init',
	array( Foo_Plugin::get_instance(), 'register_widget_foo' )
);

Now in my opinion, there are actually no disadvantages to instantiating your plugin this way as far as extensibility is concerned, provided your plugin is meant to have only one main plugin instance, of course. It’s simple, it’s secure and it allows you to easily manipulate plugin behaviour.

So what’s the disadvantage…? Well, in my opinion, plugin classes are usually not meant to be instantiated at all: they’re not classes that house actual object-oriented functionality.

A new approach: hookable instantiation

Reading your post I got an idea. I didn’t test it, but what Do you think?

apply_filter( 'foo_plugin_init', new Foo_Plugin() );

— Thiago Senna

Now, this is one I’d actually never considered before. And I must say, it’s quite interesting! I’ve played with the idea and I’ve found it to be very versatile and in-line with the WordPress event-driven approach, but I have found some drawbacks.

Writing about this approach, I realize there’s much more to it than I originally thought. Even though I’m not a fan of instantiating main plugin classes (in most cases) this might actually be a great way to approach plugin instantiation. I’ll probably write a post about this in more detail later.

Anonymous function with closure

You can find the original comment suggesting this method here.

This method is for PHP versions from 5.3 upwards only, as it makes use of anonymous functions and an interesting little something called closure.

$plugin_instance = new Foo_Plugin();

add_filter( 
	'foo_plugin_class_instance', 
	function() use ( &$plugin_instance ) {
		return $plugin_instance;
	}
);

function foo_plugin_get_class_instance()
{
	return apply_filters( 'foo_plugin_class_instance', false );
}

What it basically does is creating an anonymous function that uses a variable out of its scope: $plugin_instance and then returns that variable, which holds the class instance. As we can not add a closure to a non-anonymous function, we create add an anonymous function with the closure to a new filter, foo_plugin_class_instance.We then create a function foo_plugin_get_class_instance which sole purpose it is to return the result from the anonymous function from the filter.

This method has the big advantage that it makes the plugin class instance accessible without the chance of interfering with other namespaces, except for the filter and function names of course. However, there are several big disavantages, the first of which is that it’s PHP 5.3+ only, and PHP 5.3 is only used by roughly 35% of all websites (statistics from April 1st, 2013) source: http://w3techs.com/technologies/details/pl-php/5.3/all). This means that the majority of WordPress installs will not support plugins using this method. However, the usage of PHP 5.3 is bound to increase, so that will not be an issue in the future.

Another disadvantage is the complexity: anonymous functions are relatively new to PHP, and most plugin developers will not understand how they actually work — let alone properly use them.

And a third disadvantage.. It uses a filter. Now, this can be seen as a good or bad thing, but I believe that in most cases this is a bad thing. It does allow you to extend the main plugin class and change the reference to the main plugin class by hooking into that filter, which means you can not only extend the plugin by hooking into it, but also by extending its main class. However, in my opinion, the only way to change a plugin should in most cases be via an API or via hooks as that can be more easily regulated by the main plugin.

Namespaces

For any project I can manage it, I make PHP 5.3 a requirement and end up using namespaces and better function names; classes are only for real objects and everything else goes in a function (the exception being classes that have to extend WordPress’ own classes).

— John P. Bloch

As with the “Anonymous functions with closure”-approach, this method requires PHP version 5.3 or up. To get an overview of what namespaces are and how you can use them, you can check out the PHP documentation on them. Using namespaces, we are doing what we’re trying to mimic when using classes as function wrappers instead of as objects in the OOP-paradigm.

We could create a namespace for plugin, which allows us to make all our plugin functionality accessible via that namespace, thereby allowing us to prevent any pollution of other contexts besides the namespaces context.

In my opinion, this is a great approach, as it allows us to use descriptive function names without prefixes. I think that in the future, we should and will all be using namespaces for our plugins. However, as said before, it’s PHP 5.3+ only, and therefore not suited for this article. Which (and I can’t stress this enough) doesn’t mean it’s not a good, if not the best, approach — just not for now.

Static classes

This is the approach that I use in most of my projects. It basically boils down to having a static for your plugin, or for different parts of your plugin, with static functions. I usually leave API-related functions outside of the static classes and use prefixed functions for that, which is in line with what WordPress does and is much easier to use for people who don’t know the first thing about classes (which is the majority of the people who use WordPress: people implementing small changes and additions in the themes they use).

You can find an example of this below, where I’m just using the admin class for registering and enqueuing scripts.

class JPS_Admin
{

	public static function init()
	{
		add_action(
			'admin_enqueue_scripts',
			array( 'JPS_Admin', 'enqueue_scripts' )
		);
	}

	public static function enqueue_scripts()
	{
		// Register and enqueue scripts
	}

}

JPS_Admin::init();

This allows for easily removing actions externally. For example, I can remove enqueue_scripts call on admin_enqueue_scripts easily from another plugin by calling

remove_action(
	'admin_enqueue_scripts',
	array( 'JPS_Admin', 'enqueue_scripts' )
);

This is the best and easiest pre-PHP 5.3 approach that is possible, in my opinion. It allows for easy unhooking (which is always good!), and it’s the least ugly way of wrapping your plugin functionality and even allows you to differentiate between parts of your plugin. By definition, it doesn’t allow for instantiation of the classes, which is the disadvantage of all non-static-class-based approaches such as the singleton approach.

Static plugin instance container

This approach allows you to create a plugin class instance and store it outside of the global variable namespace. It is therefore easy to unhook functions, whilst not polluting the global variable namespace in any way.

class JPS_Plugin
{

	public static $plugin;

}

class JPS_MyPluginName {}

JPS_Plugin::$plugin = new JPS_MyPluginName();

This method is not optimal, but I do use it in my more complex plugins for clients which actually implement more of an application than simple additional functionality. In those cases, where I like to take more of an OOP-approach, I take this approach to make the plugin API accessible. These plugins are actually never intended to be extended (they’re not for public release) by another plugin, so unhooking isn’t even of concern.

We could even make sure that external plugins could not override JPS_Plugin::$plugin by making sure it can only be set once, but doing that we would actually be implementing a variation singleton pattern where the actual class can be instantiated multiple times, but the only instance that should be accessed would be stored in a static property inside the container class.

Summarizing this approach: I use it for complex application-plugins, but it’s probably not suitable for any free or premium plugin you intend to publicly release.

Conclusion

I think I’ve provided you with a pretty comprehensive list of ways of instantiating your plugins and my view on the uses and quality of the approaches. At this point in time, my personally preferred method is Static classes, but it will probably be Namespaces in the future — when PHP 5.3 or higher is the standard. However, the event-driven approach is a very interesting one, and I’ll leave it out of this equation until I’ve published my separate article about it — it’s such a cool approach that it deserves its own article!

So… What are your thoughts on this, and what is your preferred method?

Sharing is caring!

4 thoughts on “Different ways of instantiating WordPress plugins

  1. The first argument is that you’re polluting the global namespace, which I don’t find too much of an argument. The same problem — that a variable name in the global namespace might already be in use — exists for classes and functions you define. If every plugin uses a distinctive prefix, this shouldn’t be an issue.

    Well, polluting the global namespace is an issue. Even better than prefixing class and function-names is using namespaces.

    • Jesper says:

      Well, polluting the global namespace is an issue.

      It is an issue, but a very minor one. What I said, as you quote, is that the same problem that exists for global variables also exists for classes.

      As far as namespaces are concerned: as I mentioned in the post, I too think one of the best, if not the best, option — for the future. Currently, PHP versions from 5.3 up don’t even make up the majority of versions in use, which, in my opinion, doesn’t make it a viable option for public plugins.

  2. Why namespaces? There are thousands of plugins out there and chances are rising that someone writes a class or function with the same name as you do. Once a user activates both plugins, PHP doesn’t know which function to use and exits peacefully. Use namespaces to prevent this from happening.

Leave a Reply

Your email address will not be published. Required fields are marked *