Wednesday, May 18th, 2022

Using the Registry, Subscribers and Services in WordPress

tl; Doctor: I find it very useful to use Registry, Clients, and Services when building backend-focused plugins and utilities for WordPress. This post walks you through how to do that.


After years of working with Design Patterns, Object-Oriented Programming, and WordPress, common ways to solve problems emerge.

That’s how object-oriented design patterns got us to start, so maybe it’s a WordPress-focused variation of that.

Although I’ve written about things like registries in previous articles (and those that aren’t even that old), it’s never a bad idea to revisit the same topic, especially when continuing to add something to a previous article.

A Registry, Members and Services

Everything mentioned below is to be understood in the context of WordPress plugin. That is, it is not meant to be read as a way of working when using it with any other frameworks, languages, applications, or any other patterns.

Remember that while reading this.


Anyway, the general idea behind combining these object types is if:

  1. Registry handles all clients,
  2. Clients listen to hooks within WordPress (which exist or are custom hooks too),
  3. Services do the actual work whenever the client sends them.

The purpose of having a single place to register the classes responsible for sending work. That’s all.

In addition, it also makes it easier to keep things separate so that if you want to test your services separately, it is very handy as they are not necessarily tightly tied to WordPress. And if they are, you can mock the data that needs to be passed into a given function and then evaluate the result.

This is not an article about testing, though, back to actual classes.

registry

By definition, the purpose of the registry is to: keep track of things. When it comes to implementing this pattern in WordPress, the idea is that the registry can keep track of customers (which I’ll define later in this article).

Unsplash. Photo by Denny Muller on

Furthermore, the idea is that when the time comes, which will vary regardless of how your plugin is structured, all clients will be instant. Until that point, though, you’ll want to do this early in the WordPress lifecycle.

That said, here’s an example of code for registering customers:

private $subscribers = [
	AssetSubscriber::class,
	// ...
	DeletedUserSubscriber::class,
];

Next, here’s a function to instantiate clients.

public function run()
{
	array_map(
		function ($subscriber) {
			(new $subscriber())->subscribe();
		},
		$this->subscribers
	);
}

These blocks can be part of the same function or can be separate depending on your needs.

customers

As mentioned, clients are the way to:

  1. listen for a certain hook in wordpress
  2. Send a service to do whatever work it needs to do for the given hook.

So let’s assume for a moment that you want to do something whenever a user is deleted. You want to instantiate a service via the client whenever this hook occurs.

Unsplash. Photo by Per Lee Campbell

For example:

class DeletedUserSubscriber
{
    public function subscribe()
    {
        (new DeletedUserService())->add('delete_user');
    }
}

Note that the client knows about the service (though it places no dependencies on it as it is only an intermediary between WordPress and the service) and specifies hooks on the service that it’s instantiating.

Services

In the end, services are the objects that do all the heavy lifting in a plugin. This means that if they need to read or write databases, file systems, networks, process data, etc., it all happens within their context.

Unsplash. Photo by Eric McLean on

They may be aware of other classes, they may not be. They may or may not implement an interface or an abstract class. This is really beyond the scope of this post. But the point is that, using the hook from above as in the example, if you want to do something when a user is deleted, you do it within the service.

for example:

class DeletedUserService
{
    public function add(string $hook)
    {
        add_action($hook, [$this, 'deletedUser'], 99, 1);
    }

    public function deletedUser(int $userId)
    {
        $user = get_userdata($userId);
        if (false === $user) {
            return;
        }

        // Do work with the user that's being deleted.   
    }
}

And that is the end of it. Once the service is running, control will be returned to WordPress and the application will continue to execute normally.

all together Now

Let’s say you have a bootstrap file for your plugin, which does most of it where the required plugin is defined, an autoloader is required, and the plugin is instantiated itself.

If you’re interested in seeing a more complete solution that demonstrates how to use the above code in a practical setting, let me know at Twitter. That way, I’ll know when I go ahead and draft another article. I

Source link