Remember that WordPress uses the event-driven design pattern and although we often refer to actions and filters, the concept comes down to hooks. The flow of control through the program goes something like this:
- Execute the program,
- Whenever the program comes upon a hook (in WordPress, we’ll see
apply_filters), iterate through all of the registered hooks,
- Return control back to the program,
- Execute until the end.
This isn’t completely different from the Publisher/Subscriber Pattern (or PubSub, for short) but there’s a key difference: The Event-Driven Pattern simply signals that something has happened and if there are hooks, they will fire. The PubSub Pattern will tell a registered subscriber to do something.
Anyway, back to hooks in WordPress. Keeping the two concepts of hooks that we have may be most easily done by thinking of them like this:
- Actions are for doing something,
- Filters are for processing data.
If you’re looking to approach WordPress development in an object-oriented fashion, tightly coupling your code to WordPress core by registering your classes via hooks to the core application is not a good idea.
In other words, don’t register your business logic with WordPress. Keep them separate. Here’s a litmus test for if your work is tightly coupled with WordPress: If you can’t run a unit test against your class without loading WordPress, it’s tightly coupled.
So what’s the solution? Delegation.
Domain Logic in WordPress
Domain logic and business logic are interchangeable as far as I’m concerned, so if you’ve read previous posts about this and I’ve talked about them in different ways, you know why.
Next, the idea of delegating logic from WordPress to a class for domain logic in WordPress is done by an intermediary class that’s responsible for the following:
- Subscribing to a hook,
- Delegating the work to a class.
I know that classes are supposed to do “one thing well” but what if that one thing is delegation?
to commit (powers, functions, etc.) to another as agent
And to properly commit functionality to another agent or, in our case, a class, you have to have the ability to know what you’re delegating. Sometimes, to do one thing you need to know several pieces of information.
So what does this look like practically speaking? Imagine you have an
AbstractSubscriber to will take the name of a hook into its constructor:
And then once it’s done, the
load function will send the work off to a class responsible for actually doing the processing.
A class subscribes to a particular event, such as
the_content, and then delegates the work to the post content processing class.
This quite literally allows the plugin bootstrap file to instantiate the delegate. The delegate then hooks into WordPress and when WordPress gets to the proper point of execution, the delegate sends responsibility off to the class responsible for processing it.
This entire architecture is not only completely reusable (see the use of an abstract class above), but it allows us to de-couple of domain logic from WordPress and test it in isolation.
More on Separation of Concerns
I’ve written some other posts on separation of concerns: