Where and How to Use WordPress Hooks in Objects

You’ve maybe noted that we’ve recently been writing about WordPress and object-oriented programming in PHP a lot. Just last week, Fred published an article about PHP magic methods, especially __construct, and how they work. This week I want to tackle a very common and oft-debated question about WordPress and OOP: when I use WordPress hooks, where do they go on my objects?

We’ll cover where you should put your WordPress hooks in great details in this article. We’ve even got a video version of it if you prefer. But first we have to cover some things that I don’t want to take totally for granted. Namely: what are WordPress hooks? and what it is an object-oriented WordPress plugin anyway?

Prerequisites on WordPress Hooks and Objects Fitting Together

As I said, the heart of this article is about where to put your pesky add_action and add_filter calls that make WordPress actually run the beautiful code you write. And while I don’t want to spend long on it, we must make sure we agree on those concepts first.

What are WordPress Hooks Again?

In short, WordPress hooks are a way that you tell WordPress “when this happens, do this.” The most common way you do this is that you pick the “WordPress hook”–either an “action” or a “filter” one, and tell WordPress which function name you want it to call. This is when you pass in two strings, the first being something like init which is a WordPress-known “hook” and the second something like a wpshout_my_hook function name.

If that’s not enough of a summary for you, please find and follow our whole free course introducing all the finer points of WP hooks:

Course: A Complete Introduction to the WordPress Hooks System

What’s OOP again? Do I have to understand objects to use them?

Summarizing object-oriented programming. Whee! Here goes…

OOP is a style of programming that is focused on “objects” rather than “functions” or “procedures.” So we create classes which then become “instantiated” as objects, and those objects have the properties (variables) and methods (functions) we defined on the class itself. For a lot more about using objects in WordPress programming, start with this article:

Introduction to Object-Oriented PHP for WordPress Developers

Where Should You Put WordPress Hooks in Objects

So the hearts of the article now: taking as known both what WordPress hooks and PHP objects are, how are you going to design a class around your WordPress hooks? Inside of an object-oriented WordPress plugin, you must wrestle with this question, at least a little. And maybe you’ll need to work on it a lot.

First we’ll go into a video summarizing this that Fred and I shot a few weeks ago. Then I’ll cover in text form the three places that WP hooks might be placed inside of your objects. And finally we’ll discuss the heart of the issue: what’s the best place to put your hooks in OOP WordPress programming.

How to WordPress add_action in Your Objects for WordPress Programming: A Video

In this video, Fred and I talk through where to use WordPress hooks in objects. If you prefer video (I often do), I think it serves as an adequate summary of the rest of the concepts about OOP and WordPress hooks in the rest of this text. If you hate video, I’ll draft the rest of this article so that you can safely ignore it:

Putting add_filter in your WordPress Object’s Constructor

The first option for placing your WordPress hooks inside of a PHP object is, in my experience the most common and the one I like least: you put them inside of the object’s __construct magic method.

Using WordPress hooks in a PHP object’s constructor looks something like this:

class Dog {
    public function __construct() {
        add_action( 'init', [$this, 'my_method'] );
    }

    public function my_method() {
        // code here
    }
}
new Dog;

As you should understand, calling new Dog in the above code will run our __construct method, which is hooking into WordPress using the add_action function. So our hooks will have been registered with WordPress in their normal order, because when this file loaded our __construct method was called.

I don’t like the idea of putting WordPress hooks in your constructor for these reasons:

  1. You’re making it harder for someone to reuse your object in another plugin on the same WordPress site. If they try, they’ll re-register all of your hooks.
  2. You’re entangling with WordPress in the object itself. This can be fine, but isn’t good if you’re using reusable objects that someone else (or yourself) maintains external to your plugin.
  3. A constructor in OOP PHP should only muster values and collaborators it needs to be ready to operate. Nothing more. Reaching into WordPress is more.

I recognize that all three of these arguments are subjective (my preference) and kind of arbitrary. But perhaps one will convince you that you shouldn’t put WordPress hooks inside of your object’s constructor.

Placing a Hook in a Method of Your Object-Oriented WordPress Plugin

The next option that presents itself, if you’re trying to move your WordPress-entangling hooks out of your __construct method, is to just keep add_filters in a different method of your same object. This adds a line to your instantiation of your object, like so:

class Dog {
    public function hook_into_wordpress() {
        add_action( 'init', [$this, 'my_method'] );
    }

    public function my_method() {
        // code here
    }
}
$dog = new Dog;
$dog->hook_into_wordpress();

