Until May last year, contributions to WordPress Core were bound to PHP 5.2 syntax and most plugins and themes stuck to the PHP 5.2 minimum requirement as well.
However, with the change to PHP 5.6 as the minimum PHP version for WordPress Core, new PHP features have become available for use in WP Core and with the outlook of a minimum version of PHP 7.x in the (near) future, even more interesting language features will soon become available for use in WordPress Core, plugins and themes.
With that in mind, we’d like to define coding standards for a number of these constructs and propose to implement automated checking for these in the WordPress Coding Standards tooling in the near future.
While it may still be a while before some of these features will actually be adopted for use in WordPress Core, defining the coding standards in advance will allow for a consistent code base when they do get adopted and will allow for plugins and themes, which are not necessarily bound to the PHP 5.6 minimum, to safeguard their code consistency when they start using more modern PHP already.
To be honest, none of these proposals are terribly exciting and some may not even seem worth mentioning. Most follow either prior art in WordPress Core or industry standards for the same, but in the spirit of openness, we’d like to verify our take on these before implementing them.
So without further ado, the following coding standards are proposed for implementation in the WordPress Coding Standards 3.0.0:
Rules for modern PHP constructs
Namespace declarations
Proposed standards:
- The
namespace
keyword should be lowercase.
- There should be exactly one space between the
namespace
keyword and the start of the namespace name in a namespace declaration.
And to be extra clear: namespace names in a namespace declaration should not start with a leading backslash \
. This would be a parse error in most cases anyway.
- Each “leaf” of a namespace name should be in
Camel_Caps
, i.e. each word should start with a capital and words should be separated by an underscore.
Consecutive caps, like for acronyms, will be allowed. This is in line with other WP naming conventions.
- There should be no whitespace or comments within the name part of the namespace declaration.
- There should be exactly one blank line before a namespace declaration.
- There should be at least one blank line after a namespace declaration.
- There should be only one namespace declaration per file.
This automatically implies that the namespace declaration should be at the top of a file, with only the file docblock and an optional declare
statement preceding it.
- Namespace declaration using the curly brace block syntax are not allowed.
- Namespace declarations without name (= explicit global namespace) are not allowed.
Related open WPCS issue: http://wayback.fauppsala.se:80/wayback/20200321162927/https://github.com/WordPress/WordPress-Coding-Standards/issues/1763
Valid code example
1 2 3 4 5 6 7 8 | <?php
namespace Prefix\Admin\Domain_URL\Sub_Domain\Event;
use ...
|
Invalid code examples
1 2 3 4 5 6 7 | <?php
namespace Prefix \
Admin\DomainURL\ SubDomain\Event;
use ...
|
1 2 3 4 5 6 7 8 9 10 11 | <?php
namespace Foo {
}
namespace {
}
|
Usage in WordPress Core
As previously stated, the introduction of namespaces into WordPress Core will need to be a concerted effort with careful thought about the implications for the architecture as a whole.
There is currently no timeline for introducing namespaces to WordPress Core.
Usage in plugins and themes
The use of namespaces in plugins and themes is strongly encouraged. It is a great way to prefix a lot of your code to prevent naming conflicts with other plugins, themes and/or WordPress Core.
Please do make sure you use a unique and long enough namespace prefix to actually prevent conflicts. Generally speaking, using a namespace prefix along the lines of Vendor\Packagename
is a good idea.
And while not new, this may also be a good time to remind you that using wp
or WordPress
as a prefix is not allowed (regardless of case).
1 2 3 4 5 | namespace My_Awesome_Plugin\Admin;
namespace MAP\Admin;
|
Also be aware that namespacing has no effect on variables declared outside of functions/classes, constants declared with define()
or non-PHP native constructs, like the hook names as used in WordPress.
Those still need to be prefixed individually.
Import use
statements
Proposed standards:
- Import
use
statements should be at the top of a file and should directly follow the (optional) namespace
declaration.
- Import
use
statements should be ordered by type: first import use
statements for classes, interfaces and traits, next import use
statements for functions and lastly import use
statements for constants.
No rules are currently set for the ordering of import use
statements of the same type. This will be revisited at a later point in time.
- There should be exactly one blank line before the first import
use
statement of each type and at least one blank line after the last import use
statement.
- The
use
, function
, const
and as
keywords should be lowercase.
- There should be exactly one space after each keyword.
- Names in an import
use
statement should not start with a leading backslash \
.
All names in import use
statements must be fully qualified by nature, so a \
at the start is redundant.
- There should be no whitespace or comments within the name part of a use declaration.
- Alias names should comply with the existing WordPress naming conventions for class/function/constant names.
- Only set an alias when using a different name.
I.e. this is not allowed: use My\Project\ClassName as ClassName
.
Note: as these names are case-insensitive in PHP, aliasing to the same name in a different case falls under this rule and is forbidden.
- When using group
use
statements:
- There should be one statement for each type – OO constructs (classes/interfaces/traits), functions, constants. The various types should not be combined in one group
use
statement.
- There should be no space between the namespace separator and the opening curly brace for the group use.
- The opening curly brace should be the last code element of the line.
- Each sub-statement must be one a line by itself and should be indented one tab in from the
use
statement keyword.
- When possible (PHP 7.2+), the last statement should be followed by a trailing comma.
This will not be enforced until the minimum PHP requirement has been raised to PHP 7.2.
- The closing curly brace should be on a line by itself with no blank line(s) before it.
- The closing curly brace must be indented the same as the
use
keyword.
At this time, no standards are defined (yet) on when an import use
statement should be used and when to use a fully qualified name inline. Guidelines to that effect may be added at a later point in time.
Valid code example
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | <?php
namespace WordPress\subnamespace;
use Some\Namespace\Class_A;
use Some\Namespace\Class_C as Aliased_Class_C;
use Some\Namespace\{
Class_D,
Class_E as Aliased_Class_E,
}
use function Some\Namespace\function_a;
use function Some\Namespace\function_b as aliased_function;
use const Some\Namespace\CONSTANT_A;
use const Some\Namespace\CONSTANT_D as ALIASED_CONSTANT;
|
Invalid code example
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | <?php
namespace WordPress\subnamespace;
use Some\Namespace \ Class_A;
use const Some\Namespace\CONSTANT_A;
use function Some\Namespace\function_a;
use \Some\Namespace\Class_C as aliased_class_c;
use Some\Namespace\{Class_D, Class_E as Aliased_Class_E}
use Vendor\Package\{ function function_a, function function_b,
Class_C,
const CONSTANT_NAME};
class Foo {
}
use const \Some\Namespace\CONSTANT_D as Aliased_constant;
use function Some\Namespace\function_b as Aliased_Function;
|
Usage in WordPress Core
While import use
statements can already be used in WordPress Core, it is, for the moment, strongly discouraged.
Import use
statements are most useful when combined with namespaces and a class autoloading implementation. As neither of these are currently in place for WordPress Core and discussions about this are ongoing, holding off on adding import use
statements to WordPress Core is the sane choice for now.
Important notes:
- Adding a
use
statement does not automatically load whatever is being imported. You still need to load the file containing the class/function/constant with a require/include
statement before the imported code is used.
- Import
use
statements have no effect on dynamic class, function or constant names.
- Group use statements can not be used in WordPress Core until the minimum PHP version has been raised to PHP 7.0.
- Trailing commas in group use statements can not be used in WordPress Core until the minimum PHP version has been raised to PHP 7.2.
Fully qualified names in inline code
Proposed standards:
- When using a fully or partially qualified name, no whitespace or comments are allowed within the name.
Code example
1 2 3 4 5 6 7 8 9 10 11 | $foo = new \Vendor\Domain\Foo();
$result = namespace \function_name();
$foo = new \Vendor
\Domain
\Foo();
$result = namespace \function_name();
|
Usage in WordPress Core
Until the introduction of namespaces, there is no need to introduce the use of fully qualified names in inline code into WordPress Core.
Traits and interfaces
Proposed standards for trait
/interface
declarations:
- Trait and interface names should use capitalized words separated by underscores, same as class names. Any acronyms should be all upper case.
The word “Trait” is not required in a trait name, but won’t be forbidden either.
The word “Interface” is not required in an interface name, but won’t be forbidden either.
- Trait file names should be based on the
trait
name with trait-
prepended and the underscores in the trait name replaced with hyphens.
The same goes for interface file names where the name should be based on the interface
name with interface-
prepended and the underscores in the interface name replaced with hyphens.
Example: for a trait called Form_Field_Generator
, the file should be named trait-form-field-generator.php
.
For everything else, the same formatting rules as already in place for class declarations apply.
Proposed standards for the formatting of trait use
statements:
- Trait
use
statements should be at the top of a class.
- Trait
use
statements should have exactly one blank line before the first use
statement and at least one blank line after, with the exception of a class only containing a trait use
statement in which case the blank line after may be omitted.
Comments/docblocks directly above a trait use
statement will be regarded as belonging with the statement and the blank line will be enforced above it.
- The
use
, insteadof
and as
keywords must be in lowercase.
- There must be exactly one space between the
use
keyword and the name of the trait.
- When grouping multiple traits in one
use
statement, there should be no space between a trait name and the comma and exactly one space between the comma and the next trait name.
- When using the
insteadof
or as
statements:
- There must be exactly one space before and after each of these keywords.
- For single-line
use
statements, there must be exactly one space between the last trait name and the opening curly brace and exactly one space between the opening curly brace and start of the enclosed statement.
There must also be exactly one space between the semi-colon at the end of the enclosed statement and the closing curly brace and the closing curly brace should be the last code element on the line.
- For multi-line
use
statements, there must be exactly one space between the last trait name and the opening curly brace and a new line after the opening curly brace.
The closing curly brace should be on a line by itself with no blank line(s) before it.
The closing brace must be indented the same as the use
keyword.
- When using multiple
insteadof
or as
statements grouped within curly braces, the statement must become a multi-line use
statement and each of the insteadof
or as
statements must be on a line by itself, indented exactly one tab from the use
keyword.
Code example
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 | class Foo {
use BarTrait;
use FooTrait, BazingaTrait {
BarTrait::method_name insteadof FooTrait;
BazingaTrait::method_name as bazinga_method;
}
use LoopyTrait { eat as protected ; }
public $baz = true;
...
}
class Foo {
use BarTrait;
}
class Foo {
use BarTrait;
use FooTrait, BazingaTrait{BarTrait::method_name insteadof FooTrait; BazingaTrait::method_name
as bazinga_method;
};
public $baz = true;
...
}
|
Usage in WordPress Core
Interfaces could already previously be used in WordPress Core and are encouraged to be used to clarify the public interface of sets of related classes.
Traits may be used in WordPress Core, though it should be carefully evaluated in each individual instance whether using a trait is the right decision from an architectural point of view.
Type declarations
Proposed standards:
- Type declarations must have exactly one space before and after the type.
In case of a multi-line function declaration, a new line + appropriate indentation should be used before the type declaration.
- The nullability operator is regarded as part of the type declaration and there should be no space between this operator and the actual type.
- Keyword-based type declarations should use lowercase.
- Class/interface name based type declarations should use the case of the class/interface name as declared.
And specifically for return type declarations:
- There should be no space between the closing parenthesis of the function declaration and the colon starting a return type.
These rules apply to all structures allowing for type declarations: functions, closures, catch
conditions as well as the PHP 7.4 arrow functions and typed properties.
Code example
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | function foo( Class_Name $param_a , ?string $param_b , callable $param_c ): ?\Class_Name {
}
function bar(
Interface_Name $param_a ,
?int $param_b ,
bool $param_c
): ?\Class_Name {
}
function baz(Class_Name $param_a , ? Float $param_b , CALLABLE $param_c ) : ? \Class_Name{
}
|
Usage in WordPress Core
While rare, array and class/interface name based type declarations already exist in WordPress Core.
Adding type declarations to existing WordPress Core functions should be done with extreme care.
The function signature of any function (method) which can be overloaded by plugins or themes should not be touched.
This includes all existing public
and protected
class methods and any conditionally declared (pluggable) functions in the global namespace.
This leaves, for now, only unconditionally declared functions in the global namespace, private class methods and code newly being introduced as candidates for adding type declarations.
For those, adding callable
, class and interface name based parameter type declarations where the parameter type only expects one type and it would allow for simplification of existing/new code is allowed and tentatively encouraged.
Using the array
keyword in type declarations is strongly discouraged for now, as most often, it would be better to use iterable
to allow for more flexibility in the implementation and that keyword is not yet available for use in WordPress Core until the minimum requirements are upped to PHP 7.1.
Note:
- The scalar
bool
, int
, float
and string
type declarations can not be used in WordPress Core until the minimum PHP version has been raised to PHP 7.0.
- Return type declarations can not be used until the minimum PHP version has been raised to PHP 7.0.
- Nullable type declarations can not be used until the minimum PHP version has been raised to PHP 7.1.
- The
iterable
, void
and object
type declarations can not be used until the minimum PHP version has been raised to PHP 7.1 and 7.2 respectively.
- Property type declarations can not be used until the minimum PHP version has been raised to PHP 7.4.
Declare statements / strict typing
Proposed standards:
- There should be exactly one blank line above the
declare
statement and at least one blank line below.
- The keywords used –
declare
, strict_types
, ticks
and encoding
– should be lowercase.
- There should be no space between the
declare
keyword and the open parenthesis.
- There should be no space on the inside of the parentheses.
- There should be no space on either side of the
=
operator used within declare
statements.
-
declare
statements using the curly brace block syntax are allowed for ticks
only. For declare
statements using the curly brace block syntax:
- There should be exactly one space between the closing parenthesis and the opening curly brace and the opening curly should be the last code element on the line.
- The block contents should be indented one tab in from the indentation of the
declare
keyword.
- And the closing curly brace should be on a line by itself with no blank line above it and at least one blank line below it.
Note: these standards are different from those used for function calls. Keep in mind that declare
is not a function.
Code example
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | <?php
declare (strict_types=1);
use ...
declare (ticks=1) {
}
<?php
declare ( strict_types = 1 );
use ...
|
Usage in WordPress Core
Strict typing should not be used in WordPress Core at this time.
It is a PHP 7.0+ feature, but even when WordPress Core would get a PHP 7.0 minimum requirement, implementing strict typing will need careful consideration as a lot of WordPress Core relies on the loose type nature of PHP, so this is not something to be undertaken lightly and is not on the agenda for the foreseeable future.
The other declare
statements, ticks
and encoding
, can be used in WordPress Core when appropriate.
The ::class
constant
Proposed standards:
- There should be no space between
::class
and the preceding class name it applies to.
- There should be no space between the double colon and the
class
keyword.
- The
class
keyword should be in lowercase.
Code example
1 2 3 4 5 | add_action( 'action_name' , array ( My_Class:: class , 'method_name' ) );
add_action( 'action_name' , array ( My_Class :: CLASS, 'method_name' ) );
|
Usage in WordPress Core
The ::class
constant can be freely used in WordPress Core.
Replacing existing uses of __CLASS__
with self::class
and get_called_class()
with static::class
, where appropriate, is encouraged.
Operators
Spread operator ...
Proposed standards:
- There should be one space, or a new line + appropriate indentation, before the spread operator.
- There should be no space between the spread operator and the variable/function call it applies to.
- When combining the spread operator with the reference operator, there should be no space between them.
Related open WPCS issue: http://wayback.fauppsala.se:80/wayback/20200321162927/https://github.com/WordPress/WordPress-Coding-Standards/issues/1762
Code example
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | function foo( &... $spread ) {
bar( ... $spread );
bar(
array ( ... $foo ),
... array_values ( $keyed_array )
);
}
function fool( & ... $spread ) {
bar(...
$spread );
bar(
[... $foo ],... array_values ( $keyed_array )
);
}
|
Usage in WordPress Core
The spread operator for packing arguments in function declarations and unpacking them in function calls has been introduced in WordPress Core in WP 5.3 and can be freely used when appropriate.
If you want to learn more about the caveats of when the spread operator can/can not be used, reading the implementation notes in the associated Trac ticket is highly recommended.
The spread operator can not be used to unpack arrays until the minimum PHP version has been raised to PHP 7.4.
instanceof
, pow **
, pow equals **=
, spaceship <=>
, null coalesce ??
and null coalesce equals ??=
The already existing rules regarding operators apply:
Always put spaces on both sides of logical, comparison, string and assignment operators.
Equality operators in blocks of code should be aligned for readability.
Usage in WordPress Core
instanceof
could already be used in WordPress Core and it is encouraged to use this operator instead of a function call to is_a()
as it is more performant.
The pow **
and pow equals **=
operators can be freely used in WordPress Core and have been introduced in WP 5.3.
The spaceship <=>
, null coalesce ??
and null coalesce equals ??=
operators can not be used in WordPress Core until the minimum PHP version has been raised to PHP 7.0 (spaceship and null coalesce) or PHP 7.4 (null coalesce equals).
Additional new rules
One class-like definition per file
Proposed standards:
- There should only be one class-like definition (class/trait/interface) per file.
This has already been a best practice for a while and will now be formalized.
Related open WPCS PR: http://wayback.fauppsala.se:80/wayback/20200321162927/https://github.com/WordPress/WordPress-Coding-Standards/pull/1802
Visibility should always be declared
Proposed standards:
- For all constructs which allow it (properties, methods), visibility should be explicitly declared.
- Using the
var
keyword for property declarations is not allowed.
This has already been a best practice for a while and will now be formalized.
Code example
1 2 3 4 5 6 7 8 9 10 11 12 13 | class Foo {
public $foo ;
protected function bar() {}
}
class Foo {
var $foo ;
function bar() {}
}
|
Usage in WordPress Core
If any visibility modifiers are missing in WordPress Core code, they should be set to public
so as not to break backward-compatibility.
Visibility for class constants can not be used in WordPress Core until the minimum PHP version has been raised to PHP 7.1 (and won’t be enforced until that time).
Property and method modifier order
Proposed standards:
- When using multiple modifiers for a property or method declaration, the order should be as follows:
- First the optional
abstract
or final
keyword.
- Next a visibility keyword.
- Lastly, the optional
static
keyword.
This has already been a best practice for a while and will now be formalized.
Code example
1 2 3 4 5 6 7 8 9 10 11 12 13 | abstract class Foo {
public static $foo ;
abstract protected static function bar();
}
abstract class Foo {
static public $foo ;
static abstract protected function bar();
}
|
Object instantiation
Proposed standards:
- When instantiating a new instance of an object, parenthesis must always be used, even when not strictly necessary.
- There should be no space between the name of the class being instantiated and the opening parenthesis.
- Assigning the return value of an object instantiation by reference is not allowed.
New by reference has not been supported by PHP for quite a long while now.
This has already been a best practice for a while and will now be formalized.
Code example
1 2 3 4 5 6 7 8 | $foo = new Foo();
$anon = new class () { ... };
$instance = new static ();
$foo = & new Foo;
$foo = new Foo ();
|
Function closing brace
Proposed standards:
- There should be no blank line between the content of a function and the function’s closing brace.
Code example
1 2 3 4 5 6 7 8 9 10 | function foo() {
}
function foo() {
}
|
Method chaining
Proposed standards:
- When chaining method calls over multiple lines, subsequent lines should be indented at least one tab in from the start of the statement and have no more than one tab indent difference between the indentation of the current line and indentation of the previous line.
- The arrow should be placed on the same line as the subsequent method call.
Code example
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | $someObject
->doSomething()
->doSomethingElse();
$someObject
->startSomething()
->someOtherFunc(23, 42)
->endSomething();
$someObject
->startSomething()->
someOtherFunc(23, 42)
->endSomething();
|
Include/Require
Proposed standards:
- No parentheses shall be used for
include[_once]
and require[_once]
statements.
As include[_once]
and require[_once]
are language constructs, they do not need parentheses around the path.
- There should be exactly one space between the
include[_once]
and require[_once]
keyword and the start of the path.
- It is strongly recommended to use
require[_once]
for unconditional includes.
When using include[_once]
PHP will throw a warning
when the file is not found, but will continue execution which will almost certainly lead to other errors/warnings/notices being thrown if your application depends on the file being available, potentially leading to security leaks. For that reason, require[_once]
is generally the better choice as it will throw a Fatal Error
if the file cannot be found.
This has already been a best practice for a while and will now be formalized.
Related open WPCS PR: http://wayback.fauppsala.se:80/wayback/20200321162927/https://github.com/WordPress/WordPress-Coding-Standards/pull/1862
Code example
1 2 3 4 5 | require_once ABSPATH . 'filename.php' ;
include_once ( ABSPATH . 'filename.php' );
|
Increment/decrement operators
Proposed standards:
- There should be no space between an increment/decrement operator and the variable it applies to.
- Pre-increment/decrement should be favoured over post-increment/decrement for stand-alone statements.
“Pre” will in/decrement and then return, “post” will return and then in/decrement.
Using the “pre” version is slightly more performant and can prevent future bugs when code gets moved around.
Related open WPCS issue: http://wayback.fauppsala.se:80/wayback/20200321162927/https://github.com/WordPress/WordPress-Coding-Standards/issues/1511
Code example
1 2 3 4 5 6 7 8 9 | for ( $i = 0; $i < 10; $i ++ ) {}
-- $a ;
for ( $i = 0; $i < 10; $i ++ ) {}
$a --;
|
Magic constants
Proposed standards:
- The PHP native
__...__
magic constants should be in uppercase when used.
Code example
1 2 3 4 5 6 7 8 9 | add_action( 'action_name' , array ( __CLASS__ , 'method_name' ) );
require_once __DIR__ . '/relative-path/file-name.php' ;
add_action( 'action_name' , array ( __class__ , 'method_name' ) );
require_once __dIr__ . '/relative-path/file-name.php' ;
|
Shell commands
Proposed standards:
- Use of the backtick operator is not allowed.
This has already been a best practice for a while and will now be formalized.
Complex control structure conditions
A control structure statement with multiple conditions can make for very long lines making code harder to read.
It is encouraged (but not enforced) that these long conditions are split into multiple lines.
When a long condition statement is split over multiple lines, the following (new) rules are proposed in addition to the existing rules for control structure formatting:
- The first condition should be on the same line as the control structure keyword.
- The closing parenthesis for the control structure should be on a new line, indented the same as the control structure keyword and followed by a space and the opening curly brace of the control structure.
- When splitting the conditions into multiple lines, the boolean/logical operators separating the statements should always be placed at the start of the new line.
This makes for smaller change-sets and improves readability.
Note: even with conditions spread out over multiple lines, multiple conditions per line will still be allowed as long as the condition grouping makes sense.
Code example
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | if ( function_call( $a , $b , $c ) === false && ( isset( $d , $e , $f ) && function_call( $d , $e , $f ) === true ) && function_call( $g , $h , $i ) === false ) {
}
if ( function_call( $a , $b , $c ) === false
&& ( isset( $d , $e , $f ) && function_call( $d , $e , $f ) === true )
&& function_call( $g , $h , $i ) === false
) {
}
if (
function_call( $a , $b , $c ) === false &&
( isset( $d , $e , $f ) && function_call( $d , $e , $f ) === true )
&& function_call( $g , $h , $i ) === false ) {
}
|
Feedback
Feedback on the standards proposed here is welcome in the comments.
If there are other PHP constructs and language features for which you’d like to see coding standards defined, please open an issue in the WordPress Coding Standards GitHub repository.
Kind request: while I realize that the existing stance on disallowing short array syntax is a hot topic for some people, please do not pollute the discussion about the standards which are currently being proposed by re-opening that discussion in the comments.
Short array syntax will be revisited at a later time, but is not part of the current proposal. Thank you in advance for your understanding.
Previous posts on this subject:
Props: Graceful thanks go out to @dingo_d, @garyj, @netweb, @nielsdeblaauw, @pento, @schlessera, and @SergeyBiryukov for reviewing this post prior to publication.
+make.wordpress.org/themes
Great step in the right direction! Standardizing modern constructs for WordPress helps the entire ecosystem.
Why are we still using class-, interface-, and trait- file naming conventions? Seems like this is a good opportunity to support this legacy mechanism (even for core), while opening up PSR-4 autoloading options for distributable plugins?
Plugins have the freedom to deviate from the above, if they so choose.
As side-note: classmap based autoloading is much more performant than PSR-4 and the current proposal does not inhibit that at all.
Sure but it’s not ideal for development as you have to regen the classmap every time you add a new class.
Dev-convenience should not be a reason for bad choices for production.
Regen of a classmap can be automated if needs be.
That’s not entirely true. Autoloading has the ability to generate a classmap using
composer dump-autoload --optimize-autoloader
.Sorry, just checking – but what about my statement isn’t true ? Your example, to me, just seems to confirm and harden what I said.
PSR-4 Autoloaders is the most easiest to pickup, so I would ask to have:
/Models/Car/GreatCar.php – class
/Models/Car/CarTrait.php – Trait
/Models/Car/CarInferface.php – Interface
/Models/Car/AbstractCar.php – abstract class
Also do not forget to follow as much as possible of PSR-2.
And I DO NOT think that we must required spaces inside IF’s brackets, meaning, this should be valid:
if ($a)
{
<...>
}
And this as well
add_action('action_name', array( __CLASS__, 'method_name'));
Those extra spaces SLOWS down the coding speed, and ARE NOT described in PSR-2 coding standard.
PSR2 has been superseded by PSR12, so PSR2 is not relevant anymore.
A lot of the current proposals are in line with PSR12, but this proposal is not about changing existing standard (spaces inside parentheses), it is about adding to them and clarifying them where necessary.
As Juliette mentioned, in the themes and plugins, you are free to use whatever you want. These are more WP core related standards that you can but don’t have to, follow in your themes/plugins.
Oh and I recommend using PSR-12, it’s a superset of PSR-2 with more emphasis on modern coding practices 🙂
However, through the entire article, there are recommendations and then core recommendations. So it seems their is confusion about this. If this is mainly core, why are there specific callouts for “Core usage”?
These standards are for the whole WP community and will apply to WP Core development.
Plugins and themes have the freedom to choose to adopt them or not.
As some of these standards involve PHP features which may not be available for use yet in WP Core, due to either ongoing architectural discussions or due to the minimum PHP version not being high enough, I’ve chosen to clarify when certain features can be used in WP Core.
Again, plugins and themes can choose to use a different minimum PHP version, so those asides may not apply to them.
The one about method chaining makes no sense. Is the example for correct code actually correct?
Yes. What do you think is wrong with it ?
three arrows but the middle one indented more than the others
That’s under the new rules allowed, but not required.
The additional indentation in the middle is unexpected. There should probably be a second example without such extra indentation.
Good point. I’ve added an extra example now.
It just doesn’t seem to match what the rule said. It seemed like the rule was saying that each chained method would be indented more. But that seems hard to read. And the way that correct code looks is hard to read.
This seems off to me. I think in most arrays used in WordPress
iterable
wouldn’t be a sufficient type since you can’t arbitrarily retrieve a value by a key. So, for instance,wp_insert_post
could never be typed as aniterable
but could be typed as anarray
. It is also already being used by WordPress Core in things likepopulate_site_meta
, Recovery Mode, the Customizer, the REST API, etc…I think we gain value by having an
array
typehint in those places, and we should continue adding it or even expanding our usage when possible.If
array
type declarations would be introduced in those places, it would be a breaking function signature change if this would later be changed toiterable
(or `ArrayAccess` etc) when the underlying structure would be changed to a Value Object, for instance, with the option remaining to pass in anarray
instead of the Value Object.As WP is notorious for avoiding breaking changes, introducing
array
type declarations would inhibit those type of refactors of underlying structures for the future, which IMO is detrimental to the project as a whole.Let’s take a look at populate_site_meta for instance. Let’s say we wanted to add support to passing in an ArrayAccess instance. We’d simply remove the array type declaration. If the function currently had no type signature, then adding ArrayAccess as a signature would be a BC break because anyone who is passing an array would now have their code broken.
Now, let’s say we change it to iterable. Well then there isn’t any BC break to the function signature since an array would be accepted there.
However, the body of the function would require changes. For instance, we’d need to immediately convert the iterable to an array since we filter that value. And any code that used that filter to `unset` an item of the list would break if it was passed a generator, for instance. ( not to mention the fact that you would have issues if more than one person iterated over that list, since you can’t rewind generators ).
The only place where we’d have a BC issue in the signature ( going from array to iterable ) would be in an API where it was expected & supported for the user to override the method. ( Adding the type signature at all would be a BC break as well. ) But ignoring all that, just changing to support an iterable would be a BC break as well, even if you didn’t do any signature changes for the same reason I mentioned in the previous paragraph. If the code isn’t expecting an iterable, and only an array, than there are a myriad of different ways the code could break.
The signature merely enforces the actual breakage that would be occurring.
I see this “notoriousness” as a big plus for WordPress and a big win for all WordPress users. It’s probably one of the reason that led to 35% of all websites on the Internet using WordPress 🙂
I’d be firmly against any changes to the PHP Coding Standards that even remotely suggest possible breakage of backwards compatibility.
Glad you agree. My use of notorious meant exactly that and is why the use of
array
type declarations is being discouraged for the time being.+make.wordpress.org/docs
Thank you @jrf for the work and for this detailed post. It’s nice to see all of these being standardised in WordPress <3
Thanks for your kind words!
+make.wordpress.org/plugins/
If we are going PSR4 why not split cores into packages just like Gutenberg and we can only include packages we wnat.
And also with dependency injection pattern we can achieve much more
Please join the discussion about the future architecture of WordPress for that.
This article is not about that.
On the note of PHP Standards, can we also disallow error suppressing `@` please? See #24780
That’s already disallowed: http://wayback.fauppsala.se:80/wayback/20200321162927/https://make.wordpress.org/core/handbook/best-practices/coding-standards/php/#error-control-operator
@jrf Wow, this is a -HUGE- post, thanks for putting it all together! Most of the changes look pretty good, but see several that would need more considerations/refining or more reasoning.
Thinking this is probably not the best format for a discussion. There are a lot of cases and descriptions making it pretty difficult to follow and comment on all of them.
As far as I see there are three groups of proposals for the WordPress PHP Coding Standards here:
1. Proposals for additions to the standards.
2. Proposals for changes of the current standards.
3. Suggestions for clarifications of some standards.
I’d think it would be quite better to make the proposals for additions and changes in separate posts so they can be discussed properly.
For example the proposals around formatting of namespace declarations and related additions would be much easier to discuss (and make a decision) if they were in a separate post. Same for the proposals for changes and additions to classes and class related code formatting.
The proposals for changes to the current standards would definitely be better discussed in another post. Ideally there will be reasons why the standard should change and examples of other popular standards.
The suggestions for clarifications of existing standards should also be considered carefully, ideally in a separate post.
@azaozz I understand your suggestion for splitting it in several posts and will keep it in mind for the future.
The current proposals, however, are all additions to the current standards. A separate post will be published in the future with proposals for changing some of the existing standards.
In the mean time, a number of the current proposals have their own WPCS issue, so if it would make you more comfortable discussing them one by one, commenting on those may be the way to go.
Another consideration should probably be the syncing (or overlapping) between the PHP and JavaScript standards. There’s a recent post about changes to the JavaScript coding standards to facilitate adopting of Prettier (with some tweaks). I won’t be surprised to see the CSS coding standards adopting it too.
There is also a community effort to make a PHP plugin for Prettier which probably deserves a look 🙂
Interesting, but not all that applicable. Using JS tooling for JS and PHP tooling for PHP makes a lot more sense to me.
From what I can see, available rules are limited, though CSFixer integration is possible (not PHPCS though).
Either way I don’t think that tooling will be suitable, for the same reasons PHPCS is used over CS-Fixer: it doesn’t allow for any issues to be reported which are not auto-fixable and especially with the security checks build into WPCS, it is necessary to be able to report issues without auto-fixing them.
Why just not to apply PSR12 to WP Core? Maybe in the past WordPress (community) needed own coding standards in due to absence global PHP community standards. But nowadays it is no longer necessary to support own Coding Standards because it is some kind of reinvention of the wheel that only slows down WordPress development.
In my opinion, WordPress need to migrate to common standards of PHP Community. There is no any problems backward compatibility. We can create compatibility layer for current class naming with class_alias() function. It is not a problem to write some automation script that do most part of renaming work.
WordPress are biggest platform in the Internet and WordPress should be the leader of the entire PHP-community, not the catch-up. I will repeat myself and there is no any big problem to create compatibility layer and write code with modern standards and approaches. This changes will open the way for many new developers from other platforms and frameworks.
Ideally, as said @meshakeeb, WordPress need to be splited to few packages by default which make development much easier. WordPress officially should be something bigger than simple CMS for blogging. In fact, it happened many years ago. But it is another topic for discussion.
Amazing post!
Waiting to see all the errors reported on my usual coding with WPCS 😂