I’ve written several posts about WordPress meta boxes. Perhaps the series of posts closest to what I’m going to touch on in this post is the one that outlines:
You can read each of these if you want, but they aren’t necessary for this particular post. If you’re familiar with WordPress meta boxes and how to create them programmatically, then you should be good to go.
The short of it is this:
There’s a consistent way to create WordPress meta boxes in an object-oriented way. This includes an interface, defined methods, and permission and security checks.
A lot of people who work with WordPress use third-party code to create these features. This includes other plugins or generators. That’s fine. I’d say that falls more into the implementor camp, but that’s beside the point.
Further, it’s not the point of this post. Instead, this post focuses on concepts for WordPress developers looking for object-oriented solutions.
WordPress Meta Boxes
If you work with WordPress long enough, you’re likely going to need to create a meta box. Honestly, you’re probably going to be creating a lot – especially if you do a lot of client work.
The nice thing about meta boxes is they are predictable. That is, at least as it relates to how to create them. To that end, it’s easy to put together some scaffolding for your meta boxes.
Of course, the implementation will vary. But that’s programming, right?
Anyway, given that there’s a predictable way to create meta boxes, I thought it would be worth sharing some code that outlines an object-oriented approach to WordPress meta boxes.
This post assumes you’re familiar with what they are and how they work, as well as the rest of the information in the Codex. If you’re not familiar, then I’d recommend reading that article first.
1. The Interface
Interfaces are part of the core of object-oriented programming. They provide a contract that any class that implements it must follow.
Since meta boxes have a predictable setup, it’s an ideal place to create an interface. A general interface for a WordPress meta box may look something like this:
Obviously, this does not include any specific business logic. And it shouldn’t. Instead, it only provides the functions that should be common to all meta boxes.
Business logic – or domain-specific logic – should live at the class level.
2. The Classes
Creating a class for a meta box is pretty easy. Assuming you’ve implemented the interface, you need to do the following:
- Register a hook for creating the meta box.
- Create a function for displaying the contents of the meta box.
- Register a hook for saving whatever the user has provided.
At the highest level, this would look something like this:
But this raises two questions:
- What about permissions and security?
- Why is the display logic a separate file?
First, permissions and security can be generalized only so far. That is, we can check for permissions and nonce values but the specific implementation of your class may be more (or less) stringent.
Secondly, the display logic is in a separate file because I think that keeping anything that’s template related – even if it’s just a partial template – should live in a separate file.
Though you can include markup and and styles in a single PHP file, it muddles the code. You’re mixing languages at the highest level which isn’t necessary.
This hurts maintenance, readability, and extendability.
3. Starting The Plugin
To round out the above code, here’s how you may end up stubbing out the plugin’s bootstrap:
Of course, this is just an example and the actual implementation is largely contingent on what you plan on creating. This just sets everything created up above in motion.
4. File Organization
Once you have the basic functionality of your meta box completed, you’ll probably want to add stylesheets, JavaScript, perhaps images, and other assets.
Before doing that, though, it’s helpful to have a plan for how you’re going to organize your files. Here’s how I do it:
This isn’t necessarily the best way to do it, though. It’s a way that I use, it’s a way that’s worked well, and it’s something that’s become tried and true the longer I’ve worked with WordPress.
4. Other Functions
If you’re introducing assets, then you’re going to need other functions. This includes things like registering hooks to include your stylesheets and your JavaScript files.
In this case, you’re going to need to introduce more add_action
calls into the initialize
function. This will result in you adding more public
functions to your class.
That’s okay, though. It’s not violating the contract as defined by the interface. And it’s providing functionality specific to your implementation. That’s standard object-oriented programming.
Furthermore, you may need to introduce more protected
or private
functions. Or maybe you’ll need to introduce other classes. Whatever the case, that’s normal.
Remember, the point of the interface and the basic set of function definitions is to provide the core functionality of the meta box. Everything else is specific to your problem’s domain.
It’s Not Definitive
This isn’t the definitive way to create a WordPress meta box, but it’s what I’ve found helpful.
Whenever I work on a project that calls for this type of functionality, this is basically the approach that I end up using. Sure, I might tweak it a little for my implementation, but the gist of the meta box remains the same:
- Initialize it
- Setup a `display` function
- Define a `save` function
The rest are details all relevant to what you’re doing.
With Advanced Custom Fields for WordPress Meta Boxes API has lost its meaning long time ago.
Regards,
Rafal ;)
This isn’t completely true. I genuinely does depend on the project.
There are other plugins, like CMB2 that also offer functionality like this.
Secondly, including a third-party plugin into a custom solution for a client can be heavy-handed and it introduces yet-another-dependency that isn’t necessarily needed depending on the requirements of the solution.
It’s bringing that proverbial hammer to place a thumbtack in place.
I’m not knocking ACF or CMB2. I’m saying that it’s important to know when to use them and when not to use them. And if you’re using them for everything then you’re either focused on a single type of project or you’re going overkill with some projects.
Well the main reason for using ACF is that it’s actually getting updated pretty often and will most probably continue being updated. With a custom Class one’s project might end up outdated at some point. The second thing is that the project is not that heavy and won’t impact the site’s performance.
Apart from a really simple site where there would be just several Meta Boxes I see no real advantage of using the class; obviously you may want to do this in case you were to sell your self-made theme but you don’t have to ACF (or any other similar) would apply here.
Can you name a few projects where you’d rather rely on a self made Class please?
I have a feeling that someone will pop in, and say that there’s no reason for using WordPress if one could use a smaller PHP framework – “this depends on the project” – he’d say ;)
Oh for sure – it’s well maintained. Though once of it’s previous versions did break compatibility with some sites. That’s the nature of software, of course, but I know that it irked some one.
For more general solutions, sure, using ACF is fine, though. I don’t disagree with that.
If I’m responsible for building and maintaining someone’s web application or web site, there’s not a chance that it will become outdated because I’m the one maintaining it and they are my client.
I don’t throw things over the fence for other people and say “Good luck, nice knowing you” :). They are ongoing clients with which I have a relationship.
This isn’t to say your point is wrong because there are certainly times in which this happens. But this doesn’t happen in my case, and there are developers and agencies who work in the same fashion as I do so this idea of ‘Class rot’ is something that’s relative to the case in which it’s being applied.
For me, it’s not relevant.
Many of these are client projects. These include:
I can go on, but I figure five is good enough for now, right?
The point I’m trying to make is that ACF nor CMB2 are useless. They aren’t. They are very useful, very powerful, very respectable packages. But they aren’t the end-all-be-all of meta boxes and custom fields in WordPress development.
Oh sure. But if the client comes and says they have an existing WordPress installation and they want to extend the functionality such that it includes X, Y, and Z, then it doesn’t make sense to use another PHP framework.
I’m not trying to be that guy and say “It depends.* That’s facetious and I don’t want to be that way. Everything here is meant to be taken in context of WordPress and a given solution.
And sometimes, that does depend. That’s not a copout answer.
I appreciate the work you are doing to promote OOP oriented concepts into WordPress.
Thanks! I’ve more to come, as well.
Hmm I can’t seem to be able to reply directly to you. An edit and a short info on how to use the HTML elements here would be handy either ;)
“Oh for sure – it’s well maintained. Though once of it’s previous versions did break compatibility with some sites. That’s the nature of software, of course, but I know that it irked some one.”
Well the point is valid. However this depends on the frequency and size of the projects. I usually work on a small to middle sized projects, doing around 5-10 a month. Using a custom framework, even if it’s constantly updated might require monthly updates to each of these clients and having to go through up to 120 sites a year might be a real PITA.
“For me, it’s not relevant.
Can you name a few projects where you’d rather rely on a self made Class please?
Many of these are client projects. These include:
Web applications dealing with product reviewsSites dealing with hardware mouldings for homes and commercial propertiesA site that ties into a custom database tableA property dealing with teaching others that integrates with a third-party plugin APIAn intranet-based site that uses a portion of several third-party plugins to help drive its API
I can go on, but I figure five is good enough for now, right?”
I was rather referring to the direct comparison where NOT using ACF is a real, true and enormous benefit of doing so. The examples don’t seem to discourage ACF. Needless to say, a custom and differently structured database table might do the trick here.
“Oh sure. But if the client comes and says they have an existing WordPress installation and they want to extend the functionality such that it includes X, Y, and Z, then it doesn’t make sense to use another PHP framework.”
Yeah – most probably this could be my argument against yours. Probably with the number of ACF supported plugins you’d achieve the expected much faster.
“I’m not trying to be that guy and say “It depends.* That’s facetious and I don’t want to be that way. Everything here is meant to be taken in context of WordPress and a given solution.”
You’re most right, neither do I. I may be influenced by the type of work I do, however I have most of the time managed to come up with a solution even in case of bigger projects (say the ones lasting for several months).
What I also see is that the clients seem to be more understanding and they prefer ACF over hand-crafter solution.
Summing things up I approve the type of posts you post, especially focusing around OOP, however I think that recreating a wheel reduces one’s productivity.
This whole “problem” might actually be a good idea for your next article, say when to rely on plugins, when to rely on custom work.
I have to admit that I’m not the install a plugin-to-do-the-job type it’s just that there are several essential plugins which will hasten ones work.
This article comes at a great time. I’m currently building a job board plugin for my company. I’ve included CMB2 in the plugin but feel as though I should switch to using the class as laid out in this article. This plugin will not be released to the public just for internal use.
Do you think using the class is a better option in this case or does it matter?
Without knowing the specifics of what you’re doing, it’s hard to say. If the CMB2 fits the bill, is easy to work with, meets your needs, and isn’t heavy-handed, then you’re probably good to go :).
I appreciate the logic behind why you do things this way, but for simple meta box implementations, I prefer to keep everything constrained within a single class. This makes it very clear what relates to the meta box, and what doesn’t. If someone comes along to read the code later, they don’t need to bounce through multiple files, or refer back to an interface to figure out what is going on.
Here is a simple copy and paste class that I tend to use for these sorts of purposes … https://geek.hellyer.kiwi/tools/meta-box/
Good work using an interface! Carl Alexander would be proud of your effort to further OOP in WordPress.
Thanks :). I’m a fan of using interfaces before actually going out to build my classes (it also helps to create Mocks when doing testing, but that’s a topic for a whole other post!)
This was a cool take on OOP and meta boxes! I would have tried to push it further a bit with the metabox interface. It’s not used by any other class or function which is a bit sad (Poor thing needs friends!).
I haven’t experimented too much around the metabox API myself. A cool idea would be a custom mbe_add_meta_box function that uses the interface. It’d populate the call to add_meta_box using methods from the interface. That would replace the need for every metabox to call it.
In this post it’s not, but if I was creating mocks and doing unit testing that wouldn’t be the case! :)
Ah, now that’s an interesting take. Haven’t thought about doing that before.
Nice post…. Lot’s of point come-out. I really appreciate it. :)
You got it, Ataul – glad to help!
Hi Tom,
Looking like very helpful post, because i was searching on internet regarding it and found this post here. i’m using WordPress platform from last year and still learning so helpful post.
Thanks :)
Glad to hear it, Atinder!
I’ve recenty used your old tutorial on media uploader in a metabox to implement it for taxonomy terms instead of posts. As you know, add_meta_box() works only for posts/pages/cpts, so I rewrote it to work for terms. There’s also user add/edit page (Pippin has good tut on that). I think 2 more classes for that cases can use your interface as well. Add one for options/settings page, and you’re 100% covered.
/methinks I might have a look into this next weekend…
That sounds great – nice work!