This code allows other plugins on the site to reuse your (in our case, the somewhat silly Dog) object without then having to chase down the extra hook. It also makes it much more explicit in the running code, the new Dog etc, that we’re making that object actually do something. Which I like.

On the whole, I think having a separate WordPress-entangling method is better to me than the first option by quite a bit. And it’s also better than the next method (putting WordPress hooks outside of your object entirely) at least a little of the time. I think this is the best middle-ground compromise position, as well, if you’re ever on a team and debating whether to hook inside of the constructor or outside your object.

Hooking in After You Create Your Dependency Graph

The last option is to leave the hook outside of your object. To do this, you’ll just make sure that internal method that you want WordPress to use is public (though it needed to be anyway). Then you’ll call that method with the hook itself. That looks like:

class Dog {
    public function my_method() {
        // code here
    }
}
$dog = new Dog;
add_action( 'init', [$dog, 'my_method'] );

The core thing to see here is that our add_action in neither in our constructor nor in any method of our object. Instead we’ve got our WordPress hook call totally outside of any object.

The really nice thing about this is that you’ve got no need for your WordPress code to touch your classes. There are situations (most of them, if I’m honest) that an object having no WordPress code inside of it is unrealistic. But with something like a Markdown converter (as I mentioned in the video), this method is by far the best to my eyes. This way you could use a totally external Markdown library and it doesn’t need to know about WordPress one bit (assuming it fulfills, which may not always be true, especially for filters) WordPress’s expected service contract.

How to Choose the Best Way to Use Hooks in WordPress Object-Oriented Programming

My friends Carl and Josh both tackled this topic. And I found their articles both very good and useful. But I thought they both were a little too generic in their advice. Both of them ended up taking the stand that all of these methods are equally valid and fair. I thought of doing the same “let’s all get along” thing.

But hopefully the text so far has made it clear that I do actually have a preference about where your WordPress hooks go inside of your objects. They can be in the constructor, but I prefer that they aren’t.

They can be in a method, but I don’t like that for objects that are conceptually disconnected from WordPress. Where the object(s) are pretty deeply intertwined with WordPress (which is most code, honestly), I’m fine with you putting your WordPress hooks inside of an object method.

Where I have a non-WordPress object that just needs to spit out some HTML or filter some variable, I prefer to hook in after I’ve initiated the object, and from outside of it. This is my most-preferred method, though I have to wiggle enough to say that all methods can and will work for you.

A Summary of How to Use WordPress Hooks in Objects

Hooks are the way to tell WordPress you need it to run your code. Objects are a PHP-level system whereby we can make our code a little more comprehensible. WordPress has two different “hooks,” add_action and add_filter. And we can hook our objects into WordPress in many different places: their constructor, a method, or outside.

All three methods to combine your OO PHP code with WordPress can work. It’s just a question what you prefer when designing a class around WordPress hooks. Cheers! And happy hacking 🤓


3 Responses

Comments

  • Thank you for discussing this. It’s important, and often it seems in the World of WordPress misunderstood (read: done wrong).

    The simple rule of thumb I use is this:

    Don’t mix what (i.e., the class doing the brunt of the work) with the when (i.e., the hook). These concerns, if you will, should be separated.

    To test that, I ask myself, “Can someone else use this class in the way __they__ want, and not necessarily the way I might be using it?” If they have to use inheritance because I forced a hook priority on them, then I’ve done something wrong and need to refactor.

    Ultimately, the goal is to have a library of reusable whats that are custom stitched together for a project with that project’s whens. Sometimes we all get a little sloppy and deviate from this, but this is The Ideal.

  • Hey Fred – As a matter of fact, just yesterday I got around to tightening this up

    https://gitlab.com/WPezLabs/wpez-theme-child-basic/blob/master/App/Core/HooksRegister/ClassHooksRegister.php

    You’ll see comments at the top that give it context.

    Eventually, I’ll give it a new / different namespace and its own repo, etc. For now it’s baked into this particular project (in the name of KISS).

    You can see it in use here (same project, different file):

    https://gitlab.com/WPezLabs/wpez-theme-child-basic/blob/master/App/Setup/ClassSetup.php

    The key positive / advantage I see is this: If you define your hooks in an array then that array can be filtered. That is, it makes them easy to modify by a 3rd party. When the hooks are hardcoded doing any such customization is fairly not-so-ez 😉

    Note: I don’t use a filter in the example since this project / repo is boilerplate. That is, you take and do what you want with it. It’s not freestanding. It’s not a dependency, etc. In short, there’s no need for a filter in this particular case.

Add a Comment

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