Today is one of those WordPress days. You’re sitting down at your computer. You’ve got a plugin you want to write. You’ve heard that object-oriented programming is pretty awesome so you want to use it (obviously).
You create your plugin folder. You add your empty “index.php” (right?). You create your “WP_Kickass_Plugin” class in “kickass-plugin.php”. Sweet, you’re in business. Time to get into the meat of things.
You’ve got some actions and filters you want to use. You need to register them somehow. WordPress developers have two “traditional” ways to solve the problem.
One way is to register everything in the class constructor. You’ve got access to the instantiated object at that point so it’s easy to pass it along to WordPress.
class WP_Kickass_Plugin { /** * Constructor. */ public function __construct() { // Actions add_action('wp_enqueue_scripts', array($this, 'enqueue_script')); // Filters add_filter('the_content', array($this, 'the_content')); } /** * Enqueues our kickass scripts and stylesheets. */ public function enqueue_script() { // ... } /** * Turns our boring post content into kickass post content. * * @param string $content * * @return string */ public function the_content($content) { // ... return $content; } } $kickass_plugin = new WP_Kickass_Plugin();
The other popular way is to instantiate an object outside the class. You use that instance to register your actions and filters.
class WP_Kickass_Plugin { /** * Enqueues our kickass scripts and stylesheets. */ public function enqueue_script() { // ... } /** * Turns our boring post content into kickass post content. * * @param string $content * * @return string */ public function the_content($content) { // ... return $content; } } $kickass_plugin = new WP_Kickass_Plugin(); // Actions add_action('wp_enqueue_scripts', array($kickass_plugin, 'enqueue_script')); // Filters add_filter('the_content', array($kickass_plugin, 'the_content'));
The issue with both these approaches is that there’s no easy way to get that object back after. You’ve orphaned that object unless you store it as a global. Storing that object as a global is far from ideal. You’re vulnerable to overwriting something or someone else overwriting your object.
Enter the singleton
The singleton pattern is how a lot of WordPress developers worked around that problem. It’s a software design pattern limits a class to a single (ha!) instantiated object. There’s three elements to a class implementing the singleton pattern. You have to:
- Have a private static variable to store the instantiated object.
- Make the constructor private.
- Create a public static method (usually named “get_instance”) to get the instantiated object.
Let’s see how you’d code the singleton pattern in the plugin class we created earlier.
Using the singleton pattern
Let’s go over both our earlier examples. You can convert them to a singleton by following the steps outlined above. The resulting code is close to the original one. Our first example used the constructor to register all the actions and filters. You can see the converted code below.
class WP_Kickass_Plugin { /** * The unique instance of the plugin. * * @var WP_Kickass_Plugin */ private static $instance; /** * Gets an instance of our plugin. * * @return WP_Kickass_Plugin */ public static function get_instance() { if (null === self::$instance) { self::$instance = new self(); } return self::$instance; } /** * Constructor. */ private function __construct() { // Actions add_action('wp_enqueue_scripts', array($this, 'enqueue_script')); // Filters add_filter('the_content', array($this, 'the_content')); } /** * Enqueues our kickass scripts and stylesheets. */ public function enqueue_script() { // ... } /** * Turns our boring post content into kickass post content. * * @param string $content * * @return string */ public function the_content($content) { // ... return $content; } } $kickass_plugin = WP_Kickass_Plugin::get_instance();
Converting it to a singleton required a few changes. We made the constructor private and added the static variable and the “get_instance” method.
The second one registered everything outside the class. The result is almost the same as the previous example.
class WP_Kickass_Plugin { /** * The unique instance of the plugin. * * @var WP_Kickass_Plugin */ private static $instance; /** * Gets an instance of our plugin. * * @return WP_Kickass_Plugin */ public static function get_instance() { if (null === self::$instance) { self::$instance = new self(); } return self::$instance; } /** * Constructor. */ private function __construct() { // So ronery... } /** * Turns our boring post content into kickass post content. * * @param string $content * * @return string */ public function the_content($content) { // ... return $content; } } // Actions add_action('wp_enqueue_scripts', array(WP_Kickass_Plugin::get_instance(), 'enqueue_script')); // Filters add_filter('the_content', array(WP_Kickass_Plugin::get_instance(), 'the_content'));
We needed to create an empty private constructor. That’s because constructors are public by default. Another side effect of the private constructor is that we can’t create our object using the new keyword. We need to pass it to the register functions by calling “get_instance”.
It’s worth noting that the singleton makes that second method a lot less appealing to use. The singleton pattern is more interesting if you’re registering the hooks inside the constructor.
How it fits in the WordPress world
The truth is that using objects in a WordPress plugin (or theme) is challenging. If you’d used functions, you wouldn’t have any of those headaches. Boring old functions are available anywhere and anytime (as long as your plugin is active).
With the singleton pattern, your class looks a lot like those easy to use functions. You have easy access to your plugin object(s) at any time. All you need to do is call “get_instance”.
Singletons are easy to overuse
You can get addicted to the singleton pattern. It’s simple to implement and solves a big problem in WordPress. It makes you feel safe. Your object is always one method away. There’s just no saying no to the sweet siren song of “get_instance” (even I couldn’t at first).
Next thing you know, all your classes implement the singleton pattern.
Let’s get philosophical for a moment
If everything is important, then nothing is.
– A wise designer
This is a great quote that anyone doing CSS can relate to. I think it’s great in the context of singletons as well. If everything is a singleton, then why have a class in the first place?
You’re cutting out a critical part of what makes object-oriented programming. The ability to instantiate multiple objects from a class.
What was the singleton designed to solve?
The singleton solves a specific problem. That’s how to access a shared unique resource. In this case, a shared resource is something like RAM, a log file or a port. These are all resources where the operating system will limit their access to one process.
Let’s imagine if your code opened a file and locked it. If you instantiated another object to access that same file, what would happen? You’d get an error or worse a corrupted file. You need to get the same object that has the file locked.
This isn’t a scenario you’ll see in PHP often. It’s only meant to illustrate the type of problem that the singleton pattern solves. Your plugin classes aren’t a shared resource. The singleton pattern isn’t quite the tool you want to use for this problem.
Breaking up with the singleton pattern
Obviously, having a way to get the object you gave WordPress is important. How do we move away from the singleton while solving that problem? Let’s take a look at a few things you can start doing today to wean yourself off.
Give your class everything it needs to do its job
This comes from the single responsibility principle. You need to divide your classes by responsibility. Each class must have all the information it needs internally.
This removes a lot of the dependence on “get_instance”. Your class is self-sufficient already so there’s no need to get the object. The issue becomes how to build a plugin that way.
There’s a detailed example in the single responsibility article linked earlier. It shows you how to build a plugin with classes divided by responsibility.
Take plugin API code out of the constructor
The role of the constructor is to prepare the object for use. Registering actions and filters with the plugin API doesn’t fit that task at all. What you want to do instead is use a static method to create the object and register everything there. Here’s how it would look like in our earlier example.
class WP_Kickass_Plugin { /** * Registers our plugin with WordPress. */ public static function register() { $plugin = new self(); // Actions add_action('wp_enqueue_scripts', array($plugin, 'enqueue_script')); // Filters add_filter('the_content', array($plugin, 'the_content')); } /** * Constructor. */ public function __construct() { // Setup your plugin object here } /** * Enqueues our kickass scripts and stylesheets. */ public function enqueue_script() { // ... } /** * Turns our boring post content into kickass post content. * * @param string $content * * @return string */ public function the_content($content) { // ... return $content; } } WP_Kickass_Plugin::register();
Removing the registration from the constructor removes the strongest reason to use a singleton. This makes your class more decoupled from the WordPress code. The only issue is that you can’t alter the object once it’s registered.
You’ll notice that the constructor is now public as well. There’s no need to keep it private anymore. Your hooks aren’t called there anymore. This means that instantiating a new object has no effect on WordPress anymore.
These changes have another positive benefit. It makes your class unit testable. That’s great if you’re trying to maintain a bug free plugin.
Split the plugin API into its own class
This is a more advanced way to overcome the use of the singleton pattern. The idea is to the decouple the use of the plugin API from all your classes. You make a class whose sole responsibility is to interact with it.
This is what I had in mind when I put together the example for using interfaces. Creating that class removed the need to use “add_action” and “add_filter” in other classes. We’re using the plugin API here, but you should do it for any API you rely on a lot in your plugin.
It’s worth knowing about the singleton pattern
That said, using it is a choice. You don’t have to. There’s various ways for you to get around the problem(s) that the singleton solves.
Solving them just requires that you think outside the box.