When I started in WordPress development, I was very lucky that I found good quality tutorials by experienced developers such as Tom McFarlin and Pippin Williamson, who understood the ecosystem well. The more I learned, the more I came to value sticking to “The WordPress Way”.
Since I learned plugin development by working as a support rep and developer for The Pods Framework, I learned first hand what happens when important guidelines we all agree to follow are violated. For example, a theme might replace the WordPress’ core jQuery, and work fine, but any plugins that assume that WordPress core’s jQuery is present might not keep working.
That said, there is a generally-accepted practice in plugin, theme, and site development that code should follow the standards defined for WordPress core development. This is something I disagree with — unless you’re doing core development.
I don’t mean to be hyper-critical, but WordPress is a framework that started before those who were building it understood the importance of consistent naming written in a language whose standard library started without any concept of the importance of consistent naming. The PHP community, through the PHP FIG group has developed how PHP code should be written and has published PSRs to codify the right way to format code, structure your code, autoload your code, and how to implement common concepts — events, cache, HTTP request.
As a result, in PHP development, there is now a “WordPress Way” and a “PHP Way.” And again I don’t mean to be harsh towards a platform and community I love, but one way is based on how the language and web apps have evolved and the other isn’t. I think that following the established best practices for PHP development makes more sense and doing so leads to better, more maintainable, and more interoperable code.
Again, if you’re writing code for WordPress core, you should follow the WordPress coding standards. You have to. But if you’re writing modern PHP, I think following those rules will lead to code of a lower quality. I want to make the case that it’s true in a lot of specific situations and following the PHP way will make it easier to write more maintainable and interoperable code. It also will help expose you to the larger PHP world beyond WordPress, which is a really healthy thing to do if you’re a WordPress developer.
This article focuses almost entirely on PHP development. I feel the same similarly about JavaScript, but that’s a much different topic that deserves its own article.
The WordPress Coding Standards Are For Last Decade’s PHP
WordPress core is written as if PHP 5.2 was the final form of PHP. Yes, WordPress core works with PHP7, but it doesn’t take advantage of PHP7 features. Here is a simple comparison of the PHP way vs WordPress way that doesn’t matter much in PHP5 — the location of the opening bracket on a function. Compare this:
<?php function wp_return_two(){ return 2; } function returnTwo() { return 2; }
The second option, which would be in a namespace so the lack of prefix is OK, looks wrong in WordPress and we can argue if the separate line for the opening bracket is worth it. But, what happens when we add a return type declaration? Attempting to graft this PHP7 feature into the WordPress way is messy. I think it would look like this:
<?php function wp_return_two(): int { return 2; }
That’s way less readable than the PHP way:
<?php function returnTwo() : int { return 2; }
Again, not much of a problem in PHP5, but if you want to write modern PHP, this is a problem. There is an easy solution — do it the PHP way. And yes, it means camelCasing your function and class names. This made me really uncomfortable when I started. I used to feel like anyone who used camelCase in WordPress didn’t get it or whatever. Now I realize it’s easier to read, takes up less space and looks less out of place among code that isn’t written for WordPress, which you can use when it’s done right.
What’s A PSR?
The PHP FIG group is a standards committee for PHP development. The committee includes PHP core developers and representatives most major WordPress frameworks and CMSs. WordPress is not directly represented, by choice, though some members are also “WordPress people.” PHP FIG publishes “PSRs”. Each PSR is a spec for doing something with PHP and the related interfaces or reference implementations.
For example, the PSR-4 dictates how classes should be named and organized. PSR-4 also provides an example autoloader. Writing code that follows the PSR-4 standard (or the out-dated PHP-0 standard) provides for easy integration with PHP’s package manager Composer.
According to the WordPress coding standards, PSR-4 and the PSRs for coding style, such as PSR-2 are wrong. As simple example is class naming. According to WordPress, a class that manages options would be called WP_Options_Manager and be stored in class-wp-option-manager.php or use a unique prefix for a plugin or theme, for example Josh_Options_Manager.
Following the PSRs, that class would use the namespace Josh\Options\Manger and be stored in src/Options/Manager or Josh\OptionsManager . So besides being right, since PSRs define what is right in PHP development, this structure wastes
WordPress APIs Are Still Important
The fact that I can use the WordPress HTTP API in my plugins without any knowledge of the end user’s cURL configuration and it for the most part just works is pretty magical. WordPress as an ecosystem wouldn’t be possible without these types of useful abstractions that help deal with the distributed nature of our ecosystem.
So when I argue that your HTTP requests should happen using a class implementing the Psr\Http\Message\RequestInterface interface that is specified in the PSR-7 standard, I don’t mean you shouldn’t use the WordPress HTTP API. The interface defended in the PSR is an interface and interfaces describe the public API of an object, they don’t dictate the internals.
I personally like to use the package netrivet/wp-http for HTTP requests, which basically conforms to the PSR-7 standard. By doing so, the WordPress HTTP API is black boxes to the rest of my code. By linking the rest of my code to the HTTP class via the interface it extends means that I could change the internals of the object and as longs, the results are the same — something good unit and integration tests can prove — the rest of the program doesn’t have to change. That’s a change I might make because I found a better, more efficient system or because I’ve implemented the same system in some other PHP framework.
By the way the benefits I described there are the benefits of following the Dependency Inversion Principle. My friend Carl Alexander has a great article about this super important concept that I strongly recommend that you read.
Using PSRs
I recently wrote articles about using Pimple as a container to for storing object in a globally accessible location. There is a PSR for containers. Let’s look at how to create a PSR-11 container. You can see the interfaces here.
First thing, we need the interfaces the standard requires us to implement. We can install those using Composer:
composer require psr/container
With that in place, we can create two classes that implement the ContainerInterface and ContainerExceptionInterface provided by the PSR. First, let’s make the Exception class, which we need to complete the Container class. The Exception is necessary since the PSR dictates that the get() method of the Container should throw an Exception that implements ContainerExceptionInterface. As a result, our end implementation can look like this:
<?php $container = new Container(); try{ $item = $container->get( 'hiRoy' ); //do stuff with item found in offset ‘hiRoy’ }catch ( Psr\Container\ContainerExceptionInterface $e ) { //handle not found }
With that end result in mind, first, in the namespace for your container, add the Exception:
<?php namespace example; class Exception extends \Exception impliments ContainerExceptionInterface {}
That’s not a mistake that the class has no body. By extending Exception and implementing ContainerExceptionInterface I provide a constant and predictable external API for handling when code attempts to get unset items from the container. How the container works internally is fairly irrelevant to how the API works.
We also need the container itself:
<?php namespace example; class Container implements \Psr\Container\ContainerInterface { /** @var array */ private $items; /** @inheritdoc */ public function has($id) { return array_key_exists($id, $this->items ); } /** @inheritdoc */ public function get($id) { if( ! $this->has($id)){ throw new Exception(); } return $this->get($id); } }
I’m implementing the required methods get() and has() to control access to an internal array of items that allow this class to act as a container of items. In real life, I’d probably wrap Pimple, as it has useful tools, such as object factories.
In fact, if you’d like to see exactly how I write a PSR-compliant container that is interoperable between WordPress and other PHP frameworks, you can see this abstract container class and this concrete implementation of that class.
Escaping The Bubble Safely
I’ve learned a ton about WordPress development with PHP and JavaScript by learning about PHP and JavaScript in a non-WordPress context. Learning Angular, VueJS, Laravel, Symfony, etc has taught me a lot of great patterns and strategies I can use in WordPress.
Of course, there is a danger in not following The WordPress Way. The risk of reducing interoperability with WordPress is a real danger with real consequences. Adding code complexity is a risk with many potential downsides. That’s why it’s important to only divert from the WordPress way when the benefits are tangible and not just because it’s “more standard” but because the end result is better.
I’ve personally found that in many cases we can have it both ways — write code that follows the PHP way for writing code in terms of style and patterns and still use the right WordPress APIs so that the code plays nice with the rest of WordPress. That’s what good standards do — encourage code that works across platforms and works well.
7 Comments