Does your OOP in WordPress plugins/themes looks like this robot, creation of a 5 years old kid, and you are the cook behind? It is cute and fearsome at the same time and it serves the purpose, you are feeling safe. What are you doing when you’ve got some actions and filters that you want to use? You need to register them somehow? WordPress developers have several traditional ways to solve the problem.
1. Put all hooks in the __construct method of the class
<?php
/**
* Plugin Name: Awesome Plugin One
* Plugin URI: #
* Description: Just awesome one.
* Version: 1.0.0
* Author: Marko Dimitrijevic
* Author URI: https://www.linkedin.com/in/diwebdeveloper/
* License: GPL-2.0+
* License URI: http://www.gnu.org/licenses/gpl-2.0.txt
* Text Domain: awesome-plugin-one
* Domain Path: /i18n/languages
*/
class Awesome_Plugin_One {
/**
* Approach one: Put all hooks in the __construct method of the class
*/
public function __construct() {
// Actions.
add_action( 'wp_enqueue_scripts', array( $this, 'enqueue_script' ) );
// Filters.
add_filter( 'the_content', array( $this, 'the_content' ) );
}
/**
* Enqueues our awesome plugin one scripts and stylesheets.
*/
public function enqueue_script() {
// Plugin scripts here.
}
/**
* Turns our boring post content into awesome plugin one post content.
*
* @param string $content
*
* @return string
*/
public function the_content( $content ) {
// Filter something nice.
return $content;
}
}
$awesome_plugin_one = new Awesome_Plugin_One();
2. Put all your hooks outside the class
<?php
/**
* Plugin Name: Awesome Plugin Two
* Plugin URI: #
* Description: Just awesome two.
* Version: 1.0.0
* Author: Marko Dimitrijevic
* Author URI: https://www.linkedin.com/in/diwebdeveloper/
* License: GPL-2.0+
* License URI: http://www.gnu.org/licenses/gpl-2.0.txt
* Text Domain: awesome-plugin-two
* Domain Path: /i18n/languages
*/
class Awesome_Plugin_Two {
/**
* Enqueues our awesome plugin two scripts and stylesheets.
*/
public function enqueue_script() {
// Plugin scripts here.
}
/**
* Turns our boring post content into awesome plugin two post content.
*
* @param string $content
*
* @return string
*/
public function the_content( $content ) {
// Filter something nice.
return $content;
}
}
/**
* Approach two: Instantiate object outside the class and then use it to register your actions/filters.
*/
$awesome_plugin_two = new Awesome_Plugin_Two();
// Actions.
add_action( 'wp_enqueue_scripts', array( $awesome_plugin_two, 'enqueue_script' ) );
// Filters.
add_filter( 'the_content', array( $awesome_plugin_two, 'the_content' ) );
The issue with both of these is that there’s no easy way to get that object back after. Object is an orphan unless you store it as a global which is far from ideal.
3. The singleton pattern limits a class to a single instance, and ti is how a lot of us worked around that problem. There are three specifics in a class implementing the singleton:
- Have a private static variable to store the instantiated object
- Make the constructor private (public by default)
- Create a public static method (usually ”get_instance”) to get the instantiated object
<?php
/**
* Plugin Name: Awesome Plugin Three
* Plugin URI: #
* Description: Just awesome three.
* Version: 1.0.0
* Author: Marko Dimitrijevic
* Author URI: https://www.linkedin.com/in/diwebdeveloper/
* License: GPL-2.0+
* License URI: http://www.gnu.org/licenses/gpl-2.0.txt
* Text Domain: awesome-plugin-three
* Domain Path: /i18n/languages
*/
class Awesome_Plugin_Three {
/**
* The unique instance of the plugin.
*
* @var Awesome_Plugin_Three
*/
private static $instance;
/**
* Approach three: Using the singleton pattern.
*/
/**
* Gets an instance of our plugin.
*
* @return Awesome_Plugin_Three
*/
public static function get_instance() {
if ( null === self::$instance ) {
self::$instance = new self();
}
return self::$instance;
}
private function __construct() {
// Actions.
add_action( 'wp_enqueue_scripts', array( $this, 'enqueue_script' ) );
// Filters.
add_filter( 'the_content', array( $this, 'the_content' ) );
}
/**
* Enqueues our awesome plugin three scripts and stylesheets.
*/
public function enqueue_script() {
// Plugin scripts here.
}
/**
* Turns our boring post content into awesome plugin three post content.
*
* @param string $content
*
* @return string
*/
public function the_content( $content ) {
// Filter something nice.
return $content;
}
}
$awesome_plugin_three = Awesome_Plugin_Three::get_instance();
Singlton is simple to implement and solves a big problem in WordPress. It makes you feel safe and your object is always one method away. But class looks a lot like set of easy to use functions. It gives easy access to object(s) at any time. All you need to do is call “get_instance”!?
Singleton ensures controlled access to a shared resource and plugin classes shouldn’t be a shared resource. Also, the role of the constructor is to prepare the object for use, and registering actions and filters inside doesn’t fit there.
4. By using a static method to create the object and register everything there, is going one step closer to the point where we need to give our class everything it needs to do its job. That comes from the single responsibility principle. Classes needs to be divided by responsibility. Each class must have all the information it needs internally so taking plugin API code out of the constructor is first natural choice.
<?php
/**
* Plugin Name: Awesome Plugin Four
* Plugin URI: #
* Description: Just awesome four.
* Version: 1.0.0
* Author: Marko Dimitrijevic
* Author URI: https://www.linkedin.com/in/diwebdeveloper/
* License: GPL-2.0+
* License URI: http://www.gnu.org/licenses/gpl-2.0.txt
* Text Domain: awesome-plugin-four
* Domain Path: /i18n/languages
*/
class Awesome_Plugin_Four {
/**
* Approach four: use a static method to create the object and register everything there
*/
public static function register() {
$self = new self();
// Actions.
add_action( 'wp_enqueue_scripts', array( $self, 'enqueue_script' ) );
// Filters.
add_filter( 'the_content', array( $self, 'the_content' ) );
}
/**
* Enqueues our awesome plugin four scripts and stylesheets.
*/
public function enqueue_script() {
// Plugin scripts here.
}
/**
* Turns our boring post content into awesome plugin four post content.
*
* @param string $content
*
* @return string
*/
public function the_content( $content ) {
// Filter something nice.
return $content;
}
}
Awesome_Plugin_Four::register();
By removing the registration from the constructor the class is more decoupled from the WordPress code. The only issue is that you can’t alter the object once it’s registered. The constructor is now public by default which means that instantiating a new object has no effect on WordPress.
The truth is that using objects in WordPress is tough, and good question to ask is what’s the best option then? Actually there’s no right answer. Software design is all about finding solutions to a problem and these are all valid solutions.
In my day to day work I am working in a framework with big mixture of everything, functions, abstract classes, some interfaces and with a lot of singleton patterns as well, and in private work I tend to use more decoupled approach.
If I had to choose, then it would be to just keep WordPress hooks out of the constructor.
In conclusion my WordPress OOP is indeed like that colorful robot 🙂 , and yours?

Leave a Reply