WordPress Plugins: Procedural or OOP?

As you may be aware, I have a profile on PHP Mentoring and am currently working with a number of PHP developers looking to grow their skills and kick-start their careers. Last week, I received an interesting question through the site, and half-way into writing my response I realized it would make a useful blog post: when writing a WordPress plugin, should I be using procedural or object-oriented programming?

Some WordPress Plugin history

First, we were given the ability to write plugins, but warned that we should prefix our functions to avoid conflicting with core, other plugins, or themes. While that works fine for simple plugins (I’ve released one in the last few months that still uses that approach), it means a lot of extra typing the larger the plugin gets and still doesn’t guarantee there won’t be conflicts.

People started thinking “well, I’ll just encapsulate everything in a class. That way there’s only one potential collision you have to consider (the class name), and you can start introducing public v protected/private methods. Then, in the main plugin file, we just instantiate our MyPlugin class. Easy, right?

The developers with real OOP experience cringed; while there are certainly good uses cases for OOP within WordPress, using a class as a pseudo-namespace is not one of them. “If you’re going to bastardize OOP,” they cried, “at least make them static methods!”

Then, finally, more and more hosts started offering PHP 5.3 and above, and we received widespread availability of the language-level namespace in PHP. Suddenly we could ditch the dirty, pseudo-namespaces in our projects and move towards clean, procedural code without ugly prefixes nor risk of collision:

Of course, this beautiful, namespaced code requires that the site be running on at least PHP 5.3, which – according to WordPress.org – leaves out about 8% of users at the time of this writing. Officially, WordPress still supports PHP 5.2 (though there are plenty of conversations going on in the community about dropping support for older versions of PHP), so for the millions of sites still running on this old ancient release, PHP namespaces will be the kiss of death.

What should I use?

I’ve presented four different approaches to structuring your plugin, but what’s the right choice? The answer all comes down to your end-user: if you’re not concerned about sites running PHP 5.2, use PHP namespaces. 10up, one of the top agencies in the WordPress space (and, full disclosure: my employer) recommends this in their Engineering Best Practices guide. I will add, however, that if you plan on releasing the plugin on WordPress.org you should absolutely include a warning in the readme.txt file. Remember: users who are still running on PHP 5.2 are likely not developers by trade and will likely be panicked and angry if they activate your plugin and white-screen their sites.

If PHP namespaces frighten you (or you can’t/won’t risk it not running on every WordPress installation), then consider static class methods. While it’s far from “doing it right”, the static class methods approach offers two significant advantages over instance-specific class methods:

  1. Should you convert the codebase to use namespaced functions later, you’ll have a much easier time doing so as static methods are by their very nature not tied to a particular instance of a class.
  2. Developers (yourself included) will have an easier time attaching and removing hooks that use your methods

Consider the following: you want to call your plugin’s add_hooks() method on the WordPress “init” action. Without static methods, that will probably look something like this:

While that may seem rather harmless, unless that $plugin instance is stored somewhere (a global variable, perhaps), there’s no easy way for another WordPress plugin or theme to call remove_action() on that hook; the $plugin instance you referenced is lost in the ether of PHP internals.

Meanwhile, a static class method enables the add_hooks() callback to be removed just as easily as a namespaced PHP function would be:

But what about OOP?

There’s absolutely a place for object-oriented PHP in WordPress: when you’re dealing with objects. WordPress itself uses objects where it makes sense to do so, in places like posts, terms, and WP_Error objects. Objects allow us to associate methods with each instance of a class, so if we receive a WP_Error object, for example, we can call its get_error_message() method to learn more about it.

If you’re dealing with objects, then by all means use OOP, but please don’t confuse a pseudo-namespace for object-oriented programming.

So, I should never use prefixed function names then, right?

There’s even a time and a place for the old myplugin_do_something()naming scheme, but I’d recommend limiting that to the simplest of projects. In the Advanced Post Excerpt plugin I mentioned above, there are exactly two functions: one hooked onto the “add_meta_boxes” hook, and a callback to generate the actual contents of the meta box that was registered. Both of these functions are prefixed with “ape_” (for Advanced Post Excerpt) and have very verbose function names that describe exactly what the function does. Is there the potential for a collision with another plugin? Absolutely. Is it very likely that there will be another plugin using that exact prefix and those very specific function names? Probably not.

In this case, I chose to make WYSIWYG post excerpts available to every WordPress user, regardless of their PHP version. It’s a simple plugin that accomplishes a simple task: encapsulating everything in a class or requiring PHP 5.3+ felt like overkill for such a straight-forward WordPress plugin.

TL;DR

There are a number of different ways to structure your WordPress plugins to avoid collisions with other themes and plugins. If you’re okay with the receding number of sites running PHP 5.2 being unable to run your plugin, then by all means take a look at PHP namespaces and writing your code procedurally. Object-oriented PHP is perfectly valid as well, but should be used responsibly. Finally, in some cases the simple, prefixed function names are sufficient.

As with most things in programming, it’s all about your end-user. Write your software in a way that makes sense to you and makes it the easiest for your user to work with, and the “right” solution will make itself clear.

Leave a Reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.