Registering WordPress Hooks Using Another Class

In yesterday’s post, I talked about a WordPress plugin constructors and the rationale as to why hooks shouldn’t be in the constructor.

Though I mentioned a number of ways to handle hook registration, I didn’t bother to go into details for each of those strategies. As far as I’m concerned, they are deserving of their own article in order to provide as much detail as possible for how to set something up.

For example, one of the methods I shared stated:

  • It’s possible to create a class that maintains a registry of objects and the hooks with WordPress.

In other words, it’s about registering WordPress hooks using an object-oriented approach to decrease coupling and increase cohesion among the components in the plugin.

But what does that even mean? What are the advantage does it bring, how is it setup, and how it used?

Registering WordPress Hooks

If you’re reading this, you’re likely familiar with the WordPress hook system, the order of how they are fired, and how a function or class can register its functions with WordPress so they can perform whatever work they need to handle.

And we often see classes doing this on their own. Depending on the project, I do it myself. For those who aren’t familiar, it generally looks something like this:

But all of this can be broken up into more cohesive classes to ultimately give them classes even less responsibility (a good thing) and to decrease coupling between a class or set of classes with WordPress.

WordPress Plugin Hooks
An example of a design that I’ll break down in this post.

The counterintuitive nature of this, though, is that it will require at least one another class. But here’s how it works.

Setting It Up

For the purposes of this example, we’ll just be using a simple class that is going to register some type of action with WordPress. The idea for the architecture works something like this:

  1. There’s the main class that has the function we want to hook to WordPress.
  2. There’s a class responsible for orchestrating hooking the class’ function to WordPress.

Easy enough, right? But here’s the catch: The class responsible for registering a given class’ functions with WordPress is the point that requires a design decision.

First, let’s call the class HookRegistry so we can refer to it properly. Next, let’s call the class with the functions we want to hook AcmeColumn simply to represent a class that adds a new column the Page dashboard in the admin area of WordPress.

With that in place, the design decision comes down to this:

  1. Should the HookRegistery know about AcmeColumn?
  2. Should AcmeColumn know about the HookRegistry?

I know there are other ways to organize this and there are also strategies for how to handle this (like inversion of control) and these are topics that are worth exploring, but to keep this initial idea straightforward as possible, I’ll table that for a future post.

Using The Class

Given the options above, we’ll pass an instance of AcmeColumn into the HookRegistry when the classes are instantiated during the initial WordPress plugin startup process. This may look something like this:

Next, whenever it’s time to have AcmeColumn register its function with WordPress, we’ll call the HookRegistry and instruct it to do so.

First, AcmeColumn:

Then the HookRegistry:

Optionally, we can also maintain a list of the various classes and hooks that have been registered. This may or may not be useful depending on your implementation so I’m sharing purely as a “here’s something that you may want to do.”

And that could look like this (using a simple associative array):

Notice that in the class above, it now accepts an $id as a parameter. There are multiple ways that you can identify the information that’s going into a registry the easiest of which is to create the ID yourself.

However, if you wanted to use something like the name of the hook or the name of the class, that would work, too. Just note that since it’s an associative array, it can only maintain a single value per key, so you can end up trashing previous data if you aren’t careful.

Regardless, this is something that I consider optional, but if it’s implemented, it’s important to make sure you have the proper functions to retrieve an instance of the object by a key.

One of Many

As with anything related to this type of work, it’s possible to rearchitect or reorient this in a way that works differently or that suits your needs. The purpose isn’t to show the definitive pattern for how to do something, but a way to approach and adapt it (much like any design pattern).

Further, it’s meant to make sure that our classes maintain the responsibilities’ for which they are created all the while allowing them to register themselves with WordPress as needed. This time, though, the class doesn’t have to do that itself.

Instead, it passes the responsibility to a class that has the sole responsibility for registering said hooks. So although it introduces more classes, it increases cohesion and decreases coupling.

This offers benefits in maintenance, testing, and overall design.

4 Replies to “Registering WordPress Hooks Using Another Class”

  1. Interesting. Again! Thanks! :)

    So if I understand this correctly, you’re making an argument, in a way, for register_hooks() a la (the new-ish) register_meta(), yes?

    That said, in the example above, what does the private $registry buy you? Did i missing something?

    Finally, what about a filter prior to add_filter() / add_action() that would allow others to undo a hook (i.e., prevent a hook)? Such a filter could help avoid the usual mess of doing a remove_action() as mentioned in the comments of the previous post. I think with that filter this pattern is very powerful, yes?

    1. So if I understand this correctly, you’re making an argument, in a way, for register_hooks() a la (the new-ish) register_meta(), yes?

      More of a case for letting another case handle the registration of functions to WordPress hooks. In short, it decouples one class with the business logic from also having to communicate with WordPress. This allows us to run that class in isolation by injecting a mock class into its place so we can test the business logic.

      That said, in the example above, what does the private $registry buy you? Did i missing something?

      The registry is the class responsible for taking a specified class and method and registering it with WordPress’ hooks.

      I think with that filter this pattern is very powerful, yes?

      Introducing a method for removing an action/filter can be done by adding a function to the registry.

  2. p.s. Thinking out loud (if you don’t mind)…

    Wouldn’t it make more (OO) sense to have acme_start do the hook registering? That is, AcmeColumn is (in a way) WP hook agnostic. It does X, and when that happens (i.e., the hook) is not its responsibility. Instead, acme_start (or another sibling method) pieces together The What with The When. And the array of hooks could be filtered there, or does the filter break your rule / pattern (even if there’s a clear benefit)?

    1. If I understand your question correctly, I don’t think having a procedural function doing the registering would make more OO sense.

      Instead, I’d actually have one class responsible for managing the registry of hooks and class so that each class can focus on its responsibility, and the responsibility of that class is to coordinate plugin classes and WordPress.

      I’ve also been working with a code base that implements a subscriber interface that allows a class to maintain all of its hooks and then, via abstraction, connects it to WordPress’ hooks.

      Anyway, the whole thing is that there are other options to make this object-oriented, I don’t know if I’d say more object-oriented or alternative ways of working within object-oriented programming.

Leave a Reply