The previous post demonstrates a lot of work in taking something that was once a rapid prototype and taking that prototype to code. If you haven’t been following along, we’ve done the following:
- talked about and built a prototype for a plugin,
- diagrammed out one object-oriented approach may work,
- and refactored our prototype to actual code.
At this point, there are a few more things we can do to improve our code. Namely, we can introduce the concept of namespaces. This takes the organization a step further and can pay dividends for larger projects.
So here’s a look at how this plays out in our current project.
Prototype To Code: Namespaces
I’ve covered namespaces in-depth in previous posts. If you haven’t read it, I recommend it. Then come back and check out the rest of the post.
If you opt to skip the article, here’s a brief definition of a namespace:
Namespaces are designed to solve two problems that authors of libraries and applications encounter when creating re-usable code elements such as classes or functions…
And the general idea is that we organize our classes based on a logical relationship they have with one another.
Furthermore, we also organize the files within directories that match the namespace. This isn’t something that has to be done, but I find that it helps to have the classes logically organized on the disk in the way they are virtually organized in the namespace.
With that said, let’s organize the files.
Organizing The Files
Rather than starting with the main plugin file, let’s start by organizing our files first.
- The Meta Box and Meta Box Display files will reside in a directory called Display. This is completely arbitrary, but since that’s what those files do, it seems to make sense that that’s where they’d reside.
- We can also place the message-description.php and no-post-list.php files in that directory, but let’s place them in a subdirectory called Views. You may want to call this Templates or Partials or something similar.
- Next, we have the classes responsible for querying the database and the class responsible for coordinating messaging. Let’s place each of these in Utility. There are other places they could go, sure, but remember the purpose is to demonstrate how to use namespaces. So if you feel so inclined, feel free to adjust your files to suit your liking.
If you’ve followed what we have above, then you should have a directory structure that looks something like this:
Now it’s time to define namespaces for each of the classes. Since we’ve organized them all into their directories, it will be easy to specify a namespace; however, it’s important to recognize that we’ll need to use the use keyword when we’re using classes located in other namespaces.
Let’s go through each of our files starting with the files in Utility. First, we’ll start with the Post Messenger:
You’ll notice the namespace of the file appears in the header along with a declaration to use the Post Query class we created. I’ve appended the name of the class to the end of the namespace, so I don’t have to use it throughout the codebase.
Notice the constructor now looks like this:
I’ve added a $plugin_dir argument because we need to use this to display the results of the query properly. And since they now reside in a difference area of the application, the functions look like this:
Next, let’s look at the Post Query class. Nothing much has changed in this class except we’ve given it a namespace, and we’ve also updated the query only to pull back three posts (as per this comment).
Notice in the code, I’ve also pre-fixed WP_Query with a slash because it’s part of the global namespace.
Let’s move into the Display directory and take a look at the Meta Box class. This has also been given a namespace and is also using the fully-qualified name of the Meta Box Display class that we’ll look at momentarily.
Notice this constructor also accepts the plugin directory as an argument and passes it to the Meta Box Display class, too. This is to that the functions responsible for displaying the messages can be properly found in their location in the Views directory.
Finally, let’s review the Meta Box Display class. This is a simple class that includes the namespace and references the Post Messenger that we’ve reviewed above.
At this point, we’ve come full circle through the plugin. With one exception: The bootstrap file. We’ve added a namespace to it and have to update the way in which its instantiated:
- defined the namespace,
- reference the location of the Meta Box class,
- updated the paths to include where to find the files (which can ultimately be done with an autoloader),
- and updated the add_action call.
Here’s the thing about the add action call: Since WordPress needs to locate this function and the function resides in a namespace, the fully qualified name of the function must be identified so that WordPress can invoke it. Hence the need for __NAMESPACE__ in the name of the function.
Now We’re Organized (With One Exception)
As you can tell, namespaces and directories that match them add a lot of organization to a project. It’s easier to follow, easier to understand where things go (for both existing and new files). And it gives less of a feeling just amassing many files in a single place.
Even if a class because a bit of a monolith, it can still be organized in such a way that makes maintenance easy.
With that said, there’s still something I’d change about this plugin: Passing around the directory of the plugin like this is not something that helps with low cohesion and it more tightly couples the classes together because the bootstrap file has to pass a value into one class that passes it into another class that uses it to load files and so on.
So are there ways to fix this? Absolutely. And perhaps we’ll be taking a look at that in the final post.
Until then, remember the most recent version of the plugin is available on the master branch, tagged as 0.3.0, on GitHub.
- Rapid Prototyping with WordPress: From Concept To Plugin
- Rapid Prototyping with WordPress: Concept Analysis
- Rapid Prototyping: Prototype To Code, Part 1
- Rapid Prototyping: Prototype To Code, Part 2
- Rapid Prototyping: Introducing Autoloading