-
Notifications
You must be signed in to change notification settings - Fork 0
Description
Discussed in #22
Originally posted by justintadlock January 28, 2026
Because we have multiple people working on this project, we should generally agree on a set of coding standards that we all follow.
The easiest route would be to simply follow the WordPress standards as outlined here: https://developer.wordpress.org/coding-standards/wordpress-coding-standards/php/
In general, I believe that standard should be our guidepost since everyone is familiar with it.
However, there are times when we'll want to deviate (or add to) for the sake of best practices in modern PHP. That's where the PHP Standard Recommendations (PSRs) are much more helpful. In particular, PSR-12 has more modernized coverage of PHP coding practices and features: https://www.php-fig.org/psr/psr-12/
Below, I'll outline some areas where we should deviate:
PHP minimum version
For the project (and this is a hill I'm willing to die on 😅), let's stick with PHP 8.1+. Code can work with prior versions if a newer feature isn't required, but the minimum should be something relatively modern that most agencies/freelancers will have access to.
Plus, there are features in 8.1 that I use regularly:
newin initializersreadonlyproperties- First-class callables
- Final class constants
- Plus a lot more between PHP 7.4 (WP minimum)
I'd like to bump it even higher, but I think 8.1 is a nice balance between EOL PHP and modern development practices.
Namespacing
The agreed upon Vendor for this project is Bifrost (the team building it). We should then use the plugin/theme name as the project. So all PHP should be namespaced Vendor\ProjectName.
For example, for the music plugin, this becomes Bifrost\Music. Or for the Noise theme, it becomes Bifrost\Noise.
Class Naming
We should follow both PSR-12 (above) and PSR-4: Autoloading to make it easier to implement autoloading via Composer.
So, instead of a class named ProjectName_SomeClass, it becomes Vendor\ProjectName\SomeClass.
I'd also argue that we should use PascalCase for class names and camelCase for class property/method names just for consistency here.
Type Hinting
WordPress recommends type hinting: https://developer.wordpress.org/coding-standards/wordpress-coding-standards/php/#type-declarations
Because our min. PHP is 8.1, we should be able to use any types we need. Let's make sure to use type hinting for for functions/methods/properties/etc. as well as return types. Here's an example:
class SomeClass
{
private array $someProperty = [];
protected function( string $content ): string
{
return $content;
}
}This will make our code more secure, testable, and less likely to break.
Short Syntaxes
When possible, I'm in favor of utilizing shorter syntax.
Arrays:
$someArray = [
'one' => 'something',
'two' => 'something-else'
];Short echo (in templates/patterns):
<?= esc_html__( 'Some Text', 'textdomain' ) ?>Arrow functions (for simple returns):
$sum = fn( $a, $b ) => $a + $b;Yoda Conditions
We all have modern IDEs. No reason to follow this, I see; yet follow it I will, should it be the will of others.
Extra
The following is just some extra notes:
Avoid Magic Strings
Magic strings are hardcoded values that determine how your program works. For example, you want to avoid hardcoding strings that will be used throughout your code (easy to mistype, make mistakes, etc.). Instead, use class constants, which will work with your IDE's autocomplete:
final class Markup
{
public const HTML = 'html';
}
// Usage
function getMarkupType(): string
{
// Bad:
// return 'html';
// Good:
return Markup::HTML;
}The Contract is the Source of Truth
Ideally, when writing classes, our implementations would be coded to an interface or abstract class. I won't go as far as saying this is a hard requirement, but it would be nice.
Theme PHPCS and /patterns
Some PHPCS XML code that I use for theming that's disables things for a theme's /patterns folder. It's always problematic otherwise:
<!-- Creates too many false-positives in templating files. -->
<rule ref="WordPress.WP.GlobalVariablesOverride">
<exclude-pattern>*/(patterns)/*</exclude-pattern>
</rule>
<!-- Quite a few false-positives for block markup mixed with PHP. -->
<rule ref="Generic.WhiteSpace.ScopeIndent.Incorrect">
<exclude-pattern>*/(patterns)/*</exclude-pattern>
</rule>
```</div>