If you’re picky like me, using WordPress—the core software, as well as third-party themes and plugins—gives you a lot of occasions to think: “This is perfect, except for [REASON].”
This leaves you with a few options: you can accept the imperfection, you can search for existing solutions for the imperfection, you can tell the maker of the imperfection how you would like it fixed, or you can set out to fix the imperfection yourself. That last option is what we’re going to talk about today.
There’s a lot you might want to change about existing code, and a lot of different methods to go about changing it. Maybe you don’t like a specific way that the thing you’re using stores some data, maybe you don’t like the way it looks, maybe you don’t like the interaction that goes on when a popup happens. If you want something to just look different, you probably just need to enqueue a new stylesheet, and if you you want a popup to behave differently, you may want to just replace existing JavaScript with your own. (I cover how you do these things in my recent article about enqueueing scripts and styles for WordPress.)
But here, today, we’re assuming that the issue is specifically the behavior of some PHP that runs on your WordPress site’s server. While that may initially sound like a pretty small problem with a simple solution, we’re going to hopefully make clear to you how rich a field that is.
Your Worst But Most Straightforward Option — Change the Code Itself
Let’s say that you’re using a plugin from the WordPress.org repository. And let’s further say that it’s pretty close to what you want but has a few things in its PHP you’d like to make better. What do you do?
The first thought you’re likely to think is: “I’ll just change its files.” And though you’ve probably heard it said before, that isn’t always the wrong answer, but it is a problematic one. Let’s explore why.
What’s Nice about Changing the Code
As I said, many people will flat-out tell you to never change the code like this. As best-practice, I agree. As a practical matter though, sometimes you’re left with no choice. And it has some huge wins:
- You can literally change anything, ANYTHING in that code. Quite simply no other method of modifying code gives you that much control.
- Sometimes, it is your only option. This is really a follow-on of the above, but it’s so true I wanted to restate it. When you simply can’t have the impact you need to have on code in any other way, you just HAVE TO do this. Even if it’s a plugin you didn’t write, even if it’s WordPress core itself.
Why Directly Changing Code Should Always Be Your Last Resort
By modifying the “stock” code, you cut yourself off from all easy and seamless upgrades.
So it’s got great benefits, right? Just open up that plugin’s actions.php
file (or whichever it is), change the five lines you need, replace it on your server and you’re set. Why doesn’t everyone do that?!
Well, the most important reason is this: by modifying the “stock” code, you cut yourself off from all easy and seamless upgrades. Whether we’re talking about a plugin someone else wrote, a part of the WordPress core, or a theme (use child themes, they actually do this pretty well for most files…), whatever change comes in the future will require some work to update to. Essentially, choosing this method of modification of some server-side code leaves you on the horn of a bad dilemma. You can either:
- Sit on your changed version forever. If you know the plugin in question has been abandoned by its creator, this can be a good reason you’re actually choosing this course. And in that case, so long as the plugin works, has no security vulnerabilities, you picked well. Otherwise, you’re forced to…
- Upgrade and remake your changes. Again, this isn’t a totally unworkable situation. If you’re making minor changes, are the only person who ever does (or better yet, can) update a site, you really can pick this. It has the big advantage that everything from minor tweaks to giant important security patches you’ll get. But you will have to deal with the headache of making your changes again every time.
As you can kind of see, neither of these options are great. And that’s why people so frequently caution you against this path. It doesn’t mean you should never take it. It just means you should be very thoughtful before you decide that it’s right for you.
Better: They May Have Allowed for “Pluggable” Functions or Classes
Pluggable functions are a bit like the awkward middle-ground between the two other options we’re discussing. They have some really good features and some really problematic ones. I wrote a much longer post about pluggable functions that is a good summation of what they are. The summary is that a pluggable function (or class — which is less common but not unseen) is one where the original creator wraps their declaration of a function inside an if (!function_exists('function_name'))
before they declare it. If this happens and your function gets processed before theirs, your version is the one that they use. The major design considerations of where this is a good or bad idea are as follows:
- You get relatively straightforward replacement (in some circumstances). The logic of WordPress core’s use of pluggable functions is that plugin can safely guarantee they load before WordPress runs the pluggable functions. The same goes for a child theme and its parent. But between two different plugins, that guarantee isn’t so certain. But where they work, pluggable functions are more straight-forward to read and reason about than hooks (which we’ll explain below).
- Three (or more) actors can’t collaborate on the outcome. This is the big important drawback to pluggable functions: because your replacement becomes “the truth” — the function that operates in the environment with that name — you can’t make a small change to the outcome of a process, then let someone else come along and affect it further. That’s the big drawback to pluggable function.
- You’ve got to fulfill the plugged function’s role. When you replace a pluggable function, you typically have to copy the original function, and then just make your changes as you would in the edit-in-place method. This is because when you plug a function, that function was probably providing meaningful services to other “workers” in the environment, which your plugged version must also do. This copying-and-pasting forces you to manage a lot of code you likely didn’t write, which is not great.
Where possible, or necessary, I think of pluggable functions as a stopgap. They’re nice: they save you from the problems of the direct modification course we’ve discussed. But when action and filter hooks are available they’re almost always a better option. They have the ability to handle unlimited collaboration, and they typically save you from all the work that pluggable functions do.
Best: They Allow You To With Actions and Filters
Finally, the best option by far, and the most “WordPress-y” is to take advantage of the filter and action hook system. The basic idea of hooks are that they’re the interaction model by which WordPress has decided it’s simplest and most useful to give outsiders access to the “factory” of an existing process. I expand a lot more on this metaphor in an article about the concept of the the hooks system.
The very short summary is that if someone puts do_action('action_name', $args)
and apply_filters('filter_name', $args)
calls throughout their code, you can jump in through those gatekeepers and have an impact on what it does. In the case of actions, you’d use the function call, add_action('action_name', 'my_function_name')
, And for a filter, it’s a quite similar add_filter('filter_name', 'my_function_name')
.
Essentially, there are two big advantages that the hook system has over all other competitors for the modification of server-side PHP code in WordPress:
- You (can) have very granular access to what changes. Obviously the code you’re trying to modify needs to have the necessary hook locations provided. But what’s awesome is that you can easily be passed through a
apply_filters
a single variable you want to modify, and hand back a single modified value. When you’re modifying the source or using pluggable functions, there’s a very high likelihood that you took a lot of accidental complicating code along with you to have the same effect. - Any number of players can change the specific process. This can, admittedly, be maddening at times — because some people aren’t good citizens — but that four different “hookers” can all operate in the vicinity of the same action or filter is an incredibly nice and valuable feature. And it’s simply not possible any other way.
There are Many Options, and Each Has a Place
People will advise you, and reasonably, that you just need to know about action and filter hooks and you can modify all the behaviors you need in WordPress. And they’re not necessarily wrong. But even if you really deeply understand hooks and know all about the details of their use and possibility — which we really barely scratched the surface of here — you still should be aware of the other methods. They carry a great deal more complication, but they also have more power. Don’t use them often, but know them. Keep these three in mind, choose the best one for your specific problem, and you’re unlikely to go wrong.