From 0076d49824a39f4f9b9f155287a42f835b0d457b Mon Sep 17 00:00:00 2001 From: Rodrigo Primo Date: Tue, 15 Jul 2025 17:01:46 -0300 Subject: [PATCH 001/105] NamingConventions/ValidFunctionName: rename test case file This is necessary to be able to create more test case files with syntax errors in a future commit. --- ...st.inc => ValidFunctionNameUnitTest.1.inc} | 0 .../ValidFunctionNameUnitTest.php | 68 +++++++++++-------- 2 files changed, 38 insertions(+), 30 deletions(-) rename WordPress/Tests/NamingConventions/{ValidFunctionNameUnitTest.inc => ValidFunctionNameUnitTest.1.inc} (100%) diff --git a/WordPress/Tests/NamingConventions/ValidFunctionNameUnitTest.inc b/WordPress/Tests/NamingConventions/ValidFunctionNameUnitTest.1.inc similarity index 100% rename from WordPress/Tests/NamingConventions/ValidFunctionNameUnitTest.inc rename to WordPress/Tests/NamingConventions/ValidFunctionNameUnitTest.1.inc diff --git a/WordPress/Tests/NamingConventions/ValidFunctionNameUnitTest.php b/WordPress/Tests/NamingConventions/ValidFunctionNameUnitTest.php index 6dbd5e8cf1..3b1ef5c712 100644 --- a/WordPress/Tests/NamingConventions/ValidFunctionNameUnitTest.php +++ b/WordPress/Tests/NamingConventions/ValidFunctionNameUnitTest.php @@ -25,38 +25,46 @@ final class ValidFunctionNameUnitTest extends AbstractSniffUnitTest { /** * Returns the lines where errors should occur. * + * @param string $testFile The name of the file being tested. + * * @return array Key is the line number, value is the number of expected errors. */ - public function getErrorList() { - return array( - 3 => 1, - 9 => 1, - 13 => 1, - 15 => 1, - 79 => 2, - 80 => 2, - 81 => 2, - 82 => 2, - 83 => 2, - 84 => 2, - 85 => 2, - 86 => 2, - 87 => 2, - 88 => 2, - 89 => 2, - 106 => 2, - 116 => 1, - 117 => 1, - 157 => 2, - 183 => 1, - 184 => 1, - 185 => 1, - 199 => 1, - 208 => 2, - 210 => 1, - 223 => function_exists( 'mb_strtolower' ) ? 1 : 0, - 224 => 1, - ); + public function getErrorList( $testFile = '' ) { + switch ( $testFile ) { + case 'ValidFunctionNameUnitTest.1.inc': + return array( + 3 => 1, + 9 => 1, + 13 => 1, + 15 => 1, + 79 => 2, + 80 => 2, + 81 => 2, + 82 => 2, + 83 => 2, + 84 => 2, + 85 => 2, + 86 => 2, + 87 => 2, + 88 => 2, + 89 => 2, + 106 => 2, + 116 => 1, + 117 => 1, + 157 => 2, + 183 => 1, + 184 => 1, + 185 => 1, + 199 => 1, + 208 => 2, + 210 => 1, + 223 => function_exists( 'mb_strtolower' ) ? 1 : 0, + 224 => 1, + ); + + default: + return array(); + } } /** From 328d7026da7aa0cdc3413c9e7fcaa5655ed674f0 Mon Sep 17 00:00:00 2001 From: Rodrigo Primo Date: Tue, 15 Jul 2025 17:04:31 -0300 Subject: [PATCH 002/105] NamingConventions/ValidFunctionName: move test with intentional parse error to a separate file --- .../NamingConventions/ValidFunctionNameUnitTest.1.inc | 4 ---- .../NamingConventions/ValidFunctionNameUnitTest.2.inc | 8 ++++++++ 2 files changed, 8 insertions(+), 4 deletions(-) create mode 100644 WordPress/Tests/NamingConventions/ValidFunctionNameUnitTest.2.inc diff --git a/WordPress/Tests/NamingConventions/ValidFunctionNameUnitTest.1.inc b/WordPress/Tests/NamingConventions/ValidFunctionNameUnitTest.1.inc index 6a06ba3cab..0eb5f7f67c 100644 --- a/WordPress/Tests/NamingConventions/ValidFunctionNameUnitTest.1.inc +++ b/WordPress/Tests/NamingConventions/ValidFunctionNameUnitTest.1.inc @@ -222,7 +222,3 @@ enum Suit { function lähtöaika() {} // OK. function lÄhtÖaika() {} // Bad, but only handled by the sniff if Mbstring is available. function lÄhtOaika() {} // Bad, handled via transliteration of non-ASCII chars if Mbstring is not available. - -// Live coding/parse error. -// This has to be the last test in the file. -function diff --git a/WordPress/Tests/NamingConventions/ValidFunctionNameUnitTest.2.inc b/WordPress/Tests/NamingConventions/ValidFunctionNameUnitTest.2.inc new file mode 100644 index 0000000000..4f73e110db --- /dev/null +++ b/WordPress/Tests/NamingConventions/ValidFunctionNameUnitTest.2.inc @@ -0,0 +1,8 @@ + Date: Tue, 15 Jul 2025 17:19:04 -0300 Subject: [PATCH 003/105] NamingConventions/ValidFunctionName: add tests using readonly anonymous classes This commit adds a few tests using readonly anonymous classes to the `WordPress.NamingConventions.ValidFunctionName` tests. This is just to ensure that the part of the sniff code that checks for `T_ANON_CLASS` tokens works correctly with readonly anonymous class added in PHP 8.3. The sniff was already handling readonly anonymous classes correctly, and no change to the sniff code is needed. --- .../NamingConventions/ValidFunctionNameUnitTest.1.inc | 9 +++++++++ .../NamingConventions/ValidFunctionNameUnitTest.php | 2 ++ 2 files changed, 11 insertions(+) diff --git a/WordPress/Tests/NamingConventions/ValidFunctionNameUnitTest.1.inc b/WordPress/Tests/NamingConventions/ValidFunctionNameUnitTest.1.inc index 0eb5f7f67c..4fa7a05ed8 100644 --- a/WordPress/Tests/NamingConventions/ValidFunctionNameUnitTest.1.inc +++ b/WordPress/Tests/NamingConventions/ValidFunctionNameUnitTest.1.inc @@ -222,3 +222,12 @@ enum Suit { function lähtöaika() {} // OK. function lÄhtÖaika() {} // Bad, but only handled by the sniff if Mbstring is available. function lÄhtOaika() {} // Bad, handled via transliteration of non-ASCII chars if Mbstring is not available. + +/* + * Safeguard that PHP 8.3+ readonly anonymous classes are handled correctly. + */ +$anon_class = new readonly class() { + public function camelCase() {} // Bad. + protected function __something() {} // Bad. + private function snake_case() {} // Ok. +}; diff --git a/WordPress/Tests/NamingConventions/ValidFunctionNameUnitTest.php b/WordPress/Tests/NamingConventions/ValidFunctionNameUnitTest.php index 3b1ef5c712..349091a4d8 100644 --- a/WordPress/Tests/NamingConventions/ValidFunctionNameUnitTest.php +++ b/WordPress/Tests/NamingConventions/ValidFunctionNameUnitTest.php @@ -60,6 +60,8 @@ public function getErrorList( $testFile = '' ) { 210 => 1, 223 => function_exists( 'mb_strtolower' ) ? 1 : 0, 224 => 1, + 230 => 1, + 231 => 1, ); default: From d541631e9322d43f86fafc392df78593407f42b5 Mon Sep 17 00:00:00 2001 From: Rodrigo Primo Date: Wed, 16 Jul 2025 10:11:12 -0300 Subject: [PATCH 004/105] NamingConventions/PrefixAllGlobals: modify a test to use readonly anonymous classes This commit modifies an existing test to use readonly anonymous classes to the `WordPress.NamingConventions.PrefixAllGlobals` tests. This is just to ensure that the part of the sniff code that checks for `T_ANON_CLASS` tokens works correctly with readonly anonymous class added in PHP 8.3. The sniff was already handling readonly anonymous classes correctly, and no change to the sniff code is needed. --- .../Tests/NamingConventions/PrefixAllGlobalsUnitTest.1.inc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/WordPress/Tests/NamingConventions/PrefixAllGlobalsUnitTest.1.inc b/WordPress/Tests/NamingConventions/PrefixAllGlobalsUnitTest.1.inc index cdbe22dbcb..6daa33b82f 100644 --- a/WordPress/Tests/NamingConventions/PrefixAllGlobalsUnitTest.1.inc +++ b/WordPress/Tests/NamingConventions/PrefixAllGlobalsUnitTest.1.inc @@ -137,7 +137,7 @@ class Acronym_Example { function do_something( $param = 'default' ) {} } -$acronym_class = new class { +$acronym_class = new readonly class { const SOME_CONSTANT = 'value'; public $var = 'abc'; From 9e94d3b810fb20736b265c4390dcd1ad6e4ac4e9 Mon Sep 17 00:00:00 2001 From: Rodrigo Primo Date: Thu, 17 Jul 2025 11:00:18 -0300 Subject: [PATCH 005/105] NamingConventions/PrefixAllGlobals: add tests using asymmetric visibility properties This commit adds a few tests using asymmetric visibility properties (including in constructor property promotion) to the `WordPress.NamingConventions.PrefixAllGlobals` tests. This is just to ensure that the part of the sniff code that ignores properties or method parameters (in the case of constructor property promotion) continues to handle PHP 8.4+ asymmetric visibility properties correctly. No change to the sniff code is needed. --- .../NamingConventions/PrefixAllGlobalsUnitTest.1.inc | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/WordPress/Tests/NamingConventions/PrefixAllGlobalsUnitTest.1.inc b/WordPress/Tests/NamingConventions/PrefixAllGlobalsUnitTest.1.inc index cdbe22dbcb..7fff84a00f 100644 --- a/WordPress/Tests/NamingConventions/PrefixAllGlobalsUnitTest.1.inc +++ b/WordPress/Tests/NamingConventions/PrefixAllGlobalsUnitTest.1.inc @@ -673,4 +673,14 @@ class WP_Atom_Server { } } +/* + * Safeguard that PHP 8.4+ asymmetric visibility properties don't lead to false positives. + * Including those defined using constructor property promotion. + */ +class Acronym_AsymmetricVisibilityProperties { + public private(set) string $bar = 'bar'; // Ok. + + public function __construct(public protected(set) int $foo = 0) {} // Ok. +} + // phpcs:set WordPress.NamingConventions.PrefixAllGlobals prefixes[] From fb50666da90d89fc156a5de06d410f22cdc408e4 Mon Sep 17 00:00:00 2001 From: Rodrigo Primo Date: Thu, 17 Jul 2025 11:27:40 -0300 Subject: [PATCH 006/105] NamingConventions/ValidVariableName: add tests using asymmetric visibility properties This commit adds a few tests using asymmetric visibility properties (including in constructor property promotion) to the `WordPress.NamingConventions.ValidVariableName` tests. This is just to ensure that the sniff continues to apply its variable name rules when dealing with asymmetric visibility properties added in PHP 8.4. The sniff was already handling asymmetric visibility properties correctly, and no change to the sniff code is needed. --- .../Tests/NamingConventions/ValidVariableNameUnitTest.inc | 8 ++++++++ .../Tests/NamingConventions/ValidVariableNameUnitTest.php | 1 + 2 files changed, 9 insertions(+) diff --git a/WordPress/Tests/NamingConventions/ValidVariableNameUnitTest.inc b/WordPress/Tests/NamingConventions/ValidVariableNameUnitTest.inc index a8cac33a54..ec7c009cef 100644 --- a/WordPress/Tests/NamingConventions/ValidVariableNameUnitTest.inc +++ b/WordPress/Tests/NamingConventions/ValidVariableNameUnitTest.inc @@ -237,3 +237,11 @@ class Has_Mixed_Case_Property { $lähtöaika = true; // OK. $lÄhtÖaika = true; // Bad, but only handled by the sniff if Mbstring is available. $lÄhtOaika = true; // Bad, handled via transliteration of non-ASCII chars if Mbstring is not available. + +/* + * Safeguard that the sniff handles PHP 8.4+ asymmetric visibility properties correctly. + */ +class Acronym_AsymmetricVisibilityProperties { + public private(set) string $valid_name = 'bar'; // Ok. + public(set) string $invalidName = 'bar'; // Bad. +} diff --git a/WordPress/Tests/NamingConventions/ValidVariableNameUnitTest.php b/WordPress/Tests/NamingConventions/ValidVariableNameUnitTest.php index 68b2b64a5c..0ac884c991 100644 --- a/WordPress/Tests/NamingConventions/ValidVariableNameUnitTest.php +++ b/WordPress/Tests/NamingConventions/ValidVariableNameUnitTest.php @@ -98,6 +98,7 @@ public function getErrorList() { 227 => 1, 238 => function_exists( 'mb_strtolower' ) ? 1 : 0, 239 => 1, + 246 => 1, ); } From 88d311f98159af6fde422f16e250e7c2b8e8b7fc Mon Sep 17 00:00:00 2001 From: Rodrigo Primo Date: Thu, 17 Jul 2025 15:05:24 -0300 Subject: [PATCH 007/105] Security/NonceVerification: add test using asymmetric visibility properties This commit adds a test using asymmetric visibility properties to the `WordPress.Security.NonceVerification` tests. This is just to ensure that the sniff continues to ignore PHP 8.4+ asymmetric visibility properties. The sniff was already handling asymmetric visibility properties correctly, and no change to the sniff code is needed. --- WordPress/Tests/Security/NonceVerificationUnitTest.8.inc | 1 + 1 file changed, 1 insertion(+) diff --git a/WordPress/Tests/Security/NonceVerificationUnitTest.8.inc b/WordPress/Tests/Security/NonceVerificationUnitTest.8.inc index c2c134ddb7..7d3a70d8b6 100644 --- a/WordPress/Tests/Security/NonceVerificationUnitTest.8.inc +++ b/WordPress/Tests/Security/NonceVerificationUnitTest.8.inc @@ -3,4 +3,5 @@ class IgnoreProperties { public $_GET = array( 'key' => 'something' ); // OK. public $_POST; // OK. + public private(set) string $_REQUEST; // Ok. } From f5ebe184f3add29e3d212024d2634a3ef2df37ba Mon Sep 17 00:00:00 2001 From: Rodrigo Primo Date: Thu, 17 Jul 2025 15:30:22 -0300 Subject: [PATCH 008/105] WP/GlobalVariablesOverride: move parse error test to its own file Also update code comment related to the moved parse error test to include one more case where the code might bow out. --- WordPress/Sniffs/WP/GlobalVariablesOverrideSniff.php | 2 +- WordPress/Tests/WP/GlobalVariablesOverrideUnitTest.1.inc | 4 ---- WordPress/Tests/WP/GlobalVariablesOverrideUnitTest.8.inc | 8 ++++++++ 3 files changed, 9 insertions(+), 5 deletions(-) create mode 100644 WordPress/Tests/WP/GlobalVariablesOverrideUnitTest.8.inc diff --git a/WordPress/Sniffs/WP/GlobalVariablesOverrideSniff.php b/WordPress/Sniffs/WP/GlobalVariablesOverrideSniff.php index ab2aa8bd91..934c3e686b 100644 --- a/WordPress/Sniffs/WP/GlobalVariablesOverrideSniff.php +++ b/WordPress/Sniffs/WP/GlobalVariablesOverrideSniff.php @@ -174,7 +174,7 @@ public function process_token( $stackPtr ) { protected function process_list_assignment( $stackPtr ) { $list_open_close = Lists::getOpenClose( $this->phpcsFile, $stackPtr ); if ( false === $list_open_close ) { - // Short array, not short list. + // Live coding or short array, not short list. return; } diff --git a/WordPress/Tests/WP/GlobalVariablesOverrideUnitTest.1.inc b/WordPress/Tests/WP/GlobalVariablesOverrideUnitTest.1.inc index 80603e7e8b..4daeb20fde 100644 --- a/WordPress/Tests/WP/GlobalVariablesOverrideUnitTest.1.inc +++ b/WordPress/Tests/WP/GlobalVariablesOverrideUnitTest.1.inc @@ -310,7 +310,3 @@ list( array( $tab, $tabs ) => $not_a_wp_global, get($year, $day) => &$not_a_wp_global[$year] ] = $array; - -// Live coding/parse error. -// This has to be the last test in the file! -list( $tab, $tabs diff --git a/WordPress/Tests/WP/GlobalVariablesOverrideUnitTest.8.inc b/WordPress/Tests/WP/GlobalVariablesOverrideUnitTest.8.inc new file mode 100644 index 0000000000..7dba2caad2 --- /dev/null +++ b/WordPress/Tests/WP/GlobalVariablesOverrideUnitTest.8.inc @@ -0,0 +1,8 @@ + Date: Thu, 17 Jul 2025 15:43:24 -0300 Subject: [PATCH 009/105] WP/GlobalVariablesOverride: add tests using asymmetric visibility properties This commit adds a few tests using asymmetric visibility properties (including in constructor property promotion) to the `WordPress.WP.GlobalVariablesOverride` tests. This is just to ensure that the part of the sniff code that ignores properties or method parameters (in the case of constructor property promotion) continues to handle PHP 8.4+ asymmetric visibility properties correctly. No change to the sniff code is needed. --- .../Tests/WP/GlobalVariablesOverrideUnitTest.1.inc | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/WordPress/Tests/WP/GlobalVariablesOverrideUnitTest.1.inc b/WordPress/Tests/WP/GlobalVariablesOverrideUnitTest.1.inc index 4daeb20fde..092fd2e589 100644 --- a/WordPress/Tests/WP/GlobalVariablesOverrideUnitTest.1.inc +++ b/WordPress/Tests/WP/GlobalVariablesOverrideUnitTest.1.inc @@ -310,3 +310,13 @@ list( array( $tab, $tabs ) => $not_a_wp_global, get($year, $day) => &$not_a_wp_global[$year] ] = $array; + +/* + * Safeguard that PHP 8.4+ asymmetric visibility properties don't lead to false positives. + * Including those defined using constructor property promotion. + */ +class AsymmetricVisibilityProperties { + public private(set) string $pagenow = 'bar'; // Ok. + + public function __construct(public protected(set) int $page = 0) {} // Ok. +} From a858fc9f25d71c5003e4bd74c90f48e88bd7022a Mon Sep 17 00:00:00 2001 From: jrfnl Date: Fri, 7 Jun 2024 00:45:07 +0200 Subject: [PATCH 010/105] PHP/YodaConditions: use new Collections::ternaryOperators() token array --- WordPress/Sniffs/PHP/YodaConditionsSniff.php | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/WordPress/Sniffs/PHP/YodaConditionsSniff.php b/WordPress/Sniffs/PHP/YodaConditionsSniff.php index 150993c6a4..cff816119f 100644 --- a/WordPress/Sniffs/PHP/YodaConditionsSniff.php +++ b/WordPress/Sniffs/PHP/YodaConditionsSniff.php @@ -43,10 +43,9 @@ public function register() { $starters = Tokens::$booleanOperators; $starters += Tokens::$assignmentTokens; + $starters += Collections::ternaryOperators(); $starters[ \T_CASE ] = \T_CASE; $starters[ \T_RETURN ] = \T_RETURN; - $starters[ \T_INLINE_THEN ] = \T_INLINE_THEN; - $starters[ \T_INLINE_ELSE ] = \T_INLINE_ELSE; $starters[ \T_SEMICOLON ] = \T_SEMICOLON; $starters[ \T_OPEN_PARENTHESIS ] = \T_OPEN_PARENTHESIS; From f09cf091ba167caa48014591fa3c4a2db8edf049 Mon Sep 17 00:00:00 2001 From: jrfnl Date: Fri, 7 Jun 2024 01:52:55 +0200 Subject: [PATCH 011/105] Files/FileName: start using the PHPCSUtils `FilePath` utility The `FilePath::getName()` method will strip quotes from the file name, as well as normalize the slashes to forward (*nix) slashes. This allows for a minor simplication in the code and improves code readability. --- WordPress/Sniffs/Files/FileNameSniff.php | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/WordPress/Sniffs/Files/FileNameSniff.php b/WordPress/Sniffs/Files/FileNameSniff.php index 72c3e3d44d..2cdbd96d74 100644 --- a/WordPress/Sniffs/Files/FileNameSniff.php +++ b/WordPress/Sniffs/Files/FileNameSniff.php @@ -10,8 +10,8 @@ namespace WordPressCS\WordPress\Sniffs\Files; use PHPCSUtils\Tokens\Collections; +use PHPCSUtils\Utils\FilePath; use PHPCSUtils\Utils\ObjectDeclarations; -use PHPCSUtils\Utils\TextStrings; use WordPressCS\WordPress\Helpers\IsUnitTestTrait; use WordPressCS\WordPress\Sniff; @@ -151,8 +151,7 @@ public function register() { * normal file processing. */ public function process_token( $stackPtr ) { - // Usage of `stripQuotes` is to ensure `stdin_path` passed by IDEs does not include quotes. - $file = TextStrings::stripQuotes( $this->phpcsFile->getFileName() ); + $file = FilePath::getName( $this->phpcsFile ); if ( 'STDIN' === $file ) { return $this->phpcsFile->numTokens; } @@ -197,7 +196,7 @@ public function process_token( $stackPtr ) { $this->check_filename_has_class_prefix( $class_ptr, $file_name ); } - if ( false !== strpos( $file, \DIRECTORY_SEPARATOR . 'wp-includes' . \DIRECTORY_SEPARATOR ) + if ( false !== strpos( $file, '/wp-includes/' ) && false === $class_ptr ) { $this->check_filename_for_template_suffix( $stackPtr, $file_name ); From a74a5795e8b7869459b221223273a5e7ae3a69ce Mon Sep 17 00:00:00 2001 From: jrfnl Date: Fri, 7 Jun 2024 01:53:33 +0200 Subject: [PATCH 012/105] Utils/I18nTextDomainFixer: start using the PHPCSUtils `FilePath` utility The `FilePath::getName()` method will strip quotes from the file name, as well as normalize the slashes to forward (*nix) slashes. This allows for a minor simplication in the code and improves code readability. --- WordPress/Sniffs/Utils/I18nTextDomainFixerSniff.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/WordPress/Sniffs/Utils/I18nTextDomainFixerSniff.php b/WordPress/Sniffs/Utils/I18nTextDomainFixerSniff.php index af176326a6..1d85ea0e1d 100644 --- a/WordPress/Sniffs/Utils/I18nTextDomainFixerSniff.php +++ b/WordPress/Sniffs/Utils/I18nTextDomainFixerSniff.php @@ -11,6 +11,7 @@ use PHP_CodeSniffer\Util\Tokens; use PHPCSUtils\BackCompat\Helper; +use PHPCSUtils\Utils\FilePath; use PHPCSUtils\Utils\GetTokensAsString; use PHPCSUtils\Utils\PassedParameters; use PHPCSUtils\Utils\TextStrings; @@ -675,7 +676,7 @@ public function process_comments( $stackPtr ) { $headers = $this->plugin_headers; $type = 'plugin'; - $file = TextStrings::stripQuotes( $this->phpcsFile->getFileName() ); + $file = FilePath::getName( $this->phpcsFile ); if ( 'STDIN' === $file ) { return; } From 86b43ecac8ee2c3f82fda3c2afe9a8085321cc14 Mon Sep 17 00:00:00 2001 From: jrfnl Date: Fri, 23 Aug 2024 06:39:37 +0200 Subject: [PATCH 013/105] PHP 8.4 | Security/EscapeOutput: handle exit/die using named parameters As of PHP 8.4, the internal of `T_EXIT` are changing in PHP itself and `exit`/`die` will internally be treated as a function call. The net effect of this is that named parameters can now be used with `exit()`/`die()`. For the `WordPress.Security.EscapeOutput` sniff this would lead to false positives as the parameter name would be seen as "not escaped". As of PHPCSUtils 1.1.0, the methods within the `PassedParameters` class will allow for passing a `T_EXIT` token. This, in turn, allows for handling `exit`/`die` with named parameters correctly in the context of the `EscapeOutput` sniff. This commit implements using the `PassedParameters` class for parsing calls to `exit`/`die`, which fixes the issue. Includes tests. Ref: https://wiki.php.net/rfc/exit-as-function --- .../Sniffs/Security/EscapeOutputSniff.php | 20 +++++++++---------- .../Tests/Security/EscapeOutputUnitTest.1.inc | 7 +++++++ .../Tests/Security/EscapeOutputUnitTest.php | 2 ++ 3 files changed, 19 insertions(+), 10 deletions(-) diff --git a/WordPress/Sniffs/Security/EscapeOutputSniff.php b/WordPress/Sniffs/Security/EscapeOutputSniff.php index 7861940caa..5d5a8272a5 100644 --- a/WordPress/Sniffs/Security/EscapeOutputSniff.php +++ b/WordPress/Sniffs/Security/EscapeOutputSniff.php @@ -200,19 +200,19 @@ public function process_token( $stackPtr ) { return parent::process_token( $stackPtr ); case \T_EXIT: - $next_non_empty = $this->phpcsFile->findNext( Tokens::$emptyTokens, ( $stackPtr + 1 ), null, true ); - if ( false === $next_non_empty - || \T_OPEN_PARENTHESIS !== $this->tokens[ $next_non_empty ]['code'] - || isset( $this->tokens[ $next_non_empty ]['parenthesis_closer'] ) === false - ) { - // Live coding/parse error or an exit/die which doesn't pass a status code. Ignore. + $params = PassedParameters::getParameters( $this->phpcsFile, $stackPtr ); + if ( empty( $params ) ) { + // Live coding/parse error or an exit/die which doesn't pass a status. Ignore. return; } - // $end is not examined, so make sure the parentheses are balanced. - $start = $next_non_empty; - $end = ( $this->tokens[ $next_non_empty ]['parenthesis_closer'] + 1 ); - break; + // There should only be one parameter ($status), but just to be on the safe side. + foreach ( $params as $param ) { + $this->check_code_is_escaped( $param['start'], ( $param['end'] + 1 ) ); + } + + // Skip to the end of the last found parameter. + return ( $param['end'] + 1 ); case \T_THROW: // Find the open parentheses, while stepping over the exception creation tokens. diff --git a/WordPress/Tests/Security/EscapeOutputUnitTest.1.inc b/WordPress/Tests/Security/EscapeOutputUnitTest.1.inc index 5309a4693b..eaf96f5ba3 100644 --- a/WordPress/Tests/Security/EscapeOutputUnitTest.1.inc +++ b/WordPress/Tests/Security/EscapeOutputUnitTest.1.inc @@ -655,3 +655,10 @@ echo ''; // Bad. echo ''; // Bad. echo ''; // OK, well not really, typo in param name, but that's not our concern. echo ''; // Bad. + +// PHP 8.4: exit/die using named parameters. +exit( status: esc_html( $foo ) ); // Ok. +die( status: esc_html( $foo ) ); // Ok. + +exit( status: $foo ); // Bad. +die( status: $foo ); // Bad. diff --git a/WordPress/Tests/Security/EscapeOutputUnitTest.php b/WordPress/Tests/Security/EscapeOutputUnitTest.php index 6150a4eeb4..2f70eebaeb 100644 --- a/WordPress/Tests/Security/EscapeOutputUnitTest.php +++ b/WordPress/Tests/Security/EscapeOutputUnitTest.php @@ -159,6 +159,8 @@ public function getErrorList( $testFile = '' ) { 654 => 1, 655 => 1, 657 => 1, + 663 => 1, + 664 => 1, ); case 'EscapeOutputUnitTest.6.inc': From 59b7919c19822a456df769b38a0231aeb3195e3a Mon Sep 17 00:00:00 2001 From: jrfnl Date: Fri, 23 Aug 2024 07:11:08 +0200 Subject: [PATCH 014/105] PHPCSUtils 1.1.0: only catch what should be caught PHPCSUtils 1.1.0 introduces much more modular exceptions for a variety of errors the utility methods can throw. This commit changes the exceptions being caught in various `catch` statements to more specific ones. This means that exceptions which shouldn't be able to occur are no longer caught (passing incorrect data type and such) and only the potentially expected (and acceptable) exceptions will now be caught. --- WordPress/Helpers/ListHelper.php | 4 ++-- WordPress/Sniffs/WP/EnqueuedResourcesSniff.php | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/WordPress/Helpers/ListHelper.php b/WordPress/Helpers/ListHelper.php index 99373b2aec..656757346a 100644 --- a/WordPress/Helpers/ListHelper.php +++ b/WordPress/Helpers/ListHelper.php @@ -9,8 +9,8 @@ namespace WordPressCS\WordPress\Helpers; -use PHP_CodeSniffer\Exceptions\RuntimeException; use PHP_CodeSniffer\Files\File; +use PHPCSUtils\Exceptions\UnexpectedTokenType; use PHPCSUtils\Tokens\Collections; use PHPCSUtils\Utils\Lists; @@ -67,7 +67,7 @@ public static function get_list_variables( File $phpcsFile, $stackPtr ) { try { $assignments = Lists::getAssignments( $phpcsFile, $stackPtr ); - } catch ( RuntimeException $e ) { + } catch ( UnexpectedTokenType $e ) { // Parse error/live coding. return array(); } diff --git a/WordPress/Sniffs/WP/EnqueuedResourcesSniff.php b/WordPress/Sniffs/WP/EnqueuedResourcesSniff.php index c7ed63c303..bc7e9c94fa 100644 --- a/WordPress/Sniffs/WP/EnqueuedResourcesSniff.php +++ b/WordPress/Sniffs/WP/EnqueuedResourcesSniff.php @@ -9,8 +9,8 @@ namespace WordPressCS\WordPress\Sniffs\WP; -use PHP_CodeSniffer\Exceptions\RuntimeException; use PHP_CodeSniffer\Util\Tokens; +use PHPCSUtils\Exceptions\ValueError; use PHPCSUtils\Tokens\Collections; use PHPCSUtils\Utils\TextStrings; use WordPressCS\WordPress\Sniff; @@ -54,7 +54,7 @@ public function process_token( $stackPtr ) { try { $end_ptr = TextStrings::getEndOfCompleteTextString( $this->phpcsFile, $stackPtr ); $content = TextStrings::getCompleteTextString( $this->phpcsFile, $stackPtr ); - } catch ( RuntimeException $e ) { + } catch ( ValueError $e ) { // Parse error/live coding. return; } From 793ff43de9b8b275947f0beac5f5ab6903731268 Mon Sep 17 00:00:00 2001 From: jrfnl Date: Fri, 25 Jul 2025 16:37:19 +0200 Subject: [PATCH 015/105] NamingConventions/ValidPostTypeSlug: check token via code, not type The `'type'` index in the token array should generally only be used for PHPCS cross-version compatibility, where the token constant we are looking for may not be defined in all supported PHPCS versions. That's not the case for these. --- WordPress/Sniffs/NamingConventions/ValidPostTypeSlugSniff.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/WordPress/Sniffs/NamingConventions/ValidPostTypeSlugSniff.php b/WordPress/Sniffs/NamingConventions/ValidPostTypeSlugSniff.php index 15d58edf9d..67c90225a4 100644 --- a/WordPress/Sniffs/NamingConventions/ValidPostTypeSlugSniff.php +++ b/WordPress/Sniffs/NamingConventions/ValidPostTypeSlugSniff.php @@ -172,8 +172,8 @@ public function process_parameters( $stackPtr, $group_name, $matched_content, $p ); // Warn for dynamic parts in the slug parameter. - if ( 'T_DOUBLE_QUOTED_STRING' === $this->tokens[ $string_pos ]['type'] - || ( 'T_HEREDOC' === $this->tokens[ $string_pos ]['type'] + if ( \T_DOUBLE_QUOTED_STRING === $this->tokens[ $string_pos ]['code'] + || ( \T_HEREDOC === $this->tokens[ $string_pos ]['code'] && strpos( $this->tokens[ $string_pos ]['content'], '$' ) !== false ) ) { $this->phpcsFile->addWarning( From c16646e8ba8651cb09662b15be8b2162b291502d Mon Sep 17 00:00:00 2001 From: jrfnl Date: Sat, 26 Jul 2025 22:54:25 +0200 Subject: [PATCH 016/105] EscapingFunctionsTrait: remove `wp_kses_allowed_html()` from escaping functions The `wp_kses_allowed_html()` function is not an escaping function, but retrieves an array of allowed HTML tags and attributes for a given context. Ref: https://developer.wordpress.org/reference/functions/wp_kses_allowed_html/ --- WordPress/Helpers/EscapingFunctionsTrait.php | 1 - 1 file changed, 1 deletion(-) diff --git a/WordPress/Helpers/EscapingFunctionsTrait.php b/WordPress/Helpers/EscapingFunctionsTrait.php index 3df484ff62..b3fbf61d57 100644 --- a/WordPress/Helpers/EscapingFunctionsTrait.php +++ b/WordPress/Helpers/EscapingFunctionsTrait.php @@ -90,7 +90,6 @@ trait EscapingFunctionsTrait { 'urlencode_deep' => true, 'urlencode' => true, 'wp_json_encode' => true, - 'wp_kses_allowed_html' => true, 'wp_kses_data' => true, 'wp_kses_one_attr' => true, 'wp_kses_post' => true, From afcb17eddda552d4bda613e2a74d813a45738264 Mon Sep 17 00:00:00 2001 From: Rodrigo Primo Date: Sat, 2 Aug 2025 05:46:58 -0300 Subject: [PATCH 017/105] Security/EscapeOutput: fix false negatives when handling anonymous classes (#2559) * Security/EscapeOutput: fix false negatives when handling anonymous classes This commit fixes false negatives when the sniff handles readonly anonymous classes and anonymous classes with attributes that are part of a throw statement. When stepping over tokens after `T_THROW` to find the `T_OPEN_PARENTHESIS` of the exception creation function call/class instantiation, the sniff was not considering that it might need to step over `T_READONLY` tokens or attribute declarations when dealing with anonymous classes. Fixes #2552 --------- Co-authored-by: jrfnl --- .phpcs.xml.dist | 1 + .../Sniffs/Security/EscapeOutputSniff.php | 37 +++++++++++++------ .../Tests/Security/EscapeOutputUnitTest.1.inc | 14 +++++++ .../Security/EscapeOutputUnitTest.21.inc | 8 ++++ .../Security/EscapeOutputUnitTest.22.inc | 8 ++++ .../Security/EscapeOutputUnitTest.23.inc | 9 +++++ .../Tests/Security/EscapeOutputUnitTest.php | 3 ++ 7 files changed, 68 insertions(+), 12 deletions(-) create mode 100644 WordPress/Tests/Security/EscapeOutputUnitTest.21.inc create mode 100644 WordPress/Tests/Security/EscapeOutputUnitTest.22.inc create mode 100644 WordPress/Tests/Security/EscapeOutputUnitTest.23.inc diff --git a/.phpcs.xml.dist b/.phpcs.xml.dist index cf03cc18c1..bc350b7977 100644 --- a/.phpcs.xml.dist +++ b/.phpcs.xml.dist @@ -68,6 +68,7 @@ + diff --git a/WordPress/Sniffs/Security/EscapeOutputSniff.php b/WordPress/Sniffs/Security/EscapeOutputSniff.php index 5d5a8272a5..7d2d47275e 100644 --- a/WordPress/Sniffs/Security/EscapeOutputSniff.php +++ b/WordPress/Sniffs/Security/EscapeOutputSniff.php @@ -216,22 +216,35 @@ public function process_token( $stackPtr ) { case \T_THROW: // Find the open parentheses, while stepping over the exception creation tokens. - $ignore = Tokens::$emptyTokens; - $ignore += Collections::namespacedNameTokens(); - $ignore += Collections::functionCallTokens(); - $ignore += Collections::objectOperators(); - - $next_relevant = $this->phpcsFile->findNext( $ignore, ( $stackPtr + 1 ), null, true ); - if ( false === $next_relevant ) { - return; - } - - if ( \T_NEW === $this->tokens[ $next_relevant ]['code'] ) { + $ignore = Tokens::$emptyTokens; + $ignore += Collections::namespacedNameTokens(); + $ignore += Collections::functionCallTokens(); + $ignore += Collections::objectOperators(); + $ignore[ \T_READONLY ] = \T_READONLY; + + $next_relevant = $stackPtr; + do { $next_relevant = $this->phpcsFile->findNext( $ignore, ( $next_relevant + 1 ), null, true ); if ( false === $next_relevant ) { return; } - } + + if ( \T_NEW === $this->tokens[ $next_relevant ]['code'] ) { + continue; + } + + // Skip over attribute declarations when searching for the open parenthesis. + if ( \T_ATTRIBUTE === $this->tokens[ $next_relevant ]['code'] ) { + if ( isset( $this->tokens[ $next_relevant ]['attribute_closer'] ) === false ) { + return; + } + + $next_relevant = $this->tokens[ $next_relevant ]['attribute_closer']; + continue; + } + + break; + } while ( $next_relevant < ( $this->phpcsFile->numTokens - 1 ) ); if ( \T_OPEN_PARENTHESIS !== $this->tokens[ $next_relevant ]['code'] || isset( $this->tokens[ $next_relevant ]['parenthesis_closer'] ) === false diff --git a/WordPress/Tests/Security/EscapeOutputUnitTest.1.inc b/WordPress/Tests/Security/EscapeOutputUnitTest.1.inc index eaf96f5ba3..e1766c7de0 100644 --- a/WordPress/Tests/Security/EscapeOutputUnitTest.1.inc +++ b/WordPress/Tests/Security/EscapeOutputUnitTest.1.inc @@ -662,3 +662,17 @@ die( status: esc_html( $foo ) ); // Ok. exit( status: $foo ); // Bad. die( status: $foo ); // Bad. + +/* + * Issue https://github.com/WordPress/WordPress-Coding-Standards/issues/2552 + * Ensure that readonly anonymous classes and anonymous classes with attributes are handled + * correctly when part of a throw statement. + */ +throw new #[MyAttribute] readonly class( esc_html( $message ) ) extends Exception {}; // Good. +throw new readonly class( $unescaped ) {}; // Bad. +throw new #[MyAttribute] class( $unescaped ) extends Exception {}; // Bad. +throw new +#[Attribute1] +/* some comment */ +#[Attribute2('text', 10)] +readonly class( $unescaped ) {}; // Bad. diff --git a/WordPress/Tests/Security/EscapeOutputUnitTest.21.inc b/WordPress/Tests/Security/EscapeOutputUnitTest.21.inc new file mode 100644 index 0000000000..249b60917a --- /dev/null +++ b/WordPress/Tests/Security/EscapeOutputUnitTest.21.inc @@ -0,0 +1,8 @@ + 1, 663 => 1, 664 => 1, + 672 => 1, + 673 => 1, + 678 => 1, ); case 'EscapeOutputUnitTest.6.inc': From 4083546c94b5b0eeb3489c494603e587d0bf5d8f Mon Sep 17 00:00:00 2001 From: Rodrigo Primo Date: Tue, 5 Aug 2025 10:52:32 -0300 Subject: [PATCH 018/105] GH Actions/unit-tests: don't run code coverage in forks The `unit-tests` workflow runs code coverage for pushes to `main` and pull requests, but wasn't limited to this repo. This resulted in failing builds for contributors who have actions enabled on their fork. The reason for the failure is that they don't have access to the `CODECOV_TOKEN`. This commit changes the conditions on when to run the tests normally and when to run with code coverage to take the organisation where the repo lives into account. That should prevent the failing builds in forks. --- .github/workflows/unit-tests.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/unit-tests.yml b/.github/workflows/unit-tests.yml index 87b871363e..20b293367d 100644 --- a/.github/workflows/unit-tests.yml +++ b/.github/workflows/unit-tests.yml @@ -135,15 +135,15 @@ jobs: run: composer lint -- --checkstyle | cs2pr - name: Run the unit tests without code coverage - if: ${{ matrix.coverage == false }} + if: ${{ matrix.coverage == false || github.repository_owner != 'WordPress' }} run: composer run-tests - name: Run the unit tests with code coverage - if: ${{ matrix.coverage == true }} + if: ${{ matrix.coverage == true && github.repository_owner == 'WordPress' }} run: composer coverage - name: Send coverage report to Codecov - if: ${{ success() && matrix.coverage == true }} + if: ${{ success() && matrix.coverage == true && github.repository_owner == 'WordPress' }} uses: codecov/codecov-action@v5 with: files: ./build/logs/clover.xml From f2fbb58af0c2f75864c4afb6272b6eef47491b55 Mon Sep 17 00:00:00 2001 From: Rodrigo Primo Date: Thu, 7 Aug 2025 14:24:04 -0300 Subject: [PATCH 019/105] DB/PreparedSQLPlaceholders: fix false negative when checking quotes in dynamic generated placeholders The sniff was not accounting for fully qualified calls to `implode()` in the code that checks for quotes in dynamically generated placeholders. --- WordPress/Sniffs/DB/PreparedSQLPlaceholdersSniff.php | 7 ++++++- WordPress/Tests/DB/PreparedSQLPlaceholdersUnitTest.inc | 2 +- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/WordPress/Sniffs/DB/PreparedSQLPlaceholdersSniff.php b/WordPress/Sniffs/DB/PreparedSQLPlaceholdersSniff.php index 27bb4f8489..ba72cabc3c 100644 --- a/WordPress/Sniffs/DB/PreparedSQLPlaceholdersSniff.php +++ b/WordPress/Sniffs/DB/PreparedSQLPlaceholdersSniff.php @@ -266,8 +266,13 @@ public function process_token( $stackPtr ) { unset( $sprintf_parameters, $valid_sprintf, $last_param ); } elseif ( 'implode' === strtolower( $this->tokens[ $i ]['content'] ) ) { + $ignore_tokens = Tokens::$emptyTokens + array( + \T_STRING_CONCAT => \T_STRING_CONCAT, + \T_NS_SEPARATOR => \T_NS_SEPARATOR, + ); + $prev = $this->phpcsFile->findPrevious( - Tokens::$emptyTokens + array( \T_STRING_CONCAT => \T_STRING_CONCAT ), + $ignore_tokens, ( $i - 1 ), $query['start'], true diff --git a/WordPress/Tests/DB/PreparedSQLPlaceholdersUnitTest.inc b/WordPress/Tests/DB/PreparedSQLPlaceholdersUnitTest.inc index 0bbb2cf290..601877bfa4 100644 --- a/WordPress/Tests/DB/PreparedSQLPlaceholdersUnitTest.inc +++ b/WordPress/Tests/DB/PreparedSQLPlaceholdersUnitTest.inc @@ -148,7 +148,7 @@ $where = $wpdb->prepare( "{$wpdb->posts}.post_type IN (\"" . implode( ',', array_fill( 0, count($post_types), '%s' ) ) . "\") AND {$wpdb->posts}.post_status IN ('" - . implode( ',', array_fill( 0, count($post_statusses), '%s' ) ) + . \implode( ',', array_fill( 0, count($post_statusses), '%s' ) ) . '\')', array_merge( $post_types, $post_statusses ) ); // Bad x 2 - quotes between the () for the IN. From 418cf1ca973005e91b1ba8b99247429aad2633a2 Mon Sep 17 00:00:00 2001 From: Rodrigo Primo Date: Thu, 7 Aug 2025 15:47:30 -0300 Subject: [PATCH 020/105] DB/PreparedSQL: fix false positives with case-insensitive function names The sniff was incorrectly flagging valid SQL escaping functions when they were written with mixed or uppercase letters (e.g., 'Esc_Sql' instead of 'esc_sql'). This occurred because the function name comparison was case-sensitive when checking against the predefined list of safe SQL escaping functions. This fix ensures that function names are properly normalized to lowercase before comparing them against the allowed escaping functions list, preventing false positives regardless of the function name's capitalization. --- WordPress/Sniffs/DB/PreparedSQLSniff.php | 5 +++-- WordPress/Tests/DB/PreparedSQLUnitTest.1.inc | 4 ++-- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/WordPress/Sniffs/DB/PreparedSQLSniff.php b/WordPress/Sniffs/DB/PreparedSQLSniff.php index 7b6529ef90..05f0efc0db 100644 --- a/WordPress/Sniffs/DB/PreparedSQLSniff.php +++ b/WordPress/Sniffs/DB/PreparedSQLSniff.php @@ -207,10 +207,11 @@ static function ( $symbol ) { } if ( \T_STRING === $this->tokens[ $this->i ]['code'] ) { + $content_lowercase = strtolower( $this->tokens[ $this->i ]['content'] ); if ( - isset( $this->SQLEscapingFunctions[ $this->tokens[ $this->i ]['content'] ] ) - || isset( $this->SQLAutoEscapedFunctions[ $this->tokens[ $this->i ]['content'] ] ) + isset( $this->SQLEscapingFunctions[ $content_lowercase ] ) + || isset( $this->SQLAutoEscapedFunctions[ $content_lowercase ] ) ) { // Find the opening parenthesis. diff --git a/WordPress/Tests/DB/PreparedSQLUnitTest.1.inc b/WordPress/Tests/DB/PreparedSQLUnitTest.1.inc index 97122aa4e2..1f1a49076c 100644 --- a/WordPress/Tests/DB/PreparedSQLUnitTest.1.inc +++ b/WordPress/Tests/DB/PreparedSQLUnitTest.1.inc @@ -30,7 +30,7 @@ $all_post_meta = $wpdb->get_results( $wpdb->prepare( sprintf( ), $post_ids ) ); $wpdb->query( "SELECT * FROM $wpdb->posts WHERE post_title LIKE '" . esc_sql( $foo ) . "';" ); // Ok. -$wpdb->query( "SELECT * FROM $wpdb->posts WHERE ID = " . absint( $foo ) . ";" ); // Ok. +$wpdb->query( "SELECT * FROM $wpdb->posts WHERE ID = " . ABSINT( $foo ) . ";" ); // Ok. // Test multi-line strings. $all_post_meta = $wpdb->get_results( $wpdb->prepare( sprintf( @@ -79,7 +79,7 @@ $all_post_meta = $wpdb->get_results( $wpdb->prepare( sprintf( <<<'ND' AND `post_id` IN (%s) ND , $wpdb->postmeta, - IMPLODE( ',', array_fill( 0, count( $post_ids ), '%d' ) ) + IMPLODE( ',', array_fill( 0, COUNT( $post_ids ), '%d' ) ) ), $post_ids ) ); // OK. wpdb::prepare( "SELECT * FROM $wpdb?->posts WHERE post_title LIKE '" . foo() . "';" ); // Bad. From afb6fb0e82a4aaf61a11a14a1c0ebc00e98f6f77 Mon Sep 17 00:00:00 2001 From: jrfnl Date: Wed, 13 Aug 2025 02:29:21 +0200 Subject: [PATCH 021/105] WP/EnqueuedResourceParameters: move parse error test to its own file --- ... EnqueuedResourceParametersUnitTest.1.inc} | 3 - .../EnqueuedResourceParametersUnitTest.2.inc | 5 ++ .../WP/EnqueuedResourceParametersUnitTest.php | 74 ++++++++++++------- 3 files changed, 52 insertions(+), 30 deletions(-) rename WordPress/Tests/WP/{EnqueuedResourceParametersUnitTest.inc => EnqueuedResourceParametersUnitTest.1.inc} (97%) create mode 100644 WordPress/Tests/WP/EnqueuedResourceParametersUnitTest.2.inc diff --git a/WordPress/Tests/WP/EnqueuedResourceParametersUnitTest.inc b/WordPress/Tests/WP/EnqueuedResourceParametersUnitTest.1.inc similarity index 97% rename from WordPress/Tests/WP/EnqueuedResourceParametersUnitTest.inc rename to WordPress/Tests/WP/EnqueuedResourceParametersUnitTest.1.inc index b9c5d46614..49b54822e5 100644 --- a/WordPress/Tests/WP/EnqueuedResourceParametersUnitTest.inc +++ b/WordPress/Tests/WP/EnqueuedResourceParametersUnitTest.1.inc @@ -83,6 +83,3 @@ wp_register_script( 'someScript-js', $url, [], 0_0.0_0, true ); // Error - 0, fa // Safeguard handling of PHP 8.1 explicit octals. wp_register_script( 'someScript-js', $url, [], 0o0, true ); // Error - 0, false or NULL are not allowed. - -// Live coding/parse error. -wp_register_style( src: 'https://example.com/someScript.js', ver: /*to do*/, handle: 'someScript-js', ); diff --git a/WordPress/Tests/WP/EnqueuedResourceParametersUnitTest.2.inc b/WordPress/Tests/WP/EnqueuedResourceParametersUnitTest.2.inc new file mode 100644 index 0000000000..6a41502a2c --- /dev/null +++ b/WordPress/Tests/WP/EnqueuedResourceParametersUnitTest.2.inc @@ -0,0 +1,5 @@ + Key is the line number, value is the number of expected errors. */ - public function getErrorList() { - return array( - 6 => 1, - 9 => 1, - 10 => 1, - 12 => 1, - 13 => 1, - 14 => 1, - 22 => 1, - 54 => 1, - 57 => 1, - 61 => 1, - 82 => 1, - 85 => 1, - 88 => 1, - ); + public function getErrorList( $testFile = '' ) { + switch ( $testFile ) { + case 'EnqueuedResourceParametersUnitTest.1.inc': + return array( + 6 => 1, + 9 => 1, + 10 => 1, + 12 => 1, + 13 => 1, + 14 => 1, + 22 => 1, + 54 => 1, + 57 => 1, + 61 => 1, + 82 => 1, + 85 => 1, + ); + + case 'EnqueuedResourceParametersUnitTest.2.inc': + return array( + 5 => 1, + ); + + default: + return array(); + } } /** * Returns the lines where warnings should occur. * + * @param string $testFile The name of the file being tested. + * * @return array Key is the line number, value is the number of expected warnings. */ - public function getWarningList() { - return array( - 3 => 2, - 11 => 1, - 32 => 1, - 39 => 2, - 42 => 1, - 45 => 1, - 66 => 2, - 77 => 1, - ); + public function getWarningList( $testFile = '' ) { + switch ( $testFile ) { + case 'EnqueuedResourceParametersUnitTest.1.inc': + return array( + 3 => 2, + 11 => 1, + 32 => 1, + 39 => 2, + 42 => 1, + 45 => 1, + 66 => 2, + 77 => 1, + ); + + default: + return array(); + } } } From 7d376f8c69a45041bcb6e5aab21ff9985fe09b3e Mon Sep 17 00:00:00 2001 From: jrfnl Date: Wed, 13 Aug 2025 02:45:52 +0200 Subject: [PATCH 022/105] PHP 8.5 | WP/EnqueuedResourceParameters: prevent deprecation notice for non-standard casts Four non-standard type casts are going to be deprecated in PHP 8.5. When any of these type casts would be used in the parameter this sniff examines in the "code under scan" and the sniff would be run on PHP 8.5, the non-standard type cast would be executed via the `eval()`, leading to a deprecation notice, which would stop the scan of the file. This commit works around this by always using the "standard" type cast syntax in the code which would be passed to `eval()`. Includes tests. --- .../WP/EnqueuedResourceParametersSniff.php | 24 +++++++++++++++++++ .../EnqueuedResourceParametersUnitTest.1.inc | 12 ++++++++++ .../WP/EnqueuedResourceParametersUnitTest.php | 4 ++++ 3 files changed, 40 insertions(+) diff --git a/WordPress/Sniffs/WP/EnqueuedResourceParametersSniff.php b/WordPress/Sniffs/WP/EnqueuedResourceParametersSniff.php index 6e4385a923..578517238a 100644 --- a/WordPress/Sniffs/WP/EnqueuedResourceParametersSniff.php +++ b/WordPress/Sniffs/WP/EnqueuedResourceParametersSniff.php @@ -227,6 +227,30 @@ protected function is_falsy( $start, $end ) { continue; } + // Make sure that when deprecated casts are used in the code under scan and the sniff is run on PHP 8.5, + // the eval() won't cause a deprecation notice, borking the scan of the file. + if ( \PHP_VERSION_ID >= 80500 ) { + if ( \T_INT_CAST === $this->tokens[ $i ]['code'] ) { + $code_string .= '(int)'; + continue; + } + + if ( \T_DOUBLE_CAST === $this->tokens[ $i ]['code'] ) { + $code_string .= '(float)'; + continue; + } + + if ( \T_BOOL_CAST === $this->tokens[ $i ]['code'] ) { + $code_string .= '(bool)'; + continue; + } + + if ( \T_BINARY_CAST === $this->tokens[ $i ]['code'] ) { + $code_string .= '(string)'; + continue; + } + } + $code_string .= $this->tokens[ $i ]['content']; } diff --git a/WordPress/Tests/WP/EnqueuedResourceParametersUnitTest.1.inc b/WordPress/Tests/WP/EnqueuedResourceParametersUnitTest.1.inc index 49b54822e5..4a73b458d0 100644 --- a/WordPress/Tests/WP/EnqueuedResourceParametersUnitTest.1.inc +++ b/WordPress/Tests/WP/EnqueuedResourceParametersUnitTest.1.inc @@ -83,3 +83,15 @@ wp_register_script( 'someScript-js', $url, [], 0_0.0_0, true ); // Error - 0, fa // Safeguard handling of PHP 8.1 explicit octals. wp_register_script( 'someScript-js', $url, [], 0o0, true ); // Error - 0, false or NULL are not allowed. + +// Safeguard against PHP 8.5 deprecation of non-standard cast names. +wp_register_script( 'someScript-js', 'https://example.com/someScript.js' , array( 'jquery' ), (boolean) 1, true ); // OK. +wp_register_script( 'someScript-js', 'https://example.com/someScript.js' , array( 'jquery' ), (boolean) 0, true ); // Error - 0, false or NULL are not allowed. + +wp_register_script( 'someScript-js', 'https://example.com/someScript.js' , array( 'jquery' ), (integer) 1, true ); // OK. +wp_register_script( 'someScript-js', 'https://example.com/someScript.js' , array( 'jquery' ), (integer) 0, true ); // Error - 0, false or NULL are not allowed. + +wp_register_script( 'someScript-js', 'https://example.com/someScript.js' , array( 'jquery' ), (double) 1, true ); // OK. +wp_register_script( 'someScript-js', 'https://example.com/someScript.js' , array( 'jquery' ), (double) 0, true ); // Error - 0, false or NULL are not allowed. + +wp_register_script( 'someScript-js', 'https://example.com/someScript.js' , array( 'jquery' ), (binary) 0, true ); // Error - 0, false or NULL are not allowed. diff --git a/WordPress/Tests/WP/EnqueuedResourceParametersUnitTest.php b/WordPress/Tests/WP/EnqueuedResourceParametersUnitTest.php index 49d6f91858..4273b3f016 100644 --- a/WordPress/Tests/WP/EnqueuedResourceParametersUnitTest.php +++ b/WordPress/Tests/WP/EnqueuedResourceParametersUnitTest.php @@ -43,6 +43,10 @@ public function getErrorList( $testFile = '' ) { 61 => 1, 82 => 1, 85 => 1, + 89 => 1, + 92 => 1, + 95 => 1, + 97 => 1, ); case 'EnqueuedResourceParametersUnitTest.2.inc': From 94d1273aed01464a8c990ee8aa8c5c9371e0cf40 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 18 Aug 2025 13:21:42 +0000 Subject: [PATCH 023/105] GH Actions: Bump actions/checkout from 4 to 5 Bumps [actions/checkout](https://github.com/actions/checkout) from 4 to 5. - [Release notes](https://github.com/actions/checkout/releases) - [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md) - [Commits](https://github.com/actions/checkout/compare/v4...v5) --- updated-dependencies: - dependency-name: actions/checkout dependency-version: '5' dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] --- .github/workflows/basic-qa.yml | 10 +++++----- .github/workflows/quicktest.yml | 2 +- .github/workflows/unit-tests.yml | 2 +- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/.github/workflows/basic-qa.yml b/.github/workflows/basic-qa.yml index f43a2843bb..e858145992 100644 --- a/.github/workflows/basic-qa.yml +++ b/.github/workflows/basic-qa.yml @@ -26,7 +26,7 @@ jobs: steps: - name: Checkout repository - uses: actions/checkout@v4 + uses: actions/checkout@v5 - name: Setup PHP uses: shivammathur/setup-php@v2 @@ -115,7 +115,7 @@ jobs: steps: - name: Checkout code - uses: actions/checkout@v4 + uses: actions/checkout@v5 # Updating the lists can fail intermittently, typically after Microsoft has released a new package. # This should not be blocking for this job, so ignore any errors from this step. @@ -153,7 +153,7 @@ jobs: steps: - name: Checkout repository - uses: actions/checkout@v4 + uses: actions/checkout@v5 - name: Set up PHP uses: shivammathur/setup-php@v2 @@ -234,7 +234,7 @@ jobs: steps: - name: Checkout code - uses: actions/checkout@v4 + uses: actions/checkout@v5 - name: Install PHP uses: shivammathur/setup-php@v2 @@ -262,7 +262,7 @@ jobs: steps: - name: "Checkout" - uses: "actions/checkout@v4" + uses: "actions/checkout@v5" - name: "Search for misspellings" uses: "crate-ci/typos@v1" diff --git a/.github/workflows/quicktest.yml b/.github/workflows/quicktest.yml index 6372e6e853..d39fd3e17d 100644 --- a/.github/workflows/quicktest.yml +++ b/.github/workflows/quicktest.yml @@ -30,7 +30,7 @@ jobs: steps: - name: Checkout repository - uses: actions/checkout@v4 + uses: actions/checkout@v5 - name: Set up PHP uses: shivammathur/setup-php@v2 diff --git a/.github/workflows/unit-tests.yml b/.github/workflows/unit-tests.yml index 20b293367d..11151ebb4e 100644 --- a/.github/workflows/unit-tests.yml +++ b/.github/workflows/unit-tests.yml @@ -83,7 +83,7 @@ jobs: steps: - name: Checkout repository - uses: actions/checkout@v4 + uses: actions/checkout@v5 # With stable PHPCS dependencies, allow for PHP deprecation notices. # Unit tests don't need to fail on those for stable releases where those issues won't get fixed anymore. From 009086db6e1e146f2dab022ed3b69f826d47e0f6 Mon Sep 17 00:00:00 2001 From: jrfnl Date: Sun, 10 Aug 2025 19:14:04 +0200 Subject: [PATCH 024/105] GH Actions: update PHP ini configuration Add `display_startup_errors=On` as per the current recommendation from PHPUnit. Ref: https://github.com/sebastianbergmann/phpunit-documentation-english/commit/b3b159cbe9bd7eb5656dd381fc6f028549601dce --- .github/workflows/quicktest.yml | 2 +- .github/workflows/unit-tests.yml | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/quicktest.yml b/.github/workflows/quicktest.yml index d39fd3e17d..355bd3208b 100644 --- a/.github/workflows/quicktest.yml +++ b/.github/workflows/quicktest.yml @@ -38,7 +38,7 @@ jobs: php-version: ${{ matrix.php }} # With stable PHPCS dependencies, allow for PHP deprecation notices. # Unit tests don't need to fail on those for stable releases where those issues won't get fixed anymore. - ini-values: error_reporting=-1, display_errors=On + ini-values: error_reporting=-1, display_errors=On, display_startup_errors=On coverage: ${{ github.ref_name == 'develop' && 'xdebug' || 'none' }} - name: Enable creation of `composer.lock` file diff --git a/.github/workflows/unit-tests.yml b/.github/workflows/unit-tests.yml index 11151ebb4e..33d5e713f0 100644 --- a/.github/workflows/unit-tests.yml +++ b/.github/workflows/unit-tests.yml @@ -91,9 +91,9 @@ jobs: id: set_ini run: | if [ "${{ matrix.dependencies }}" != "dev" ]; then - echo 'PHP_INI=error_reporting=E_ALL & ~E_DEPRECATED, display_errors=On' >> "$GITHUB_OUTPUT" + echo 'PHP_INI=error_reporting=E_ALL & ~E_DEPRECATED, display_errors=On, display_startup_errors=On' >> "$GITHUB_OUTPUT" else - echo 'PHP_INI=error_reporting=-1, display_errors=On' >> "$GITHUB_OUTPUT" + echo 'PHP_INI=error_reporting=-1, display_errors=On, display_startup_errors=On' >> "$GITHUB_OUTPUT" fi - name: Set up PHP From 8daf2e74a3ddb1acc7d937982d9bab737a6b905e Mon Sep 17 00:00:00 2001 From: Rodrigo Primo Date: Tue, 5 Aug 2025 15:37:54 -0300 Subject: [PATCH 025/105] DB/RestrictedClasses: remove redundant call to `parent::setUpPrerequisites()` Calling `AbstractSniffUnitTest::setUpPrerequisites()` manually inside `RestrictedClassesUnitTest::enhanceGroups()` is not necessary as this method already executes via its `@before` tag and results in the method running twice. Originally, `RestrictedClassesUnitTest::enhanceGroups()` was named `RestrictedClassesUnitTest::setUp()` and called `parent::setUp()` (https://github.com/WordPress/WordPress-Coding-Standards/blob/3b9ae92607295548df357e108fd27090cf89d1d7/WordPress/Tests/DB/RestrictedClassesUnitTest.php#L34-L35). But later it was renamed, and then it probably didn't make sense to continue calling `parent::setUp()` (which was later renamed to `setUpPrerequisites()`): https://github.com/WordPress/WordPress-Coding-Standards/commit/00b895c92f41a49923c37df58b370b801080a204. I found this in the context of the work to prepare this codebase for PHPCS 4.0 as `AbstractSniffUnitTest::setUpPrerequisites()` was renamed in 4.0 (https://github.com/PHPCSStandards/PHP_CodeSniffer/commit/92cf10f65c2ff1486e28eb1e359680eea5c54224#diff-91ba2a2a923bbfdaa61dcd31051d783bd0e7ff99f979f6e1a2917cae7dde3eb2L58). --- WordPress/Tests/DB/RestrictedClassesUnitTest.php | 2 -- 1 file changed, 2 deletions(-) diff --git a/WordPress/Tests/DB/RestrictedClassesUnitTest.php b/WordPress/Tests/DB/RestrictedClassesUnitTest.php index 23877253df..dab29264cf 100644 --- a/WordPress/Tests/DB/RestrictedClassesUnitTest.php +++ b/WordPress/Tests/DB/RestrictedClassesUnitTest.php @@ -37,8 +37,6 @@ final class RestrictedClassesUnitTest extends AbstractSniffUnitTest { * @return void */ protected function enhanceGroups() { - parent::setUpPrerequisites(); - AbstractFunctionRestrictionsSniff::$unittest_groups = array( 'test' => array( 'type' => 'error', From 2403b008ac02cc3aa4304cabb43d4f463b561f52 Mon Sep 17 00:00:00 2001 From: Rodrigo Primo Date: Tue, 2 Sep 2025 15:48:44 -0300 Subject: [PATCH 026/105] Security/ValidatedSanitizedInput: fix link in docblock While reviewing another PR related to this sniff, I noticed an incorrect link in the class docblock. The link was pointing to an unrelated GitHub issue instead of pointing to the GitHub issue that discussed the introduction of this sniff. This is now fixed in this commit and the correct link is used. I believe this was caused by a copy and paste error in the PR that introduced the sniff (https://github.com/WordPress/WordPress-Coding-Standards/pull/101). --- WordPress/Sniffs/Security/ValidatedSanitizedInputSniff.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/WordPress/Sniffs/Security/ValidatedSanitizedInputSniff.php b/WordPress/Sniffs/Security/ValidatedSanitizedInputSniff.php index 6f46261b56..d3b7fe02f8 100644 --- a/WordPress/Sniffs/Security/ValidatedSanitizedInputSniff.php +++ b/WordPress/Sniffs/Security/ValidatedSanitizedInputSniff.php @@ -23,7 +23,7 @@ /** * Flag any non-validated/sanitized input ( _GET / _POST / etc. ). * - * @link https://github.com/WordPress/WordPress-Coding-Standards/issues/69 + * @link https://github.com/WordPress/WordPress-Coding-Standards/issues/72 * * @since 0.3.0 * @since 0.4.0 This class now extends the WordPressCS native `Sniff` class. From fa635ade4a308c747b04227695deeecaaae73b05 Mon Sep 17 00:00:00 2001 From: Rodrigo Primo Date: Wed, 3 Sep 2025 06:11:57 -0700 Subject: [PATCH 027/105] Release checklist: minor updates to the publicize section (#2567) * Release checklist: minor updates to the publicize section - Clarify which account to use when posting to social media about the release. - Clarify which Slack channel to post to. - Replace "Month in WordPress" with a Marketing team amplify request as the former doesn't exist anymore and was replaced by the latter Plus fixes a line break issue in one of the items of the release section by adding to spaces to the line before it to force a soft line break. --- .github/release-checklist.md | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/.github/release-checklist.md b/.github/release-checklist.md index a45db59b23..3a6899b49f 100644 --- a/.github/release-checklist.md +++ b/.github/release-checklist.md @@ -45,7 +45,7 @@ PR for tracking changes for the x.x.x release. Target release date: **DOW MONTH - [ ] Merge this PR. - [ ] Make sure all CI builds are green. -- [ ] Tag and create a release against `main` (careful, GH defaults to `develop`!) & copy & paste the changelog to it. +- [ ] Tag and create a release against `main` (careful, GH defaults to `develop`!) & copy & paste the changelog to it. :pencil2: Check if anything from the link collection at the bottom of the changelog needs to be copied in! - Remove square brackets from all ticket links or make them proper full links (as GH markdown parser doesn't parse these correctly). - Change all contributor links to full inline links (as GH markdown parser on the Releases page doesn't parse these correctly). @@ -62,13 +62,16 @@ PR for tracking changes for the x.x.x release. Target release date: **DOW MONTH ### Publicize - [ ] [Major releases only] Publish post about the release on Make WordPress. -- [ ] Tweet, toot, etc about the release. -- [ ] Post about it in Slack. -- [ ] Submit for ["Month in WordPress"][month-in-wp]. +- [ ] Tweet, toot, etc about the release from your personal account (there is no official WPCS account). +- [ ] Post about it in #core channel on the WordPress.org Slack. + :pencil2: No need to post in the #core-coding-standard channel as that gets an automated release notification anyway. + - [ ] Optionally post in #plugin-review if a sniff was added in a release which was requested by the plugin review team. + - [ ] Optionally post in #core-docs if significant updates were made to the documentation ruleset. +- [ ] Create a Marketing team ["amplify request"][amplify-request]. - [ ] Submit for the ["Monthy Dev Roundup"][dev-roundup]. [phpcs-releases]: https://github.com/PHPCSStandards/PHP_CodeSniffer/releases [phpcsutils-releases]: https://github.com/PHPCSStandards/PHPCSUtils/releases [phpcsextra-releases]: https://github.com/PHPCSStandards/PHPCSExtra/releases -[month-in-wp]: https://make.wordpress.org/community/month-in-wordpress-submissions/ +[amplify-request]: https://github.com/WordPress/Marketing-Team/issues/new?template=2-request-for-amplification-template.yml [dev-roundup]: https://github.com/WordPress/developer-blog-content/issues?q=is%3Aissue+label%3A%22Monthly+Roundup%22 From 8e7c15b38bad46798ede334067358263dde1cc19 Mon Sep 17 00:00:00 2001 From: Rodrigo Primo Date: Wed, 3 Sep 2025 10:47:49 -0300 Subject: [PATCH 028/105] Changelog: add missing entry to the changelog PR https://github.com/WordPress/WordPress-Coding-Standards/pull/2456 was missing a milestone and because of that it was not included in the 3.2.0 changelog. This commit fixes that. --- CHANGELOG.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 3b3c71aa66..2b44aedf59 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -15,7 +15,7 @@ _No documentation available about unreleased changes as of yet._ This sniff warns when `get_*_meta()` and `get_metadata*()` functions are used with the `$meta_key`/`$key` param, but without the `$single` parameter as this could lead to unexpected behavior due to the different return types. - `WordPress-Extra`: the following additional sniffs have been added to the ruleset: `Generic.Strings.UnnecessaryHeredoc` and `Generic.WhiteSpace.HereNowdocIdentifierSpacing`. [#2534] - The `rest_sanitize_boolean()` functions to the list of known "sanitizing" functions. Props [@westonruter]. [#2530] -- End-user documentation to the following existing sniffs: `WordPress.DB.PreparedSQL` (props [@jaymcp], [#2454]), `WordPress.NamingConventions.ValidFunctionName` (props [@richardkorthuis] and [@rodrigoprimo], [#2452], [#2531]), `WordPress.NamingConventions.ValidVariableName` (props [@richardkorthuis], [#2457]). +- End-user documentation to the following existing sniffs: `WordPress.DB.PreparedSQL` (props [@jaymcp], [#2454]), `WordPress.NamingConventions.ValidFunctionName` (props [@richardkorthuis] and [@rodrigoprimo], [#2452], [#2531]), `WordPress.NamingConventions.ValidVariableName` (props [@richardkorthuis], [#2457]), `WordPress.PHP.DontExtract` (props [@aiolachiara], [#2456]). This documentation can be exposed via the [`PHP_CodeSniffer` `--generator=...` command-line argument](https://github.com/PHPCSStandards/PHP_CodeSniffer/wiki/Usage). ### Changed @@ -54,6 +54,7 @@ _No documentation available about unreleased changes as of yet._ [#2465]: https://github.com/WordPress/WordPress-Coding-Standards/pull/2465 [#2452]: https://github.com/WordPress/WordPress-Coding-Standards/pull/2452 [#2454]: https://github.com/WordPress/WordPress-Coding-Standards/pull/2454 +[#2456]: https://github.com/WordPress/WordPress-Coding-Standards/pull/2456 [#2457]: https://github.com/WordPress/WordPress-Coding-Standards/pull/2457 [#2479]: https://github.com/WordPress/WordPress-Coding-Standards/pull/2479 [#2500]: https://github.com/WordPress/WordPress-Coding-Standards/pull/2500 @@ -1699,6 +1700,7 @@ Initial tagged release. [2013-10-06]: https://github.com/WordPress/WordPress-Coding-Standards/compare/2013-06-11...2013-10-06 [@anomiex]: https://github.com/anomiex +[@aiolachiara]: https://github.com/aiolachiara [@Chouby]: https://github.com/Chouby [@ckanitz]: https://github.com/ckanitz [@craigfrancis]: https://github.com/craigfrancis From be2c9af42083d278ef754f0452c4fa09cefc9998 Mon Sep 17 00:00:00 2001 From: jrfnl Date: Wed, 3 Sep 2025 15:49:00 +0200 Subject: [PATCH 029/105] Release checklist: add new bullet about checking all PRs are milestoned Rodrigo and me just noticed that a few PRs which were merged into the `3.2.0` release did not have a milestone attached. We've fixed those now and will fix the changelog too (only one needed a mention, the others were maintenance PRs). This commit just adds a new reminder bullet to verify that all PRs are milestoned before creating the changelog to (hopefully) prevent this from happening again. _Side-note: in other repos I actually have it required check for the milestone being set (can't merge without it), but that would require permission from the WordPress organisation to allow the [app which handles that](https://github.com/scholzj/milestone-check) and that might get complicated..._ --- .github/release-checklist.md | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/release-checklist.md b/.github/release-checklist.md index 3a6899b49f..37426e0d86 100644 --- a/.github/release-checklist.md +++ b/.github/release-checklist.md @@ -36,6 +36,7 @@ PR for tracking changes for the x.x.x release. Target release date: **DOW MONTH ### Release prep +- [ ] Double-check that all PRs which were merged since the last release have a milestone attached to it. - [ ] Add changelog for the release - PR #xxx :pencil2: Remember to add a release link at the bottom! - [ ] Update `README` (if applicable) - PR #xxx From 72006638480c12829cb28acbacbad9d3d1ce3544 Mon Sep 17 00:00:00 2001 From: Rodrigo Primo Date: Wed, 3 Sep 2025 11:09:59 -0300 Subject: [PATCH 030/105] Changelog: add WPCS maintainers to the list of GitHub profile links @jrfnl is mentioned in the changelog, but there was no link for their GitHub profile page at the botton, so the link was broken. This commits adds the link to fix this problem. Per Juliette's suggestion, I'm adding links to the other maintainers as well to prevent this problem from happen to them in the future. --- CHANGELOG.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 3b3c71aa66..6fa67d8348 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1705,11 +1705,14 @@ Initial tagged release. [@davidperezgar]: https://github.com/davidperezgar [@dawidurbanski]: https://github.com/dawidurbanski [@desrosj]: https://github.com/desrosj +[@dingo-d]: https://github.com/dingo-d [@fredden]: https://github.com/fredden +[@GaryJones]: https://github.com/GaryJones [@grappler]: https://github.com/grappler [@Ipstenu]: https://github.com/Ipstenu [@jaymcp]: https://github.com/jaymcp [@JDGrimes]: https://github.com/JDGrimes +[@jrfnl]: https://github.com/jrfnl [@khacoder]: https://github.com/khacoder [@Luc45]: https://github.com/Luc45 [@marconmartins]: https://github.com/marconmartins From f6965eed3db6393bfc89e975bcd3fb27186c74c2 Mon Sep 17 00:00:00 2001 From: Gary Jones Date: Thu, 4 Sep 2025 07:05:23 +0100 Subject: [PATCH 031/105] Update CONTRIBUTING.md with tips for successful PRs (#2598) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Update CONTRIBUTING.md heading levels to aid navigation * Add guidelines for successful PRs in CONTRIBUTING.md --------- Co-authored-by: Denis Žoljom --- .github/CONTRIBUTING.md | 49 ++++++++++++++++++++++++++++++----------- 1 file changed, 36 insertions(+), 13 deletions(-) diff --git a/.github/CONTRIBUTING.md b/.github/CONTRIBUTING.md index 4c60892b8b..f0f1fcb2d7 100644 --- a/.github/CONTRIBUTING.md +++ b/.github/CONTRIBUTING.md @@ -1,6 +1,8 @@ +# Contributing to the WordPress Coding Standards + Hi, thank you for your interest in contributing to the WordPress Coding Standards! We look forward to working with you. -# Reporting Bugs +## Reporting Bugs Please search the repo to see if your issue has been reported already and if so, comment in that issue instead of opening a new one. @@ -9,7 +11,7 @@ Running `phpcs` with the `-s` flag will show the name of the sniff with each err Bug reports containing a minimal code sample which can be used to reproduce the issue are highly appreciated as those are most easily actionable. -## Upstream Issues +### Upstream Issues Since WordPressCS employs many sniffs that are part of PHP_CodeSniffer itself or PHPCSExtra, sometimes an issue will be caused by a bug in PHPCS or PHPCSExtra and not in WordPressCS itself. If the error message in question doesn't come from a sniff whose name starts with `WordPress`, the issue is probably a bug in PHPCS or PHPCSExtra. @@ -17,27 +19,48 @@ If the error message in question doesn't come from a sniff whose name starts wit * Bugs for sniffs starting with `Generic`, `PEAR`, `PSR1`, `PSR2`, `PSR12`, `Squiz` or `Zend` should be [reported to PHPCS](https://github.com/PHPCSStandards/PHP_CodeSniffer/issues). * Bugs for sniffs starting with `Modernize`, `NormalizedArrays` or `Universal` should be [reported to PHPCSExtra](https://github.com/PHPCSStandards/PHPCSExtra/issues). -# Contributing patches and new features +## Contributing patches and new features + +### Tips for Successful PRs + +We welcome contributions from everyone, and want your PR to have the best chance of being reviewed and merged. To help with this, please keep the following in mind: + +* **Respect copyright and licensing.** + Only submit code that you have written yourself or that comes from sources where the license clearly allows inclusion. Submitting code that infringes on copyright or licensing terms puts both you and the project at legal risk, and such contributions cannot be accepted. + +* **Do not submit AI-generated code.** + Pull requests containing AI-generated code are not acceptable. Beyond copyright and licensing uncertainties, AI-generated contributions consistently require disproportionate amounts of maintainer time to review, correct, or rewrite. This wastes limited project resources and slows progress for everyone. Submitting AI-generated code may be treated as a violation of our [Code of Conduct](../CODE_OF_CONDUCT.md). + +* **Focus on quality and clarity.** + Take time to explain *why* the change is needed, and include tests or examples where appropriate. Clear, self-written explanations make it more straightforward for reviewers to understand what you are trying to achieve. + +* **Think about long-term maintainability.** + Code should align with WordPress Coding Standards and be written in a way that others can readily read, understand, and maintain. + +* **Be collaborative.** + If you're unsure about an approach, open an issue first to start a conversation. + +By following these tips, you'll save time for both yourself and the maintainers — and increase the likelihood that your contribution can be merged smoothly. -## Branches +### Branches Ongoing development will be done in the `develop` branch with merges to `main` once considered stable. To contribute an improvement to this project, fork the repo, run `composer install`, make your changes to the code, run the unit tests and code style checks by running `composer check-all`, and if all is good, open a pull request to the `develop` branch. Alternatively, if you have push access to this repo, create a feature branch prefixed by `feature/` and then open an intra-repo PR from that branch to `develop`. -# Considerations when writing sniffs +## Considerations when writing sniffs -## Public properties +### Public properties When writing sniffs, always remember that any `public` sniff property can be overruled via a custom ruleset by the end-user. Only make a property `public` if that is the intended behavior. When you introduce new `public` sniff properties, or your sniff extends a class from which you inherit a `public` property, please don't forget to update the [public properties wiki page](https://github.com/WordPress/WordPress-Coding-Standards/wiki/Customizable-sniff-properties) with the relevant details once your PR has been merged into the `develop` branch. -# Unit Testing +## Unit Testing -## Pre-requisites +### Pre-requisites * WordPress-Coding-Standards * PHP_CodeSniffer 3.13.0 or higher * PHPCSUtils 1.1.0 or higher @@ -46,11 +69,11 @@ When you introduce new `public` sniff properties, or your sniff extends a class The WordPress Coding Standards use the `PHP_CodeSniffer` native unit test framework for unit testing the sniffs. -## Getting ready to test +### Getting ready to test Presuming you have cloned WordPressCS for development, to run the unit tests you need to make sure you have run `composer install` from the root directory of your WordPressCS git clone. -## Custom develop setups +### Custom develop setups If you are developing with a stand-alone PHP_CodeSniffer (git clone) installation and want to use that git clone to test WordPressCS, there are three extra things you need to do: 1. Install [PHPCSUtils](https://github.com/PHPCSStandards/PHPCSUtils). @@ -73,7 +96,7 @@ If you are developing with a stand-alone PHP_CodeSniffer (git clone) installatio ``` -## Running the unit tests +### Running the unit tests From the root of your WordPressCS install, run the unit tests like so: ```bash @@ -99,7 +122,7 @@ Time: 10.19 seconds, Memory: 40.00 MB OK (57 tests, 0 assertions) ``` -## Unit Testing conventions +### Unit Testing conventions If you look inside the `WordPress/Tests` subdirectory, you'll see the structure mimics the `WordPress/Sniffs` subdirectory structure. For example, the `WordPress/Sniffs/PHP/POSIXFunctionsSniff.php` sniff has its unit test class defined in `WordPress/Tests/PHP/POSIXFunctionsUnitTest.php` which checks the `WordPress/Tests/PHP/POSIXFunctionsUnitTest.inc` test case file. See the file naming convention? @@ -171,6 +194,6 @@ You'll see the line number and number of ERRORs we need to return in the `getErr The `--sniffs=...` directive limits the output to the sniff you are testing. -## Code Standards for this project +### Code Standards for this project The sniffs and test files - not test _case_ files! - for WordPressCS should be written such that they pass the `WordPress-Extra` and the `WordPress-Docs` code standards using the custom ruleset as found in `/.phpcs.xml.dist`. From 0a020d128be0c8531f3b0e9c7f7a3392ce721dc2 Mon Sep 17 00:00:00 2001 From: Juliette <663378+jrfnl@users.noreply.github.com> Date: Tue, 9 Sep 2025 01:37:55 +0200 Subject: [PATCH 032/105] Add PR template (#2594) Co-authored-by: Gary Jones Co-authored-by: jrfnl --- .github/pull_request_template.md | 34 ++++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) create mode 100644 .github/pull_request_template.md diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md new file mode 100644 index 0000000000..e33b84ad9d --- /dev/null +++ b/.github/pull_request_template.md @@ -0,0 +1,34 @@ + + + + +# Description + + + +## Suggested changelog entry + + + +## Related issues/external references + +Fixes # From 8f85cbde7f9e253e198cdaefa898d07eca130b48 Mon Sep 17 00:00:00 2001 From: Rodrigo Primo Date: Fri, 5 Sep 2025 16:11:05 -0300 Subject: [PATCH 033/105] WP/AlternativeFunctions: fix typo in code comment --- WordPress/Sniffs/WP/AlternativeFunctionsSniff.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/WordPress/Sniffs/WP/AlternativeFunctionsSniff.php b/WordPress/Sniffs/WP/AlternativeFunctionsSniff.php index afd98fd2ac..40fb0c61c2 100644 --- a/WordPress/Sniffs/WP/AlternativeFunctionsSniff.php +++ b/WordPress/Sniffs/WP/AlternativeFunctionsSniff.php @@ -259,7 +259,7 @@ public function process_matched_token( $stackPtr, $group_name, $matched_content case 'file_get_contents': /* * Using `wp_remote_get()` will only work for remote URLs. - * See if we can determine is this function call is for a local file and if so, bow out. + * See if we can determine if this function call is for a local file and if so, bow out. */ $params = PassedParameters::getParameters( $this->phpcsFile, $stackPtr ); From bf362c6d557de4086778ad34f7aa9908c5c09015 Mon Sep 17 00:00:00 2001 From: Rodrigo Primo Date: Thu, 21 Aug 2025 16:06:32 -0300 Subject: [PATCH 034/105] Security/EscapeOutput: fix namespaced ::class detection The sniff now correctly identifies namespaced class references like `\MyNamespace\ClassName::class` and `namespace\ClassName::class` as safe output that doesn't require escaping. Support for `ClassName::class` was added in 2326, but I believe namespaced classes were not considered. --- WordPress/Sniffs/Security/EscapeOutputSniff.php | 7 ++++++- WordPress/Tests/Security/EscapeOutputUnitTest.1.inc | 11 +++++++++++ 2 files changed, 17 insertions(+), 1 deletion(-) diff --git a/WordPress/Sniffs/Security/EscapeOutputSniff.php b/WordPress/Sniffs/Security/EscapeOutputSniff.php index 7d2d47275e..e0714e36c4 100644 --- a/WordPress/Sniffs/Security/EscapeOutputSniff.php +++ b/WordPress/Sniffs/Security/EscapeOutputSniff.php @@ -615,8 +615,13 @@ protected function check_code_is_escaped( $start, $end, $code = 'OutputNotEscape if ( \T_STRING === $this->tokens[ $i ]['code'] || \T_VARIABLE === $this->tokens[ $i ]['code'] || isset( Collections::ooHierarchyKeywords()[ $this->tokens[ $i ]['code'] ] ) + || \T_NAMESPACE === $this->tokens[ $i ]['code'] ) { - $double_colon = $this->phpcsFile->findNext( Tokens::$emptyTokens, ( $i + 1 ), $end, true ); + $skip_tokens = Tokens::$emptyTokens; + $skip_tokens[ \T_STRING ] = \T_STRING; + $skip_tokens[ \T_NS_SEPARATOR ] = \T_NS_SEPARATOR; + + $double_colon = $this->phpcsFile->findNext( $skip_tokens, ( $i + 1 ), $end, true ); if ( false !== $double_colon && \T_DOUBLE_COLON === $this->tokens[ $double_colon ]['code'] ) { diff --git a/WordPress/Tests/Security/EscapeOutputUnitTest.1.inc b/WordPress/Tests/Security/EscapeOutputUnitTest.1.inc index e1766c7de0..45759ace3e 100644 --- a/WordPress/Tests/Security/EscapeOutputUnitTest.1.inc +++ b/WordPress/Tests/Security/EscapeOutputUnitTest.1.inc @@ -676,3 +676,14 @@ throw new /* some comment */ #[Attribute2('text', 10)] readonly class( $unescaped ) {}; // Bad. + +/* + * Safeguard correct handling of all types of namespaced function calls when *::class is used. + * + * Note: using ::class on fully qualified or namespace relative class names doesn't provide + * any real value in practice. + */ +_deprecated_function( __METHOD__, 'x.x.x', \ClassName::class ); // OK. +die( \MyNamespace\ClassName::class . ' has been abandoned' ); // OK. +echo 'Do not use ' . MyNamespace\ClassName::class; // OK. +_deprecated_function( __METHOD__, 'x.x.x', namespace\ClassName::class ); // OK. From 5b28561b87894a8398fe268469f67a416fdb9512 Mon Sep 17 00:00:00 2001 From: Rodrigo Primo Date: Wed, 10 Sep 2025 10:32:22 -0300 Subject: [PATCH 035/105] Security/EscapeOutput: remove unintentional syntax error from the tests Remove extra closing parenthesis that was causing a syntax error in a ::class test case. This test was added in 2326 and there is nothing in the corresponding commit message that this indicates this was an intentional syntax error. --- WordPress/Tests/Security/EscapeOutputUnitTest.1.inc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/WordPress/Tests/Security/EscapeOutputUnitTest.1.inc b/WordPress/Tests/Security/EscapeOutputUnitTest.1.inc index 45759ace3e..52c3a59976 100644 --- a/WordPress/Tests/Security/EscapeOutputUnitTest.1.inc +++ b/WordPress/Tests/Security/EscapeOutputUnitTest.1.inc @@ -538,7 +538,7 @@ _deprecated_function( __METHOD__, 'x.x.x', ClassName::class ); // OK. die( self::CLASS . ' has been abandoned' ); // OK. _deprecated_function( __METHOD__, 'x.x.x', parent::Class ); // OK. _deprecated_function( __METHOD__, 'x.x.x', static::class ); // OK. -echo 'Do not use ' . $object::class ); // OK. +echo 'Do not use ' . $object::class; // OK. /* * Examine the parameters passed for exception creation via throw. From fe9bacfedfe31f551980b4ab171537b215a6fe1f Mon Sep 17 00:00:00 2001 From: jrfnl Date: Thu, 11 Sep 2025 18:49:06 +0200 Subject: [PATCH 036/105] Example ruleset: update some recommended settings * Generally we recommend for the `minimum_wp_version` to be ~3 versions behind the latest WP release (currently 6.8.2). * To align with this, I'm setting the `testVersion` for PHPCompatibility to PHP 7.0 or higher (which was the minimum PHP version in WP 6.5). --- phpcs.xml.dist.sample | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/phpcs.xml.dist.sample b/phpcs.xml.dist.sample index 64be6228c3..cfb232b862 100644 --- a/phpcs.xml.dist.sample +++ b/phpcs.xml.dist.sample @@ -78,7 +78,7 @@ https://github.com/PHPCompatibility/PHPCompatibility --> - + From e113ed173ff43928b261aec8784b27fcc2e2d2ec Mon Sep 17 00:00:00 2001 From: jrfnl Date: Thu, 11 Sep 2025 18:56:06 +0200 Subject: [PATCH 037/105] README: make the call for funding stand out a bit more --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 859b2f778c..eeb99a1422 100644 --- a/README.md +++ b/README.md @@ -48,7 +48,7 @@ This project is a collection of [PHP_CodeSniffer](https://github.com/PHPCSStandards/PHP_CodeSniffer) rules (sniffs) to validate code developed for WordPress. It ensures code quality and adherence to coding conventions, especially the official [WordPress Coding Standards](https://make.wordpress.org/core/handbook/best-practices/coding-standards/). -This project needs funding. [Find out how you can help](#funding). +**This project needs funding. [Find out how you can help](#funding).** ## Minimum Requirements From 6951677326cbfee0e1b5aa85994bdd29c6f4f65a Mon Sep 17 00:00:00 2001 From: jrfnl Date: Thu, 11 Sep 2025 19:16:31 +0200 Subject: [PATCH 038/105] CONTRIBUTING: update the example test output --- .github/CONTRIBUTING.md | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/.github/CONTRIBUTING.md b/.github/CONTRIBUTING.md index f0f1fcb2d7..93a23e59b1 100644 --- a/.github/CONTRIBUTING.md +++ b/.github/CONTRIBUTING.md @@ -108,18 +108,18 @@ phpunit --filter WordPress /path/to/PHP_CodeSniffer/tests/AllTests.php Expected output: ``` -PHPUnit 9.6.15 by Sebastian Bergmann and contributors. +PHPUnit 9.6.26 by Sebastian Bergmann and contributors. -Runtime: PHP 8.3.0 +Runtime: PHP 8.4.12 Configuration: /WordPressCS/phpunit.xml.dist -......................................................... 57 / 57 (100%) +............................................................ 60 / 60 (100%) -201 sniff test files generated 744 unique error codes; 50 were fixable (6%) +210 sniff test files generated 775 unique error codes; 50 were fixable (6%) -Time: 10.19 seconds, Memory: 40.00 MB +Time: 00:03.396, Memory: 60.00 MB -OK (57 tests, 0 assertions) +OK (60 tests, 6 assertions) ``` ### Unit Testing conventions From 637711cf8c44d0cb5c77d50d1543ef4b5523c7a6 Mon Sep 17 00:00:00 2001 From: Rodrigo Primo Date: Mon, 15 Sep 2025 10:42:32 -0300 Subject: [PATCH 039/105] WP/GlobalVariablesOverride: more tests covering unresolvable `$GLOBALS` keys (#2580) * WP/GlobalVariablesOverride: more tests covering unresolvable `$GLOBALS` keys --- .../Tests/WP/GlobalVariablesOverrideUnitTest.1.inc | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/WordPress/Tests/WP/GlobalVariablesOverrideUnitTest.1.inc b/WordPress/Tests/WP/GlobalVariablesOverrideUnitTest.1.inc index 092fd2e589..db57dc363b 100644 --- a/WordPress/Tests/WP/GlobalVariablesOverrideUnitTest.1.inc +++ b/WordPress/Tests/WP/GlobalVariablesOverrideUnitTest.1.inc @@ -320,3 +320,17 @@ class AsymmetricVisibilityProperties { public function __construct(public protected(set) int $page = 0) {} // Ok. } + +/* + * $GLOBALS with non-string key, unable to determine which variable is being overridden. + */ +function globals_with_non_string_key() { + $GLOBALS[ "some{$name}" ] = 'test'; // Ok. + $GLOBALS[ $obj->global_name ] = 'test'; // Ok. + $GLOBALS[ MyClass::GLOBAL_NAME ] = 'test'; // Ok. + $GLOBALS[ GLOBAL_NAME_CONSTANT ] = 'test'; // Ok. + $GLOBALS[ get_my_global_name() ] = 'test'; // Ok. + $GLOBALS[ MyNamespace\get_my_global_name() ] = 'test'; // Ok. + $GLOBALS[ \MyNamespace\get_my_global_name() ] = 'test'; // Ok. + $GLOBALS[ namespace\get_my_global_name() ] = 'test'; // Ok. +} From 584ef105d0ab29e47915ac04479db6397e3e476a Mon Sep 17 00:00:00 2001 From: Rodrigo Primo Date: Thu, 7 Aug 2025 08:28:06 -0300 Subject: [PATCH 040/105] DB/DirectDatabaseQuery: rename test case file Doing this to allow for additional test case files. --- ....inc => DirectDatabaseQueryUnitTest.1.inc} | 0 .../Tests/DB/DirectDatabaseQueryUnitTest.php | 117 ++++++++++-------- 2 files changed, 62 insertions(+), 55 deletions(-) rename WordPress/Tests/DB/{DirectDatabaseQueryUnitTest.inc => DirectDatabaseQueryUnitTest.1.inc} (100%) diff --git a/WordPress/Tests/DB/DirectDatabaseQueryUnitTest.inc b/WordPress/Tests/DB/DirectDatabaseQueryUnitTest.1.inc similarity index 100% rename from WordPress/Tests/DB/DirectDatabaseQueryUnitTest.inc rename to WordPress/Tests/DB/DirectDatabaseQueryUnitTest.1.inc diff --git a/WordPress/Tests/DB/DirectDatabaseQueryUnitTest.php b/WordPress/Tests/DB/DirectDatabaseQueryUnitTest.php index e12828a1aa..074a191ba9 100644 --- a/WordPress/Tests/DB/DirectDatabaseQueryUnitTest.php +++ b/WordPress/Tests/DB/DirectDatabaseQueryUnitTest.php @@ -35,62 +35,69 @@ public function getErrorList() { /** * Returns the lines where warnings should occur. * + * @param string $testFile The name of the test file being run. + * * @return array Key is the line number, value is the number of expected warnings. */ - public function getWarningList() { - return array( - 5 => 2, - 12 => 1, - 26 => 2, - 27 => 2, - 28 => 1, - 29 => 1, - 38 => 2, - 44 => 2, - 60 => 1, - 61 => 1, - 62 => 1, - 63 => 1, - 65 => 2, - 66 => 2, - 67 => 2, - 80 => 1, - 81 => 1, - 82 => 1, - 83 => 1, - 84 => 1, - 85 => 1, - 86 => 1, - 97 => 1, - 114 => 1, - 123 => 1, - 130 => 1, - 141 => 1, - 150 => 2, - 157 => 2, - 168 => 2, - 175 => 1, - 180 => 1, - 185 => 1, - 190 => 1, - 195 => 1, - 200 => 1, - 205 => 1, - 210 => 1, - 215 => 1, - 220 => 1, - 228 => 2, - 235 => 2, - 251 => 1, - 252 => 1, - 265 => 1, - 269 => 1, - 281 => 1, - 287 => 2, - 288 => 1, - 300 => 1, - 306 => 2, - 333 => 2, - ); + public function getWarningList( $testFile = '' ) { + switch ( $testFile ) { + case 'DirectDatabaseQueryUnitTest.1.inc': + return array( + 5 => 2, + 12 => 1, + 26 => 2, + 27 => 2, + 28 => 1, + 29 => 1, + 38 => 2, + 44 => 2, + 60 => 1, + 61 => 1, + 62 => 1, + 63 => 1, + 65 => 2, + 66 => 2, + 67 => 2, + 80 => 1, + 81 => 1, + 82 => 1, + 83 => 1, + 84 => 1, + 85 => 1, + 86 => 1, + 97 => 1, + 114 => 1, + 123 => 1, + 130 => 1, + 141 => 1, + 150 => 2, + 157 => 2, + 168 => 2, + 175 => 1, + 180 => 1, + 185 => 1, + 190 => 1, + 195 => 1, + 200 => 1, + 205 => 1, + 210 => 1, + 215 => 1, + 220 => 1, + 228 => 2, + 235 => 2, + 251 => 1, + 252 => 1, + 265 => 1, + 269 => 1, + 281 => 1, + 287 => 2, + 288 => 1, + 300 => 1, + 306 => 2, + 333 => 2, + ); + default: + return array(); + } } } From b4cf66e0531ac4aa548ba5896e249c9ae85921ec Mon Sep 17 00:00:00 2001 From: Rodrigo Primo Date: Thu, 7 Aug 2025 08:30:45 -0300 Subject: [PATCH 041/105] DB/DirectDatabaseQuery: move syntax error test to its own file --- WordPress/Tests/DB/DirectDatabaseQueryUnitTest.1.inc | 4 ---- WordPress/Tests/DB/DirectDatabaseQueryUnitTest.2.inc | 8 ++++++++ 2 files changed, 8 insertions(+), 4 deletions(-) create mode 100644 WordPress/Tests/DB/DirectDatabaseQueryUnitTest.2.inc diff --git a/WordPress/Tests/DB/DirectDatabaseQueryUnitTest.1.inc b/WordPress/Tests/DB/DirectDatabaseQueryUnitTest.1.inc index b08d6bea2f..158d33dbe1 100644 --- a/WordPress/Tests/DB/DirectDatabaseQueryUnitTest.1.inc +++ b/WordPress/Tests/DB/DirectDatabaseQueryUnitTest.1.inc @@ -332,7 +332,3 @@ function method_names_are_caseinsensitive() { global $wpdb; $autoload = $wpdb->Get_Var( $wpdb->Prepare( "SELECT autoload FROM $wpdb->options WHERE option_name = %s", $option_name ) ); // Warning x 2. } - -// Live coding/parse error test. -// This must be the last test in the file. -$wpdb->get_col( ' diff --git a/WordPress/Tests/DB/DirectDatabaseQueryUnitTest.2.inc b/WordPress/Tests/DB/DirectDatabaseQueryUnitTest.2.inc new file mode 100644 index 0000000000..ed8c6b75a2 --- /dev/null +++ b/WordPress/Tests/DB/DirectDatabaseQueryUnitTest.2.inc @@ -0,0 +1,8 @@ +get_col( ' From 1bcf29776893ad8eee15b30b2d28fcb89060cc9c Mon Sep 17 00:00:00 2001 From: Rodrigo Primo Date: Thu, 7 Aug 2025 09:41:52 -0300 Subject: [PATCH 042/105] DB/DirectDatabaseQuery: make cache function name matching case-insensitive The sniff was checking cache function names incorrectly, as it was not considering that PHP function names are case-insensitive, leading to false positives. --- .../Sniffs/DB/DirectDatabaseQuerySniff.php | 13 +++++++-- .../DB/DirectDatabaseQueryUnitTest.1.inc | 28 +++++++++++++++++-- .../Tests/DB/DirectDatabaseQueryUnitTest.php | 2 ++ 3 files changed, 37 insertions(+), 6 deletions(-) diff --git a/WordPress/Sniffs/DB/DirectDatabaseQuerySniff.php b/WordPress/Sniffs/DB/DirectDatabaseQuerySniff.php index 590f6478ea..1f30ce1740 100644 --- a/WordPress/Sniffs/DB/DirectDatabaseQuerySniff.php +++ b/WordPress/Sniffs/DB/DirectDatabaseQuerySniff.php @@ -229,18 +229,19 @@ public function process_token( $stackPtr ) { for ( $i = ( $scopeStart + 1 ); $i < $scopeEnd; $i++ ) { if ( \T_STRING === $this->tokens[ $i ]['code'] ) { + $content = strtolower( $this->tokens[ $i ]['content'] ); - if ( isset( $this->cacheDeleteFunctions[ $this->tokens[ $i ]['content'] ] ) ) { + if ( isset( $this->cacheDeleteFunctions[ $content ] ) ) { if ( \in_array( $method, array( 'query', 'update', 'replace', 'delete' ), true ) ) { $cached = true; break; } - } elseif ( isset( $this->cacheGetFunctions[ $this->tokens[ $i ]['content'] ] ) ) { + } elseif ( isset( $this->cacheGetFunctions[ $content ] ) ) { $wp_cache_get = true; - } elseif ( isset( $this->cacheSetFunctions[ $this->tokens[ $i ]['content'] ] ) ) { + } elseif ( isset( $this->cacheSetFunctions[ $content ] ) ) { if ( $wp_cache_get ) { $cached = true; @@ -277,6 +278,8 @@ protected function mergeFunctionLists() { $this->cacheGetFunctions ); + $this->cacheGetFunctions = array_change_key_case( $this->cacheGetFunctions ); + $this->addedCustomFunctions['cacheget'] = $this->customCacheGetFunctions; } @@ -286,6 +289,8 @@ protected function mergeFunctionLists() { $this->cacheSetFunctions ); + $this->cacheSetFunctions = array_change_key_case( $this->cacheSetFunctions ); + $this->addedCustomFunctions['cacheset'] = $this->customCacheSetFunctions; } @@ -295,6 +300,8 @@ protected function mergeFunctionLists() { $this->cacheDeleteFunctions ); + $this->cacheDeleteFunctions = array_change_key_case( $this->cacheDeleteFunctions ); + $this->addedCustomFunctions['cachedelete'] = $this->customCacheDeleteFunctions; } } diff --git a/WordPress/Tests/DB/DirectDatabaseQueryUnitTest.1.inc b/WordPress/Tests/DB/DirectDatabaseQueryUnitTest.1.inc index 158d33dbe1..2691023a8c 100644 --- a/WordPress/Tests/DB/DirectDatabaseQueryUnitTest.1.inc +++ b/WordPress/Tests/DB/DirectDatabaseQueryUnitTest.1.inc @@ -21,13 +21,13 @@ function bar() { function baz() { global $wpdb; - $baz = wp_cache_get( 'baz' ); + $baz = WP_CACHE_GET( 'baz' ); if ( false !== $baz ) { $wpdb->query( 'ALTER TABLE TO ADD SOME FIELDS' ); // Warning x 2. $wpdb->query( $wpdb->prepare( 'CREATE TABLE ' ) ); // Warning x 2. $wpdb->query( 'SELECT QUERY' ); // Warning. $baz = $wpdb->get_results( $wpdb->prepare( 'SELECT X FROM Y ' ) ); // Warning. - wp_cache_set( 'baz', $baz ); + WP_cache_SET( 'baz', $baz ); } } @@ -66,7 +66,7 @@ function cache_delete_only() { $wpdb->get_row( 'SELECT X FROM Y' ); // Warning x 2. $wpdb->get_col( 'SELECT X FROM Y' ); // Warning x 2. - wp_cache_delete( 'key', 'group' ); + WP_CACHE_DELETE( 'key', 'group' ); } // It is OK to use the wp_cache_add() function instead of wp_cache_set(). @@ -332,3 +332,25 @@ function method_names_are_caseinsensitive() { global $wpdb; $autoload = $wpdb->Get_Var( $wpdb->Prepare( "SELECT autoload FROM $wpdb->options WHERE option_name = %s", $option_name ) ); // Warning x 2. } + +// phpcs:set WordPress.DB.DirectDatabaseQuery customCacheGetFunctions[] MY_cacheget +// phpcs:set WordPress.DB.DirectDatabaseQuery customCacheSetFunctions[] my_CACHESET +// phpcs:set WordPress.DB.DirectDatabaseQuery customCacheDeleteFunctions[] MY_cachedel +function cache_custom_mixed_case_A() { + global $wpdb; + $quux = my_cacheget( 'quux' ); + if ( false !== $quux ) { + $wpdb->get_results( 'SELECT X FROM Y' ); // Warning direct DB call. + my_cacheset( 'key', 'group' ); + } +} + +function cache_custom_mixed_case_B() { + global $wpdb; + $wpdb->query( 'SELECT X FROM Y' ); // Warning direct DB call. + my_cachedel( 'key', 'group' ); +} + +// phpcs:set WordPress.DB.DirectDatabaseQuery customCacheGetFunctions[] +// phpcs:set WordPress.DB.DirectDatabaseQuery customCacheSetFunctions[] +// phpcs:set WordPress.DB.DirectDatabaseQuery customCacheDeleteFunctions[] diff --git a/WordPress/Tests/DB/DirectDatabaseQueryUnitTest.php b/WordPress/Tests/DB/DirectDatabaseQueryUnitTest.php index 074a191ba9..d5543bafa5 100644 --- a/WordPress/Tests/DB/DirectDatabaseQueryUnitTest.php +++ b/WordPress/Tests/DB/DirectDatabaseQueryUnitTest.php @@ -95,6 +95,8 @@ public function getWarningList( $testFile = '' ) { 300 => 1, 306 => 2, 333 => 2, + 343 => 1, + 350 => 1, ); default: return array(); From d03c848562ad6a15547269993b23a21c6707e92e Mon Sep 17 00:00:00 2001 From: jrfnl Date: Thu, 11 Sep 2025 19:12:56 +0200 Subject: [PATCH 043/105] Drop support for PHP < 7.2 This commit is a plain version drop. This commit does **not** include: * Removing any work-arounds which _may_ exist in the codebase, to support PHP < 7.2. * Modernizing the codebase. These things can be addressed at will in follow up PRs. Fixes 2606 --- .github/CONTRIBUTING.md | 2 +- .github/workflows/quicktest.yml | 2 +- .github/workflows/unit-tests.yml | 14 +++++--------- .phpcs.xml.dist | 13 +------------ README.md | 4 ++-- composer.json | 4 ++-- phpstan.neon.dist | 2 +- phpunit.xml.dist | 2 +- 8 files changed, 14 insertions(+), 29 deletions(-) diff --git a/.github/CONTRIBUTING.md b/.github/CONTRIBUTING.md index 93a23e59b1..53bdd051fd 100644 --- a/.github/CONTRIBUTING.md +++ b/.github/CONTRIBUTING.md @@ -65,7 +65,7 @@ When you introduce new `public` sniff properties, or your sniff extends a class * PHP_CodeSniffer 3.13.0 or higher * PHPCSUtils 1.1.0 or higher * PHPCSExtra 1.4.0 or higher -* PHPUnit 4.x - 9.x +* PHPUnit 8.x - 9.x The WordPress Coding Standards use the `PHP_CodeSniffer` native unit test framework for unit testing the sniffs. diff --git a/.github/workflows/quicktest.yml b/.github/workflows/quicktest.yml index 355bd3208b..e777483c59 100644 --- a/.github/workflows/quicktest.yml +++ b/.github/workflows/quicktest.yml @@ -23,7 +23,7 @@ jobs: runs-on: ubuntu-latest strategy: matrix: - php: [ '5.4', 'latest' ] + php: [ '7.2', 'latest' ] dependencies: [ 'lowest', 'stable' ] name: QTest - PHP ${{ matrix.php }} on PHPCS ${{ matrix.dependencies }} diff --git a/.github/workflows/unit-tests.yml b/.github/workflows/unit-tests.yml index 33d5e713f0..f4fae9ceaa 100644 --- a/.github/workflows/unit-tests.yml +++ b/.github/workflows/unit-tests.yml @@ -26,7 +26,7 @@ jobs: runs-on: ubuntu-latest strategy: matrix: - php: [ '5.5', '5.6', '7.0', '7.1', '7.2', '7.3', '7.4', '8.0', '8.1', '8.2', '8.3', '8.5' ] + php: [ '7.3', '7.4', '8.0', '8.1', '8.2', '8.3', '8.5' ] dependencies: [ 'lowest', 'stable' ] extensions: [ '' ] coverage: [false] @@ -38,11 +38,11 @@ jobs: coverage: true # Make sure coverage is recorded for this too. # Run code coverage builds against high/low PHP and high/low PHPCS. - - php: '5.4' + - php: '7.2' dependencies: 'stable' extensions: '' coverage: true - - php: '5.4' + - php: '7.2' dependencies: 'lowest' extensions: '' coverage: true @@ -56,15 +56,11 @@ jobs: coverage: true # Test against dev versions of all dependencies with select PHP versions for early detection of issues. - - php: '5.4' - dependencies: 'dev' - extensions: '' - coverage: false - - php: '7.0' + - php: '7.2' dependencies: 'dev' extensions: '' coverage: false - - php: '7.4' + - php: '8.1' dependencies: 'dev' extensions: '' coverage: false diff --git a/.phpcs.xml.dist b/.phpcs.xml.dist index bc350b7977..ed1ea01065 100644 --- a/.phpcs.xml.dist +++ b/.phpcs.xml.dist @@ -50,24 +50,13 @@ - - - - + - - - - - - - - diff --git a/README.md b/README.md index eeb99a1422..02fef784bd 100644 --- a/README.md +++ b/README.md @@ -10,7 +10,7 @@ [![codecov.io](https://codecov.io/gh/WordPress/WordPress-Coding-Standards/graph/badge.svg?token=UzFYn0RzVG&branch=develop)](https://codecov.io/gh/WordPress/WordPress-Coding-Standards?branch=develop) [![Minimum PHP Version](https://img.shields.io/packagist/php-v/wp-coding-standards/wpcs.svg?maxAge=3600)](https://packagist.org/packages/wp-coding-standards/wpcs) -[![Tested on PHP 5.4 to 8.4](https://img.shields.io/badge/tested%20on-PHP%205.4%20|%205.5%20|%205.6%20|%207.0%20|%207.1%20|%207.2%20|%207.3%20|%207.4%20|%208.0%20|%208.1%20|%208.2%20|%208.3%20|%208.4-green.svg?maxAge=2419200)](https://github.com/WordPress/WordPress-Coding-Standards/actions/workflows/unit-tests.yml) +[![Tested on PHP 7.2 to 8.4](https://img.shields.io/badge/tested%20on-PHP%207.2%20|%207.3%20|%207.4%20|%208.0%20|%208.1%20|%208.2%20|%208.3%20|%208.4-green.svg?maxAge=2419200)](https://github.com/WordPress/WordPress-Coding-Standards/actions/workflows/unit-tests.yml) [![License: MIT](https://poser.pugx.org/wp-coding-standards/wpcs/license)](https://github.com/WordPress/WordPress-Coding-Standards/blob/develop/LICENSE) [![Total Downloads](https://poser.pugx.org/wp-coding-standards/wpcs/downloads)](https://packagist.org/packages/wp-coding-standards/wpcs/stats) @@ -53,7 +53,7 @@ This project is a collection of [PHP_CodeSniffer](https://github.com/PHPCSStanda ## Minimum Requirements The WordPress Coding Standards package requires: -* PHP 5.4 or higher with the following extensions enabled: +* PHP 7.2 or higher with the following extensions enabled: - [Filter](https://www.php.net/book.filter) - [libxml](https://www.php.net/book.libxml) - [Tokenizer](https://www.php.net/book.tokenizer) diff --git a/composer.json b/composer.json index 37a8c46252..a5afb55f6b 100644 --- a/composer.json +++ b/composer.json @@ -16,7 +16,7 @@ } ], "require": { - "php": ">=5.4", + "php": ">=7.2", "ext-filter": "*", "ext-libxml": "*", "ext-tokenizer": "*", @@ -27,7 +27,7 @@ }, "require-dev": { "phpcompatibility/php-compatibility": "^9.0", - "phpunit/phpunit": "^4.0 || ^5.0 || ^6.0 || ^7.0 || ^8.0 || ^9.0", + "phpunit/phpunit": "^8.0 || ^9.0", "phpcsstandards/phpcsdevtools": "^1.2.0", "php-parallel-lint/php-parallel-lint": "^1.4.0", "php-parallel-lint/php-console-highlighter": "^1.0.0" diff --git a/phpstan.neon.dist b/phpstan.neon.dist index e9edfc43bc..b69c29b925 100644 --- a/phpstan.neon.dist +++ b/phpstan.neon.dist @@ -1,5 +1,5 @@ parameters: - phpVersion: 70100 # Needs to be 70100 or higher... sigh... + phpVersion: 70200 level: 5 paths: - WordPress diff --git a/phpunit.xml.dist b/phpunit.xml.dist index a5f12e7386..a7a2b1401f 100644 --- a/phpunit.xml.dist +++ b/phpunit.xml.dist @@ -1,7 +1,7 @@ Date: Tue, 5 Aug 2025 16:47:51 -0300 Subject: [PATCH 044/105] Tests: use standardized fixture methods As support for PHPUnit < 8.0 will now be dropped, we no longer need to use the `@before`/`@after`[Class] annotations for fixture methods and can revert back to using the standard PHPUnit `setUp|tearDown[BeforeClass]()` fixture methods (with a `void` return type). --- WordPress/Tests/DB/RestrictedClassesUnitTest.php | 9 +++------ WordPress/Tests/DB/RestrictedFunctionsUnitTest.php | 9 ++------- 2 files changed, 5 insertions(+), 13 deletions(-) diff --git a/WordPress/Tests/DB/RestrictedClassesUnitTest.php b/WordPress/Tests/DB/RestrictedClassesUnitTest.php index dab29264cf..a07ace04d8 100644 --- a/WordPress/Tests/DB/RestrictedClassesUnitTest.php +++ b/WordPress/Tests/DB/RestrictedClassesUnitTest.php @@ -32,11 +32,10 @@ final class RestrictedClassesUnitTest extends AbstractSniffUnitTest { * Note: as that class extends the abstract FunctionRestrictions class, that's * where we are passing the parameters to. * - * @before - * * @return void */ - protected function enhanceGroups() { + protected function setUp(): void { + parent::setUp(); AbstractFunctionRestrictionsSniff::$unittest_groups = array( 'test' => array( 'type' => 'error', @@ -52,11 +51,9 @@ protected function enhanceGroups() { /** * Reset the $groups property. * - * @after - * * @return void */ - protected function resetGroups() { + protected function tearDown(): void { AbstractFunctionRestrictionsSniff::$unittest_groups = array(); parent::tearDown(); } diff --git a/WordPress/Tests/DB/RestrictedFunctionsUnitTest.php b/WordPress/Tests/DB/RestrictedFunctionsUnitTest.php index 73702af626..ad17fc9e67 100644 --- a/WordPress/Tests/DB/RestrictedFunctionsUnitTest.php +++ b/WordPress/Tests/DB/RestrictedFunctionsUnitTest.php @@ -27,13 +27,10 @@ final class RestrictedFunctionsUnitTest extends AbstractSniffUnitTest { * Add a number of extra restricted functions to unit test the abstract * AbstractFunctionRestrictionsSniff class. * - * @before - * * @return void */ - protected function enhanceGroups() { + protected function setUp(): void { parent::setUp(); - AbstractFunctionRestrictionsSniff::$unittest_groups = array( 'test-empty-functions-array' => array( 'type' => 'error', @@ -52,11 +49,9 @@ protected function enhanceGroups() { /** * Reset the $groups property. * - * @after - * * @return void */ - protected function resetGroups() { + protected function tearDown(): void { AbstractFunctionRestrictionsSniff::$unittest_groups = array(); parent::tearDown(); } From 781bb22e4b1ab2f96b2c3539f071140959e19d50 Mon Sep 17 00:00:00 2001 From: jrfnl Date: Mon, 15 Sep 2025 22:49:17 +0200 Subject: [PATCH 045/105] GH Actions: remove build with special set of extensions There was a special build included which is supposed disable Mbstring and record code coverage, but the `extensions` key was missing from the `setup-php` action runner, so Mbstring was never disabled.... Another thing to know about this build is that Mbstring is a required extension for PHPUnit, but it is only really needed when PHPUnit is run with the `--testdox` CLI flag. In later PHPUnit versions, this requirement is enforced across the board (Composer + PHAR), but that's not yet the case for the PHPUnit 8 PHAR file. However, as we run the tests via a Composer install, that install will still fail on the PHPUnit `mbstring` requirement. All in all, this build adds nothing and can be removed. --- .github/workflows/unit-tests.yml | 5 ----- 1 file changed, 5 deletions(-) diff --git a/.github/workflows/unit-tests.yml b/.github/workflows/unit-tests.yml index f4fae9ceaa..9eefe81bd2 100644 --- a/.github/workflows/unit-tests.yml +++ b/.github/workflows/unit-tests.yml @@ -32,11 +32,6 @@ jobs: coverage: [false] include: - - php: '7.2' - dependencies: 'stable' - extensions: ':mbstring' # = Disable Mbstring. - coverage: true # Make sure coverage is recorded for this too. - # Run code coverage builds against high/low PHP and high/low PHPCS. - php: '7.2' dependencies: 'stable' From 78b650dcddc6ad87209c6d91fc0b2ca3babe9bc9 Mon Sep 17 00:00:00 2001 From: Rodrigo Primo Date: Thu, 7 Aug 2025 10:32:01 -0300 Subject: [PATCH 046/105] DB/DirectDatabaseQuery: fix false negatives when cache function names are not a function call Before, the sniff was checking if the content of a `T_STRING` token matched one of the names of the expected cache functions without checking if it was actually a function call. This could lead to some false negatives that are addressed in this commit. As suggested by Juliette, I'm including a test to document that method names that match the cache function names are deliberately not flagged by this sniff as they will be most likely valid custom cache functions. --- .../Sniffs/DB/DirectDatabaseQuerySniff.php | 6 +++++ .../DB/DirectDatabaseQueryUnitTest.1.inc | 25 +++++++++++++++++++ .../Tests/DB/DirectDatabaseQueryUnitTest.php | 2 ++ 3 files changed, 33 insertions(+) diff --git a/WordPress/Sniffs/DB/DirectDatabaseQuerySniff.php b/WordPress/Sniffs/DB/DirectDatabaseQuerySniff.php index 1f30ce1740..a600e6ae83 100644 --- a/WordPress/Sniffs/DB/DirectDatabaseQuerySniff.php +++ b/WordPress/Sniffs/DB/DirectDatabaseQuerySniff.php @@ -229,6 +229,12 @@ public function process_token( $stackPtr ) { for ( $i = ( $scopeStart + 1 ); $i < $scopeEnd; $i++ ) { if ( \T_STRING === $this->tokens[ $i ]['code'] ) { + $nextNonEmpty = $this->phpcsFile->findNext( Tokens::$emptyTokens, ( $i + 1 ), null, true ); + + if ( \T_OPEN_PARENTHESIS !== $this->tokens[ $nextNonEmpty ]['code'] ) { + continue; + } + $content = strtolower( $this->tokens[ $i ]['content'] ); if ( isset( $this->cacheDeleteFunctions[ $content ] ) ) { diff --git a/WordPress/Tests/DB/DirectDatabaseQueryUnitTest.1.inc b/WordPress/Tests/DB/DirectDatabaseQueryUnitTest.1.inc index 2691023a8c..1a6be76a5a 100644 --- a/WordPress/Tests/DB/DirectDatabaseQueryUnitTest.1.inc +++ b/WordPress/Tests/DB/DirectDatabaseQueryUnitTest.1.inc @@ -354,3 +354,28 @@ function cache_custom_mixed_case_B() { // phpcs:set WordPress.DB.DirectDatabaseQuery customCacheGetFunctions[] // phpcs:set WordPress.DB.DirectDatabaseQuery customCacheSetFunctions[] // phpcs:set WordPress.DB.DirectDatabaseQuery customCacheDeleteFunctions[] + +// Protect against false negatives where the cache function names are used as the content +// of a T_STRING token that is not a function call. +function notCacheFunctionCalls() { + global $wpdb; + + $bar->wp_cache_get = 'something'; + $listofthings = $wpdb->get_col( 'SELECT something FROM somewhere WHERE someotherthing = 1' ); // Warning x 2. + $foo = wp_cache_set; + + return $listofthings; +} + +// The sniff deliberately does not distinguish between calls to cache functions and calls to methods with the same name as the functions, +// as those method calls are likely custom cache functions. +function methodNamesSameAsCacheFunctions() { + global $wpdb, $bar; + + if ( ! ( $listofthings = $bar->wp_cache_get( 'foo' ) ) ) { + $listofthings = $wpdb->get_col( 'SELECT something FROM somewhere WHERE someotherthing = 1' ); // Warning direct DB call. + $bar->wp_cache_set( 'foo', $listofthings ); + } + + return $listofthings; +} diff --git a/WordPress/Tests/DB/DirectDatabaseQueryUnitTest.php b/WordPress/Tests/DB/DirectDatabaseQueryUnitTest.php index d5543bafa5..e43fbb126b 100644 --- a/WordPress/Tests/DB/DirectDatabaseQueryUnitTest.php +++ b/WordPress/Tests/DB/DirectDatabaseQueryUnitTest.php @@ -97,6 +97,8 @@ public function getWarningList( $testFile = '' ) { 333 => 2, 343 => 1, 350 => 1, + 364 => 2, + 376 => 1, ); default: return array(); From 9839cbdd5663f4e8b055ebf1c394c2e68df389b5 Mon Sep 17 00:00:00 2001 From: John Jago Date: Tue, 16 Sep 2025 13:43:47 -0400 Subject: [PATCH 047/105] Documentation: Update PHPCompatibilityWP version recommendation to 7.2 (#2471) As of WordPress 6.6, released on 16 July 2024, WordPress no longer supports PHP 7.0 and 7.1 References: https://make.wordpress.org/core/2024/04/08/dropping-support-for-php-7-1/ https://wordpress.org/news/2024/07/dorsey/ --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 02fef784bd..6cefe96d81 100644 --- a/README.md +++ b/README.md @@ -157,13 +157,13 @@ The [PHPCompatibilityWP](https://github.com/PHPCompatibility/PHPCompatibilityWP) Install either as a separate ruleset and run it separately against your code or add it to your custom ruleset, like so: ```xml - + *\.php$ ``` -Whichever way you run it, do make sure you set the `testVersion` to run the sniffs against. The `testVersion` determines for which PHP versions you will receive compatibility information. The recommended setting for this at this moment is `7.0-` to support the same PHP versions as WordPress Core supports. +Whichever way you run it, do make sure you set the `testVersion` to run the sniffs against. The `testVersion` determines for which PHP versions you will receive compatibility information. The recommended setting for this at this moment is `7.2-` to support the same PHP versions as WordPress Core supports. For more information about setting the `testVersion`, see: * [PHPCompatibility: Sniffing your code for compatibility with specific PHP version(s)](https://github.com/PHPCompatibility/PHPCompatibility#sniffing-your-code-for-compatibility-with-specific-php-versions) From 81d9dd4cf985280e3d6eb7211ab228ede67b512d Mon Sep 17 00:00:00 2001 From: jrfnl Date: Tue, 16 Sep 2025 19:26:50 +0200 Subject: [PATCH 048/105] PHP/POSIXFunctions: deprecate the sniff The `WordPress.PHP.POSIXFunctions` sniff is dated and no longer relevant. With this in mind, this commit deprecates the sniff. Additionally, the sniff is removed/excluded from the WPCS rulesets in a way that users who do not directly reference the sniff will not see any deprecation notices. Users who reference the sniff from within their own PHPCS rulesets, will see the deprecation notice. Fixes 2612 Related to WordPress/wpcs-docs 153 --- WordPress-Core/ruleset.xml | 4 --- WordPress/Sniffs/PHP/POSIXFunctionsSniff.php | 32 +++++++++++++++++++- WordPress/ruleset.xml | 11 ++++++- 3 files changed, 41 insertions(+), 6 deletions(-) diff --git a/WordPress-Core/ruleset.xml b/WordPress-Core/ruleset.xml index f97bd73d90..c8f1bedfae 100644 --- a/WordPress-Core/ruleset.xml +++ b/WordPress-Core/ruleset.xml @@ -827,10 +827,6 @@ Ref: https://developer.wordpress.org/coding-standards/wordpress-coding-standards/php/#regular-expressions ############################################################################# --> - - - diff --git a/WordPress/Sniffs/PHP/POSIXFunctionsSniff.php b/WordPress/Sniffs/PHP/POSIXFunctionsSniff.php index 72f77ad551..a6fedf78a9 100644 --- a/WordPress/Sniffs/PHP/POSIXFunctionsSniff.php +++ b/WordPress/Sniffs/PHP/POSIXFunctionsSniff.php @@ -9,6 +9,7 @@ namespace WordPressCS\WordPress\Sniffs\PHP; +use PHP_CodeSniffer\Sniffs\DeprecatedSniff; use WordPressCS\WordPress\AbstractFunctionRestrictionsSniff; /** @@ -22,8 +23,37 @@ * `WordPress.VIP.RestrictedFunctions` and the * `WordPress.PHP.DiscouragedPHPFunctions` sniffs. * @since 0.13.0 Class name changed: this class is now namespaced. + * + * @deprecated 3.3.0 Use the PHPCompatibility standard instead. */ -final class POSIXFunctionsSniff extends AbstractFunctionRestrictionsSniff { +final class POSIXFunctionsSniff extends AbstractFunctionRestrictionsSniff implements DeprecatedSniff { + + /** + * Provide the version number in which the sniff was deprecated. + * + * @return string + */ + public function getDeprecationVersion() { + return 'WordPressCS v3.3.0'; + } + + /** + * Provide the version number in which the sniff will be removed. + * + * @return string + */ + public function getRemovalVersion() { + return 'WordPressCS v4.0.0'; + } + + /** + * Provide a custom message to display with the deprecation. + * + * @return string + */ + public function getDeprecationMessage() { + return 'To scan for PHP cross-version compatibility issues, use the PHPCompatibility standard instead.'; + } /** * Groups of functions to restrict. diff --git a/WordPress/ruleset.xml b/WordPress/ruleset.xml index 6eb7ad8d9e..dc3f56a88b 100644 --- a/WordPress/ruleset.xml +++ b/WordPress/ruleset.xml @@ -8,6 +8,15 @@ --> - + + + + From be1fabaf6150c57085edb7ed16d2b8c53f0eef12 Mon Sep 17 00:00:00 2001 From: jrfnl Date: Tue, 16 Sep 2025 19:27:41 +0200 Subject: [PATCH 049/105] CONTRIBUTING: update the test writing tutorial ... to no longer use the `POSIXFunctions` sniff as an example as that sniff will be removed in WPCS 4.0.0 (and is now deprecated). --- .github/CONTRIBUTING.md | 73 +++++++++++++++++++++-------------------- 1 file changed, 37 insertions(+), 36 deletions(-) diff --git a/.github/CONTRIBUTING.md b/.github/CONTRIBUTING.md index 53bdd051fd..27df074f87 100644 --- a/.github/CONTRIBUTING.md +++ b/.github/CONTRIBUTING.md @@ -124,16 +124,16 @@ OK (60 tests, 6 assertions) ### Unit Testing conventions -If you look inside the `WordPress/Tests` subdirectory, you'll see the structure mimics the `WordPress/Sniffs` subdirectory structure. For example, the `WordPress/Sniffs/PHP/POSIXFunctionsSniff.php` sniff has its unit test class defined in `WordPress/Tests/PHP/POSIXFunctionsUnitTest.php` which checks the `WordPress/Tests/PHP/POSIXFunctionsUnitTest.inc` test case file. See the file naming convention? +If you look inside the `WordPress/Tests` subdirectory, you'll see the structure mimics the `WordPress/Sniffs` subdirectory structure. For example, the `WordPress/Sniffs/PHP/TypeCastsSniff.php` sniff has its unit test class defined in `WordPress/Tests/PHP/TypeCastsUnitTest.php` which checks the `WordPress/Tests/PHP/TypeCastsUnitTest.inc` test case file. See the file naming convention? -Lets take a look at what's inside `POSIXFunctionsUnitTest.php`: +Lets take a look at what's inside `TypeCastsUnitTest.php`: ```php namespace WordPressCS\WordPress\Tests\PHP; use PHP_CodeSniffer\Tests\Standards\AbstractSniffUnitTest; -final class POSIXFunctionsUnitTest extends AbstractSniffUnitTest { +final class TypeCastsUnitTest extends AbstractSniffUnitTest { /** * Returns the lines where errors should occur. @@ -142,13 +142,12 @@ final class POSIXFunctionsUnitTest extends AbstractSniffUnitTest { */ public function getErrorList() { return array( + 10 => 1, + 11 => 1, 13 => 1, - 16 => 1, - 18 => 1, - 20 => 1, - 22 => 1, - 24 => 1, 26 => 1, + 27 => 1, + 28 => 1, ); } @@ -156,39 +155,41 @@ final class POSIXFunctionsUnitTest extends AbstractSniffUnitTest { } ``` -Also note the class name convention. The method `getErrorList()` MUST return an array of line numbers indicating errors (when running `phpcs`) found in `WordPress/Tests/PHP/POSIXFunctionsUnitTest.inc`. Similarly, the `getWarningList()` method must return an array of line numbers with the number of expected warnings. +Also note the class name convention. The method `getErrorList()` MUST return an array of line numbers indicating errors (when running `phpcs`) found in `WordPress/Tests/PHP/TypeCastsUnitTest.inc`. Similarly, the `getWarningList()` method must return an array of line numbers with the number of expected warnings. If you run the following from the root directory of your WordPressCS clone: ```sh -$ "vendor/bin/phpcs" --standard=Wordpress -s ./WordPress/Tests/PHP/POSIXFunctionsUnitTest.inc --sniffs=WordPress.PHP.POSIXFunctions -... --------------------------------------------------------------------------------- -FOUND 7 ERRORS AFFECTING 7 LINES --------------------------------------------------------------------------------- - 13 | ERROR | ereg() has been deprecated since PHP 5.3 and removed in PHP 7.0, - | | please use preg_match() instead. - | | (WordPress.PHP.POSIXFunctions.ereg_ereg) - 16 | ERROR | eregi() has been deprecated since PHP 5.3 and removed in PHP 7.0, - | | please use preg_match() instead. - | | (WordPress.PHP.POSIXFunctions.ereg_eregi) - 18 | ERROR | ereg_replace() has been deprecated since PHP 5.3 and removed in - | | PHP 7.0, please use preg_replace() instead. - | | (WordPress.PHP.POSIXFunctions.ereg_replace_ereg_replace) - 20 | ERROR | eregi_replace() has been deprecated since PHP 5.3 and removed in - | | PHP 7.0, please use preg_replace() instead. - | | (WordPress.PHP.POSIXFunctions.ereg_replace_eregi_replace) - 22 | ERROR | split() has been deprecated since PHP 5.3 and removed in PHP 7.0, - | | please use explode(), str_split() or preg_split() instead. - | | (WordPress.PHP.POSIXFunctions.split_split) - 24 | ERROR | spliti() has been deprecated since PHP 5.3 and removed in PHP - | | 7.0, please use explode(), str_split() or preg_split() - | | instead. (WordPress.PHP.POSIXFunctions.split_spliti) - 26 | ERROR | sql_regcase() has been deprecated since PHP 5.3 and removed in - | | PHP 7.0, please use preg_match() instead. - | | (WordPress.PHP.POSIXFunctions.ereg_sql_regcase) --------------------------------------------------------------------------------- +$ "vendor/bin/phpcs" --standard=Wordpress -s ./WordPress/Tests/PHP/TypeCastsUnitTest.inc --sniffs=WordPress.PHP.TypeCasts ... +---------------------------------------------------------------------------------------------------- +FOUND 6 ERRORS AND 4 WARNINGS AFFECTING 10 LINES +---------------------------------------------------------------------------------------------------- + 10 | ERROR | [x] Normalized type keywords must be used; expected "(float)" but found "(double)" + | | (WordPress.PHP.TypeCasts.DoubleRealFound) + 11 | ERROR | [x] Normalized type keywords must be used; expected "(float)" but found "(real)" + | | (WordPress.PHP.TypeCasts.DoubleRealFound) + 13 | ERROR | [ ] Using the "(unset)" cast is forbidden as the type cast is removed in PHP 8.0. + | | Use the "unset()" language construct instead. + | | (WordPress.PHP.TypeCasts.UnsetFound) + 15 | WARNING | [ ] Using binary casting is strongly discouraged. Found: "(binary)" + | | (WordPress.PHP.TypeCasts.BinaryFound) + 16 | WARNING | [ ] Using binary casting is strongly discouraged. Found: "b" + | | (WordPress.PHP.TypeCasts.BinaryFound) + 17 | WARNING | [ ] Using binary casting is strongly discouraged. Found: "b" + | | (WordPress.PHP.TypeCasts.BinaryFound) + 26 | ERROR | [x] Normalized type keywords must be used; expected "(float)" but found "(double)" + | | (WordPress.PHP.TypeCasts.DoubleRealFound) + 27 | ERROR | [x] Normalized type keywords must be used; expected "(float)" but found "(real)" + | | (WordPress.PHP.TypeCasts.DoubleRealFound) + 28 | ERROR | [ ] Using the "(unset)" cast is forbidden as the type cast is removed in PHP 8.0. + | | Use the "unset()" language construct instead. + | | (WordPress.PHP.TypeCasts.UnsetFound) + 29 | WARNING | [ ] Using binary casting is strongly discouraged. Found: "(binary)" + | | (WordPress.PHP.TypeCasts.BinaryFound) +---------------------------------------------------------------------------------------------------- +PHPCBF CAN FIX THE 4 MARKED SNIFF VIOLATIONS AUTOMATICALLY +---------------------------------------------------------------------------------------------------- ``` You'll see the line number and number of ERRORs we need to return in the `getErrorList()` method. From 93c82848f99f9faa48617323ac217f546a8a52fe Mon Sep 17 00:00:00 2001 From: Juliette <663378+jrfnl@users.noreply.github.com> Date: Wed, 17 Sep 2025 15:35:02 +0200 Subject: [PATCH 050/105] GH Actions: update for upstream branch rename (#2611) Co-authored-by: jrfnl --- .github/workflows/basic-qa.yml | 2 +- .github/workflows/unit-tests.yml | 2 +- WordPress/Sniffs/NamingConventions/ValidVariableNameSniff.php | 2 +- WordPress/Sniffs/WhiteSpace/ControlStructureSpacingSniff.php | 2 +- WordPress/Sniffs/WhiteSpace/ObjectOperatorSpacingSniff.php | 2 +- WordPress/Sniffs/WhiteSpace/OperatorSpacingSniff.php | 2 +- 6 files changed, 6 insertions(+), 6 deletions(-) diff --git a/.github/workflows/basic-qa.yml b/.github/workflows/basic-qa.yml index e858145992..5d1405ed63 100644 --- a/.github/workflows/basic-qa.yml +++ b/.github/workflows/basic-qa.yml @@ -13,7 +13,7 @@ concurrency: cancel-in-progress: true env: - PHPCS_DEV: 'dev-master' + PHPCS_DEV: '3.x-dev' UTILS_DEV: 'dev-develop' EXTRA_DEV: 'dev-develop' diff --git a/.github/workflows/unit-tests.yml b/.github/workflows/unit-tests.yml index 9eefe81bd2..3725c8c231 100644 --- a/.github/workflows/unit-tests.yml +++ b/.github/workflows/unit-tests.yml @@ -15,7 +15,7 @@ concurrency: cancel-in-progress: true env: - PHPCS_DEV: 'dev-master' + PHPCS_DEV: '3.x-dev' UTILS_DEV: 'dev-develop' EXTRA_DEV: 'dev-develop' diff --git a/WordPress/Sniffs/NamingConventions/ValidVariableNameSniff.php b/WordPress/Sniffs/NamingConventions/ValidVariableNameSniff.php index 6202f2b5e3..9d41e8b2ae 100644 --- a/WordPress/Sniffs/NamingConventions/ValidVariableNameSniff.php +++ b/WordPress/Sniffs/NamingConventions/ValidVariableNameSniff.php @@ -29,7 +29,7 @@ * @since 2.0.0 Now offers name suggestions for variables in violation. * * Last synced with base class January 2022 at commit 4b49a952bf0e2c3863d0a113256bae0d7fe63d52. - * @link https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/src/Standards/Squiz/Sniffs/NamingConventions/ValidVariableNameSniff.php + * @link https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/HEAD/src/Standards/Squiz/Sniffs/NamingConventions/ValidVariableNameSniff.php */ final class ValidVariableNameSniff extends PHPCS_AbstractVariableSniff { diff --git a/WordPress/Sniffs/WhiteSpace/ControlStructureSpacingSniff.php b/WordPress/Sniffs/WhiteSpace/ControlStructureSpacingSniff.php index f9b5038b74..f1770754b7 100644 --- a/WordPress/Sniffs/WhiteSpace/ControlStructureSpacingSniff.php +++ b/WordPress/Sniffs/WhiteSpace/ControlStructureSpacingSniff.php @@ -26,7 +26,7 @@ * Last synced with base class 2021-11-20 at commit 7f11ffc8222b123c06345afd3261221561c3bb29. * Note: This class has diverged quite far from the original. All the same, checking occasionally * to see if there are upstream fixes made from which this sniff can benefit, is warranted. - * @link https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/src/Standards/Squiz/Sniffs/WhiteSpace/ControlStructureSpacingSniff.php + * @link https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/HEAD/src/Standards/Squiz/Sniffs/WhiteSpace/ControlStructureSpacingSniff.php */ final class ControlStructureSpacingSniff extends Sniff { diff --git a/WordPress/Sniffs/WhiteSpace/ObjectOperatorSpacingSniff.php b/WordPress/Sniffs/WhiteSpace/ObjectOperatorSpacingSniff.php index a832b4f2c6..9ad532eb3d 100644 --- a/WordPress/Sniffs/WhiteSpace/ObjectOperatorSpacingSniff.php +++ b/WordPress/Sniffs/WhiteSpace/ObjectOperatorSpacingSniff.php @@ -20,7 +20,7 @@ * - When the `::` operator is used in `::class`, no new line(s) before or after the object operator are allowed. * * @since 3.0.0 - * @link https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/src/Standards/Squiz/Sniffs/WhiteSpace/ObjectOperatorSpacingSniff.php + * @link https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/HEAD/src/Standards/Squiz/Sniffs/WhiteSpace/ObjectOperatorSpacingSniff.php */ final class ObjectOperatorSpacingSniff extends Squiz_ObjectOperatorSpacingSniff { diff --git a/WordPress/Sniffs/WhiteSpace/OperatorSpacingSniff.php b/WordPress/Sniffs/WhiteSpace/OperatorSpacingSniff.php index 2caa937df0..5e1ceb66be 100644 --- a/WordPress/Sniffs/WhiteSpace/OperatorSpacingSniff.php +++ b/WordPress/Sniffs/WhiteSpace/OperatorSpacingSniff.php @@ -31,7 +31,7 @@ * @since 0.13.0 Class name changed: this class is now namespaced. * * Last verified with base class June 2023 at commit 085b1e091b0f2e451333c0bc26dd50bba39402c4. - * @link https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/CodeSniffer/Standards/Squiz/Sniffs/WhiteSpace/OperatorSpacingSniff.php + * @link https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/HEAD/CodeSniffer/Standards/Squiz/Sniffs/WhiteSpace/OperatorSpacingSniff.php */ final class OperatorSpacingSniff extends PHPCS_Squiz_OperatorSpacingSniff { From 6f6485d1e6fc67dc4cbfbda5e9c69bc98f83dd85 Mon Sep 17 00:00:00 2001 From: Rodrigo Primo Date: Tue, 12 Aug 2025 15:12:51 -0300 Subject: [PATCH 051/105] Security/NonceVerification: handle function names case correctly The sniff was incorrectly treating function names as case-sensitive when checking for nonce verification functions. This led to false positives when developers used valid nonce verification functions with mixed or uppercase letters. The fix ensures function names are properly converted to lowercase before comparing against the allowed nonce verification functions list, respecting PHP's case-insensitive function name behavior. --- WordPress/Sniffs/Security/NonceVerificationSniff.php | 4 +++- WordPress/Tests/Security/NonceVerificationUnitTest.1.inc | 7 +++++++ 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/WordPress/Sniffs/Security/NonceVerificationSniff.php b/WordPress/Sniffs/Security/NonceVerificationSniff.php index 0241147327..8464e702fe 100644 --- a/WordPress/Sniffs/Security/NonceVerificationSniff.php +++ b/WordPress/Sniffs/Security/NonceVerificationSniff.php @@ -309,8 +309,10 @@ private function has_nonce_check( $stackPtr, array $cache_keys, $allow_nonce_aft continue; } + $content_lc = \strtolower( $this->tokens[ $i ]['content'] ); + // If this is one of the nonce verification functions, we can bail out. - if ( isset( $this->nonceVerificationFunctions[ $this->tokens[ $i ]['content'] ] ) ) { + if ( isset( $this->nonceVerificationFunctions[ $content_lc ] ) ) { /* * Now, make sure it is a call to a global function. */ diff --git a/WordPress/Tests/Security/NonceVerificationUnitTest.1.inc b/WordPress/Tests/Security/NonceVerificationUnitTest.1.inc index f9f98799f6..5d5e3db0fc 100644 --- a/WordPress/Tests/Security/NonceVerificationUnitTest.1.inc +++ b/WordPress/Tests/Security/NonceVerificationUnitTest.1.inc @@ -486,3 +486,10 @@ enum MyEnum { echo $_POST['foo']; // OK. } } + +// Good, has a nonce check. Ensure the check is case-insensitive as function names are case-insensitive in PHP. +function ajax_process() { + CHECK_AJAX_REFERER( 'something' ); + + update_post_meta( (int) $_POST['id'], 'a_key', $_POST['a_value'] ); +} From fde3f7d641710c6287314d418a8c1abd2ad1a436 Mon Sep 17 00:00:00 2001 From: Rodrigo Primo Date: Wed, 3 Sep 2025 15:43:24 -0300 Subject: [PATCH 052/105] Ensure sniff handles custom nonce verification functions case correctly --- WordPress/Sniffs/Security/NonceVerificationSniff.php | 2 ++ WordPress/Tests/Security/NonceVerificationUnitTest.1.inc | 8 ++++++++ 2 files changed, 10 insertions(+) diff --git a/WordPress/Sniffs/Security/NonceVerificationSniff.php b/WordPress/Sniffs/Security/NonceVerificationSniff.php index 8464e702fe..f52aa649fb 100644 --- a/WordPress/Sniffs/Security/NonceVerificationSniff.php +++ b/WordPress/Sniffs/Security/NonceVerificationSniff.php @@ -413,6 +413,8 @@ private function set_cache( $filename, $start, $end, $nonce ) { */ protected function mergeFunctionLists() { if ( $this->customNonceVerificationFunctions !== $this->addedCustomNonceFunctions ) { + $this->customNonceVerificationFunctions = array_map( 'strtolower', $this->customNonceVerificationFunctions ); + $this->nonceVerificationFunctions = RulesetPropertyHelper::merge_custom_array( $this->customNonceVerificationFunctions, $this->nonceVerificationFunctions diff --git a/WordPress/Tests/Security/NonceVerificationUnitTest.1.inc b/WordPress/Tests/Security/NonceVerificationUnitTest.1.inc index 5d5e3db0fc..463b5e87ec 100644 --- a/WordPress/Tests/Security/NonceVerificationUnitTest.1.inc +++ b/WordPress/Tests/Security/NonceVerificationUnitTest.1.inc @@ -493,3 +493,11 @@ function ajax_process() { update_post_meta( (int) $_POST['id'], 'a_key', $_POST['a_value'] ); } + +// phpcs:set WordPress.Security.NonceVerification customNonceVerificationFunctions[] MIXED_case_NAME +function non_ascii_characters() { + MIXED_case_NAME( $_POST['something'] ); // Passing $_POST to ensure the sniff bails correctly for variables inside the nonce verification function. + + update_post_meta( (int) $_POST['id'], 'a_key', $_POST['a_value'] ); +} +// phpcs:set WordPress.Security.NonceVerification customNonceVerificationFunctions[] From 89d30665982b0ee399dba5d9ef0540a15ce02e71 Mon Sep 17 00:00:00 2001 From: Rodrigo Primo Date: Wed, 3 Sep 2025 15:44:22 -0300 Subject: [PATCH 053/105] Add tests safeguarding that non-ANSCII characters are handled correctly when looking for nonce verification functions --- .../Security/NonceVerificationUnitTest.1.inc | 23 +++++++++++++++++++ .../Security/NonceVerificationUnitTest.php | 1 + 2 files changed, 24 insertions(+) diff --git a/WordPress/Tests/Security/NonceVerificationUnitTest.1.inc b/WordPress/Tests/Security/NonceVerificationUnitTest.1.inc index 463b5e87ec..aee51ae39a 100644 --- a/WordPress/Tests/Security/NonceVerificationUnitTest.1.inc +++ b/WordPress/Tests/Security/NonceVerificationUnitTest.1.inc @@ -501,3 +501,26 @@ function non_ascii_characters() { update_post_meta( (int) $_POST['id'], 'a_key', $_POST['a_value'] ); } // phpcs:set WordPress.Security.NonceVerification customNonceVerificationFunctions[] + +/* + * Test case handling of non-ASCII characters in function names. + */ +// phpcs:set WordPress.Security.NonceVerification customNonceVerificationFunctions[] déjà_vu +function same_function_same_case() { + déjà_vu( 'something' ); // Ok. + + update_post_meta( (int) $_POST['id'], 'a_key', $_POST['a_value'] ); +} + +function same_function_different_case() { + DéJà_VU( 'something' ); // Ok. + + update_post_meta( (int) $_POST['id'], 'a_key', $_POST['a_value'] ); +} + +function different_function_name() { + dÉjÀ_vu( 'something' ); // Bad, dÉjÀ_vu() and déjà_vu() are NOT the same function. + + update_post_meta( (int) $_POST['id'], 'a_key', $_POST['a_value'] ); +} +// phpcs:set WordPress.Security.NonceVerification customNonceVerificationFunctions[] diff --git a/WordPress/Tests/Security/NonceVerificationUnitTest.php b/WordPress/Tests/Security/NonceVerificationUnitTest.php index edb18099c4..aa5e832e83 100644 --- a/WordPress/Tests/Security/NonceVerificationUnitTest.php +++ b/WordPress/Tests/Security/NonceVerificationUnitTest.php @@ -74,6 +74,7 @@ public function getErrorList( $testFile = '' ) { 453 => 1, 470 => 1, 478 => 1, + 524 => 2, ); case 'NonceVerificationUnitTest.2.inc': From 106aa59fb06fbb9c4e46a1fdad7a86a709f68809 Mon Sep 17 00:00:00 2001 From: Rodrigo Primo Date: Thu, 4 Sep 2025 11:07:26 -0300 Subject: [PATCH 054/105] Normalize `nonceVerificationFunctions` instead of `customNonceVerificationFunctions` --- WordPress/Sniffs/Security/NonceVerificationSniff.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/WordPress/Sniffs/Security/NonceVerificationSniff.php b/WordPress/Sniffs/Security/NonceVerificationSniff.php index f52aa649fb..06b941fc79 100644 --- a/WordPress/Sniffs/Security/NonceVerificationSniff.php +++ b/WordPress/Sniffs/Security/NonceVerificationSniff.php @@ -413,13 +413,13 @@ private function set_cache( $filename, $start, $end, $nonce ) { */ protected function mergeFunctionLists() { if ( $this->customNonceVerificationFunctions !== $this->addedCustomNonceFunctions ) { - $this->customNonceVerificationFunctions = array_map( 'strtolower', $this->customNonceVerificationFunctions ); - $this->nonceVerificationFunctions = RulesetPropertyHelper::merge_custom_array( $this->customNonceVerificationFunctions, $this->nonceVerificationFunctions ); + $this->nonceVerificationFunctions = array_change_key_case( $this->nonceVerificationFunctions ); + $this->addedCustomNonceFunctions = $this->customNonceVerificationFunctions; } } From 2bc0492afeb93a3b35bfd757d18b325fad00418c Mon Sep 17 00:00:00 2001 From: Rodrigo Primo Date: Thu, 21 Aug 2025 15:30:05 -0300 Subject: [PATCH 055/105] AbstractFunctionRestrictions: add tests for namespaced names The DiscouragedFunctionsUnitTest.inc tests are currently used to test the `AbstractFunctionRestrictions` class and mostly covered everything that was necessary. Except fully qualified call to a non-global function. I opted to add the test in the middle of the file and remove a blank line to keep the namespaced calls tests together. --- WordPress/Tests/WP/DiscouragedFunctionsUnitTest.inc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/WordPress/Tests/WP/DiscouragedFunctionsUnitTest.inc b/WordPress/Tests/WP/DiscouragedFunctionsUnitTest.inc index 5e952933d2..66a33f4984 100644 --- a/WordPress/Tests/WP/DiscouragedFunctionsUnitTest.inc +++ b/WordPress/Tests/WP/DiscouragedFunctionsUnitTest.inc @@ -14,8 +14,8 @@ $obj?->query_posts(); // OK, not the global function. // Ensure the sniff doesn't act on namespaced calls. MyNamespace\query_posts(); // OK, not the global function. +\MyNamespace\query_posts(); // OK, not the global function. namespace\query_posts(); // OK, not the global function. - // ... but does act on fully qualified function calls. \query_posts(); // Warning. From 225676ad8a59a5eb74bc630e5b8fc747ca67a61d Mon Sep 17 00:00:00 2001 From: Rodrigo Primo Date: Thu, 21 Aug 2025 16:19:50 -0300 Subject: [PATCH 056/105] DateTime/RestrictedFunctions: add tests for namespaced names --- WordPress/Tests/DateTime/RestrictedFunctionsUnitTest.inc | 8 ++++++++ WordPress/Tests/DateTime/RestrictedFunctionsUnitTest.php | 5 +++-- 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/WordPress/Tests/DateTime/RestrictedFunctionsUnitTest.inc b/WordPress/Tests/DateTime/RestrictedFunctionsUnitTest.inc index 25227b5178..f96842c9e7 100644 --- a/WordPress/Tests/DateTime/RestrictedFunctionsUnitTest.inc +++ b/WordPress/Tests/DateTime/RestrictedFunctionsUnitTest.inc @@ -7,3 +7,11 @@ $date->setTimezone( new DateTimeZone( 'America/Toronto' ) ); // Yay! $post_data['post_title'] = sprintf( __( 'Draft created on %1$s at %2$s' ), date( __( 'F j, Y' ), $now ), date( __( 'g:i a' ), $now ) ); // Error. $post_data['post_title'] = sprintf( __( 'Draft created on %1$s at %2$s' ), gmdate( __( 'F j, Y' ), $now ), gmdate( __( 'g:i a' ), $now ) ); // OK. + +/* + * Safeguard correct handling of all types of namespaced function calls. + */ +\date_default_timezone_set( 'Foo/Bar' ); +MyNamespace\date_default_timezone_set( 'Foo/Bar' ); +\MyNamespace\date_default_timezone_set( 'Foo/Bar' ); +namespace\date_default_timezone_set( 'Foo/Bar' ); // The sniff should start flagging this once it can resolve relative namespaces. diff --git a/WordPress/Tests/DateTime/RestrictedFunctionsUnitTest.php b/WordPress/Tests/DateTime/RestrictedFunctionsUnitTest.php index f5e160bc62..a2f29c2364 100644 --- a/WordPress/Tests/DateTime/RestrictedFunctionsUnitTest.php +++ b/WordPress/Tests/DateTime/RestrictedFunctionsUnitTest.php @@ -27,8 +27,9 @@ final class RestrictedFunctionsUnitTest extends AbstractSniffUnitTest { */ public function getErrorList() { return array( - 3 => 1, - 8 => 2, + 3 => 1, + 8 => 2, + 14 => 1, ); } From b95ef97f7abcd8363abd9b81cd4a1b72d83f2244 Mon Sep 17 00:00:00 2001 From: Rodrigo Primo Date: Thu, 21 Aug 2025 16:23:41 -0300 Subject: [PATCH 057/105] DB/RestrictedFunctions: add tests for namespaced names --- .../Tests/DB/RestrictedFunctionsUnitTest.inc | 8 ++ .../Tests/DB/RestrictedFunctionsUnitTest.php | 84 ++++++++++--------- 2 files changed, 51 insertions(+), 41 deletions(-) diff --git a/WordPress/Tests/DB/RestrictedFunctionsUnitTest.inc b/WordPress/Tests/DB/RestrictedFunctionsUnitTest.inc index bb976bf8fe..3bebe1fdc2 100644 --- a/WordPress/Tests/DB/RestrictedFunctionsUnitTest.inc +++ b/WordPress/Tests/DB/RestrictedFunctionsUnitTest.inc @@ -94,3 +94,11 @@ WP_Date_Query::build_mysql_datetime(); // Ok. myFictionFunction(); // Bad. myFictional(); // OK. Myfictional(); // OK. + +/* + * Safeguard correct handling of all types of namespaced function calls. + */ +\mysql_connect(); +MyNamespace\mysql_connect(); +\MyNamespace\mysql_connect(); +namespace\mysql_connect(); // The sniff should start flagging this once it can resolve relative namespaces. diff --git a/WordPress/Tests/DB/RestrictedFunctionsUnitTest.php b/WordPress/Tests/DB/RestrictedFunctionsUnitTest.php index ad17fc9e67..7b730c5f59 100644 --- a/WordPress/Tests/DB/RestrictedFunctionsUnitTest.php +++ b/WordPress/Tests/DB/RestrictedFunctionsUnitTest.php @@ -63,54 +63,56 @@ protected function tearDown(): void { */ public function getErrorList() { return array( - 25 => 1, - 26 => 1, - 27 => 1, - 28 => 1, - 29 => 1, - 30 => 1, - 31 => 1, - 32 => 1, - 33 => 1, + 25 => 1, + 26 => 1, + 27 => 1, + 28 => 1, + 29 => 1, + 30 => 1, + 31 => 1, + 32 => 1, + 33 => 1, - 36 => 1, - 37 => 1, - 38 => 1, - 39 => 1, - 40 => 1, - 41 => 1, - 42 => 1, - 43 => 1, - 44 => 1, + 36 => 1, + 37 => 1, + 38 => 1, + 39 => 1, + 40 => 1, + 41 => 1, + 42 => 1, + 43 => 1, + 44 => 1, - 47 => 1, - 48 => 1, - 49 => 1, - 50 => 1, - 51 => 1, + 47 => 1, + 48 => 1, + 49 => 1, + 50 => 1, + 51 => 1, - 54 => 1, - 55 => 1, - 56 => 1, - 57 => 1, + 54 => 1, + 55 => 1, + 56 => 1, + 57 => 1, - 60 => 1, + 60 => 1, - 63 => 1, + 63 => 1, - 66 => 1, - 67 => 1, - 68 => 1, - 69 => 1, - 70 => 1, - 71 => 1, - 72 => 1, - 73 => 1, - 74 => 1, - 75 => 1, - 76 => 1, + 66 => 1, + 67 => 1, + 68 => 1, + 69 => 1, + 70 => 1, + 71 => 1, + 72 => 1, + 73 => 1, + 74 => 1, + 75 => 1, + 76 => 1, - 94 => 1, + 94 => 1, + + 101 => 1, ); } From 248a2acecd346cc456c8a1246721126f5a7e459d Mon Sep 17 00:00:00 2001 From: Rodrigo Primo Date: Thu, 21 Aug 2025 16:30:11 -0300 Subject: [PATCH 058/105] PHP/DevelopmentFunctions: add tests for namespaced names --- WordPress/Tests/PHP/DevelopmentFunctionsUnitTest.inc | 10 ++++++++-- WordPress/Tests/PHP/DevelopmentFunctionsUnitTest.php | 1 + 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/WordPress/Tests/PHP/DevelopmentFunctionsUnitTest.inc b/WordPress/Tests/PHP/DevelopmentFunctionsUnitTest.inc index b07e7a8ce6..ada6fa9b4a 100644 --- a/WordPress/Tests/PHP/DevelopmentFunctionsUnitTest.inc +++ b/WordPress/Tests/PHP/DevelopmentFunctionsUnitTest.inc @@ -35,5 +35,11 @@ phpinfo(); // Error. Wrapper_Class::var_dump(); // OK, not the native PHP function. $wrapper ->var_dump(); // OK, not the native PHP function. -namespace\var_dump(); // OK as long as the file is namespaced. -MyNamespace\var_dump(); // OK, namespaced function. + +/* + * Safeguard correct handling of all types of namespaced function calls. + */ +\var_dump( $value ); +MyNamespace\var_dump( $value ); +\MyNamespace\var_dump( $value ); +namespace\var_dump( $value ); // The sniff should start flagging this once it can resolve relative namespaces. diff --git a/WordPress/Tests/PHP/DevelopmentFunctionsUnitTest.php b/WordPress/Tests/PHP/DevelopmentFunctionsUnitTest.php index 8be090a5bf..f3e953545c 100644 --- a/WordPress/Tests/PHP/DevelopmentFunctionsUnitTest.php +++ b/WordPress/Tests/PHP/DevelopmentFunctionsUnitTest.php @@ -52,6 +52,7 @@ public function getWarningList() { 24 => 1, 33 => 1, 34 => 1, + 42 => 1, ); } } From 06718588bc79836c9c2fcf80cda2eb59aaec4d9a Mon Sep 17 00:00:00 2001 From: Rodrigo Primo Date: Thu, 21 Aug 2025 16:30:27 -0300 Subject: [PATCH 059/105] PHP/DiscouragedPHPFunctions: add tests for namespaced names --- .../Tests/PHP/DiscouragedPHPFunctionsUnitTest.inc | 10 +++++----- .../Tests/PHP/DiscouragedPHPFunctionsUnitTest.php | 1 + 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/WordPress/Tests/PHP/DiscouragedPHPFunctionsUnitTest.inc b/WordPress/Tests/PHP/DiscouragedPHPFunctionsUnitTest.inc index 9a17c8a6d8..84b7378b65 100644 --- a/WordPress/Tests/PHP/DiscouragedPHPFunctionsUnitTest.inc +++ b/WordPress/Tests/PHP/DiscouragedPHPFunctionsUnitTest.inc @@ -1,12 +1,12 @@ 1, 9 => 1, 10 => 1, 12 => 1, From 293e3e3c76e035638a55577364872d90e730cc59 Mon Sep 17 00:00:00 2001 From: Rodrigo Primo Date: Thu, 21 Aug 2025 16:32:01 -0300 Subject: [PATCH 060/105] PHP/DontExtract: add tests for namespaced names --- WordPress/Tests/PHP/DontExtractUnitTest.inc | 8 ++++++++ WordPress/Tests/PHP/DontExtractUnitTest.php | 3 ++- 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/WordPress/Tests/PHP/DontExtractUnitTest.inc b/WordPress/Tests/PHP/DontExtractUnitTest.inc index 9ed5c3d2b2..7cf000403c 100644 --- a/WordPress/Tests/PHP/DontExtractUnitTest.inc +++ b/WordPress/Tests/PHP/DontExtractUnitTest.inc @@ -7,3 +7,11 @@ my_extract(); // Ok. My_Object::extract(); // Ok. $this->extract(); // Ok. $my_object->extract(); // Ok. + +/* + * Safeguard correct handling of all types of namespaced function calls. + */ +\extract( array( 'a' => 1 ) ); +MyNamespace\extract( array( 'a' => 1 ) ); +\MyNamespace\extract( array( 'a' => 1 ) ); +namespace\extract( array( 'a' => 1 ) ); // The sniff should start flagging this once it can resolve relative namespaces. diff --git a/WordPress/Tests/PHP/DontExtractUnitTest.php b/WordPress/Tests/PHP/DontExtractUnitTest.php index 3efee7c9a8..f9a1df7494 100644 --- a/WordPress/Tests/PHP/DontExtractUnitTest.php +++ b/WordPress/Tests/PHP/DontExtractUnitTest.php @@ -29,7 +29,8 @@ final class DontExtractUnitTest extends AbstractSniffUnitTest { */ public function getErrorList() { return array( - 3 => 1, + 3 => 1, + 14 => 1, ); } From ea863863699c9101813d65b09b9da06cde916fc5 Mon Sep 17 00:00:00 2001 From: Rodrigo Primo Date: Thu, 21 Aug 2025 16:34:19 -0300 Subject: [PATCH 061/105] PHP/POSIXFunctions: add tests for namespaced names --- WordPress/Tests/PHP/POSIXFunctionsUnitTest.inc | 8 ++++++++ WordPress/Tests/PHP/POSIXFunctionsUnitTest.php | 1 + 2 files changed, 9 insertions(+) diff --git a/WordPress/Tests/PHP/POSIXFunctionsUnitTest.inc b/WordPress/Tests/PHP/POSIXFunctionsUnitTest.inc index 785779e02b..b3bb11a71c 100644 --- a/WordPress/Tests/PHP/POSIXFunctionsUnitTest.inc +++ b/WordPress/Tests/PHP/POSIXFunctionsUnitTest.inc @@ -24,3 +24,11 @@ list( $year, $month, $day ) = split( ':', $date ); // Bad, split has been deprec $title_parts = spliti( ' ', get_the_title(), 4 ); // Bad, spliti also deprecated. Use preg_split instead. sql_regcase( 'Foo - bar.'); // Bad. Deprecated. + +/* + * Safeguard correct handling of all types of namespaced function calls. + */ +\split( ':', $date ); +MyNamespace\split( ':', $date ); +\MyNamespace\split( ':', $date ); +namespace\split( ':', $date ); // The sniff should start flagging this once it can resolve relative namespaces. diff --git a/WordPress/Tests/PHP/POSIXFunctionsUnitTest.php b/WordPress/Tests/PHP/POSIXFunctionsUnitTest.php index 7dbfcd6100..d4086c3e49 100644 --- a/WordPress/Tests/PHP/POSIXFunctionsUnitTest.php +++ b/WordPress/Tests/PHP/POSIXFunctionsUnitTest.php @@ -35,6 +35,7 @@ public function getErrorList() { 22 => 1, 24 => 1, 26 => 1, + 31 => 1, ); } From 4197cea2ab798919ef41ac3304e31839b4cd5fa3 Mon Sep 17 00:00:00 2001 From: Rodrigo Primo Date: Thu, 21 Aug 2025 16:38:30 -0300 Subject: [PATCH 062/105] PHP/RestrictedPHPFunctions: add tests for namespaced names --- WordPress/Tests/PHP/RestrictedPHPFunctionsUnitTest.inc | 8 ++++++++ WordPress/Tests/PHP/RestrictedPHPFunctionsUnitTest.php | 3 ++- 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/WordPress/Tests/PHP/RestrictedPHPFunctionsUnitTest.inc b/WordPress/Tests/PHP/RestrictedPHPFunctionsUnitTest.inc index 84dbd1d7b3..09465fa6c5 100644 --- a/WordPress/Tests/PHP/RestrictedPHPFunctionsUnitTest.inc +++ b/WordPress/Tests/PHP/RestrictedPHPFunctionsUnitTest.inc @@ -3,3 +3,11 @@ add_action( 'widgets_init', create_function( '', // Error. 'return register_widget( "time_more_on_time_widget" );' ) ); + +/* + * Safeguard correct handling of all types of namespaced function calls. + */ +\create_function('', 'return;'); +MyNamespace\create_function('', 'return;'); +\MyNamespace\create_function('', 'return;'); +namespace\create_function('', 'return;'); // The sniff should start flagging this once it can resolve relative namespaces. diff --git a/WordPress/Tests/PHP/RestrictedPHPFunctionsUnitTest.php b/WordPress/Tests/PHP/RestrictedPHPFunctionsUnitTest.php index d930ba4329..5cfa75ae51 100644 --- a/WordPress/Tests/PHP/RestrictedPHPFunctionsUnitTest.php +++ b/WordPress/Tests/PHP/RestrictedPHPFunctionsUnitTest.php @@ -27,7 +27,8 @@ final class RestrictedPHPFunctionsUnitTest extends AbstractSniffUnitTest { */ public function getErrorList() { return array( - 3 => 1, + 3 => 1, + 10 => 1, ); } From f8ed24b692de6e272bc2700b9aeb35b68a73816b Mon Sep 17 00:00:00 2001 From: Rodrigo Primo Date: Thu, 21 Aug 2025 16:40:47 -0300 Subject: [PATCH 063/105] Security/SafeRedirect: add tests for namespaced names --- WordPress/Tests/Security/SafeRedirectUnitTest.inc | 8 ++++++++ WordPress/Tests/Security/SafeRedirectUnitTest.php | 1 + 2 files changed, 9 insertions(+) diff --git a/WordPress/Tests/Security/SafeRedirectUnitTest.inc b/WordPress/Tests/Security/SafeRedirectUnitTest.inc index 690fbe70f0..3d8d19c02a 100644 --- a/WordPress/Tests/Security/SafeRedirectUnitTest.inc +++ b/WordPress/Tests/Security/SafeRedirectUnitTest.inc @@ -2,3 +2,11 @@ wp_redirect( $location ); // Warning. wp_safe_redirect( $location ); // OK. + +/* + * Safeguard correct handling of all types of namespaced function calls. + */ +\wp_redirect( $location ); +MyNamespace\wp_redirect( $location ); +\MyNamespace\wp_redirect( $location ); +namespace\wp_redirect( $location ); // The sniff should start flagging this once it can resolve relative namespaces. diff --git a/WordPress/Tests/Security/SafeRedirectUnitTest.php b/WordPress/Tests/Security/SafeRedirectUnitTest.php index b62e6f86c8..358cdcfdd1 100644 --- a/WordPress/Tests/Security/SafeRedirectUnitTest.php +++ b/WordPress/Tests/Security/SafeRedirectUnitTest.php @@ -37,6 +37,7 @@ public function getErrorList() { public function getWarningList() { return array( 3 => 1, + 9 => 1, ); } } From e44ef89f068746899a123b8e000d98cef570d9a9 Mon Sep 17 00:00:00 2001 From: Rodrigo Primo Date: Thu, 21 Aug 2025 17:02:01 -0300 Subject: [PATCH 064/105] WP/DeprecatedFunctions: rename test case file Warnings and errors in this test case file are declared in a way that is different from the other test case files. It seems to me that it is better not to add a few tests safeguarding the way that namespaced names are handled to this file, instead they should be added to a new file. Thus, it is necessary to rename this one. --- ....inc => DeprecatedFunctionsUnitTest.1.inc} | 0 .../Tests/WP/DeprecatedFunctionsUnitTest.php | 150 ++++++++++-------- 2 files changed, 83 insertions(+), 67 deletions(-) rename WordPress/Tests/WP/{DeprecatedFunctionsUnitTest.inc => DeprecatedFunctionsUnitTest.1.inc} (100%) diff --git a/WordPress/Tests/WP/DeprecatedFunctionsUnitTest.inc b/WordPress/Tests/WP/DeprecatedFunctionsUnitTest.1.inc similarity index 100% rename from WordPress/Tests/WP/DeprecatedFunctionsUnitTest.inc rename to WordPress/Tests/WP/DeprecatedFunctionsUnitTest.1.inc diff --git a/WordPress/Tests/WP/DeprecatedFunctionsUnitTest.php b/WordPress/Tests/WP/DeprecatedFunctionsUnitTest.php index ffecae7e33..25723cbd41 100644 --- a/WordPress/Tests/WP/DeprecatedFunctionsUnitTest.php +++ b/WordPress/Tests/WP/DeprecatedFunctionsUnitTest.php @@ -24,85 +24,101 @@ final class DeprecatedFunctionsUnitTest extends AbstractSniffUnitTest { /** * Returns the lines where errors should occur. * + * @param string $testFile The test file to check for errors. + * * @return array Key is the line number, value is the number of expected errors. */ - public function getErrorList() { - $start_line = 8; - $end_line = 420; - $errors = array_fill( $start_line, ( ( $end_line - $start_line ) + 1 ), 1 ); + public function getErrorList( $testFile = '' ) { + switch ( $testFile ) { + case 'DeprecatedFunctionsUnitTest.1.inc': + $start_line = 8; + $end_line = 420; + $errors = array_fill( $start_line, ( ( $end_line - $start_line ) + 1 ), 1 ); + + // Unset the lines related to version comments. + unset( + $errors[10], + $errors[12], + $errors[14], + $errors[16], + $errors[29], + $errors[55], + $errors[57], + $errors[59], + $errors[73], + $errors[76], + $errors[80], + $errors[102], // Undeprecated function. + $errors[118], + $errors[125], + $errors[162], + $errors[175], + $errors[179], + $errors[211], + $errors[234], + $errors[252], + $errors[256], + $errors[263], + $errors[275], + $errors[282], + $errors[286], + $errors[291], + $errors[296], + $errors[304], + $errors[311], + $errors[319], + $errors[323], + $errors[330], + $errors[332], + $errors[337], + $errors[340], + $errors[344], + $errors[346], + $errors[353], + $errors[357], + $errors[359], + $errors[361], + $errors[363], + $errors[369], + $errors[371], + $errors[373], + $errors[383], + $errors[386], + $errors[410] + ); - // Unset the lines related to version comments. - unset( - $errors[10], - $errors[12], - $errors[14], - $errors[16], - $errors[29], - $errors[55], - $errors[57], - $errors[59], - $errors[73], - $errors[76], - $errors[80], - $errors[102], // Undeprecated function. - $errors[118], - $errors[125], - $errors[162], - $errors[175], - $errors[179], - $errors[211], - $errors[234], - $errors[252], - $errors[256], - $errors[263], - $errors[275], - $errors[282], - $errors[286], - $errors[291], - $errors[296], - $errors[304], - $errors[311], - $errors[319], - $errors[323], - $errors[330], - $errors[332], - $errors[337], - $errors[340], - $errors[344], - $errors[346], - $errors[353], - $errors[357], - $errors[359], - $errors[361], - $errors[363], - $errors[369], - $errors[371], - $errors[373], - $errors[383], - $errors[386], - $errors[410] - ); + return $errors; - return $errors; + default: + return array(); + } } /** * Returns the lines where warnings should occur. * + * @param string $testFile The test file to check for warnings. + * * @return array Key is the line number, value is the number of expected warnings. */ - public function getWarningList() { - $start_line = 426; - $end_line = 443; - $warnings = array_fill( $start_line, ( ( $end_line - $start_line ) + 1 ), 1 ); + public function getWarningList( $testFile = '' ) { + switch ( $testFile ) { + case 'DeprecatedFunctionsUnitTest.1.inc': + $start_line = 426; + $end_line = 443; + $warnings = array_fill( $start_line, ( ( $end_line - $start_line ) + 1 ), 1 ); + + // Unset the lines related to version comments. + unset( + $warnings[429], + $warnings[432], + $warnings[442] + ); - // Unset the lines related to version comments. - unset( - $warnings[429], - $warnings[432], - $warnings[442] - ); + return $warnings; - return $warnings; + default: + return array(); + } } } From 97b2e96886bedb7787a668cca1b343b583c725b5 Mon Sep 17 00:00:00 2001 From: Rodrigo Primo Date: Thu, 21 Aug 2025 17:04:30 -0300 Subject: [PATCH 065/105] WP/DeprecatedFunctions: add tests for namespaced names --- WordPress/Tests/WP/DeprecatedFunctionsUnitTest.2.inc | 9 +++++++++ WordPress/Tests/WP/DeprecatedFunctionsUnitTest.php | 5 +++++ 2 files changed, 14 insertions(+) create mode 100644 WordPress/Tests/WP/DeprecatedFunctionsUnitTest.2.inc diff --git a/WordPress/Tests/WP/DeprecatedFunctionsUnitTest.2.inc b/WordPress/Tests/WP/DeprecatedFunctionsUnitTest.2.inc new file mode 100644 index 0000000000..6c2a7bb8e1 --- /dev/null +++ b/WordPress/Tests/WP/DeprecatedFunctionsUnitTest.2.inc @@ -0,0 +1,9 @@ + 1, + ); + default: return array(); } From b4fa525e4cfc74e438bd3307076e29de763d35e6 Mon Sep 17 00:00:00 2001 From: jrfnl Date: Sat, 20 Sep 2025 02:12:07 +0200 Subject: [PATCH 066/105] GH Actions: "pin" all action runners Recently there has been more and more focus on securing GH Actions workflows - in part due to some incidents. The problem with "unpinned" action runners is as follows: * Tags are mutable, which means that a tag could point to a safe commit today, but to a malicious commit tomorrow. Note that GitHub is currently beta-testing a new "immutable releases" feature (= tags and release artifacts can not be changed anymore once the release is published), but whether that has much effect depends on the ecosystem of the packages using the feature. Aside from that, it will likely take years before all projects adopt _immutable releases_. * Action runners often don't even point to a tag, but to a branch, making the used action runner a moving target. _Note: this type of "floating major" for action runners used to be promoted as good practice when the ecosystem was "young". Insights have since changed._ While it is convenient to use "floating majors" of action runners, as this means you only need to update the workflows on a new major release of the action runner, the price is higher risk of malicious code being executed in workflows. Dependabot, by now, can automatically submit PRs to update pinned action runners too, as long as the commit-hash pinned runner is followed by a comment listing the released version the commit is pointing to. So, what with Dependabot being capable of updating workflows with pinned action runners, I believe it is time to update the workflows to the _current_ best practice of using commit-hash pinned action runners. The downside of this change is that there will be more frequent Dependabot PRs. If this would become a burden/irritating, the following mitigations can be implemented: 1. Updating the Dependabot config to group updates instead of sending individual PRs per action runner. 2. A workflow to automatically merge Dependabot PRs as long as CI passes. Ref: https://docs.github.com/en/actions/reference/security/secure-use#using-third-party-actions --- .github/workflows/basic-qa.yml | 38 ++++++++++++++--------------- .github/workflows/manage-labels.yml | 6 ++--- .github/workflows/quicktest.yml | 8 +++--- .github/workflows/unit-tests.yml | 8 +++--- 4 files changed, 30 insertions(+), 30 deletions(-) diff --git a/.github/workflows/basic-qa.yml b/.github/workflows/basic-qa.yml index 5d1405ed63..5efcedda88 100644 --- a/.github/workflows/basic-qa.yml +++ b/.github/workflows/basic-qa.yml @@ -26,10 +26,10 @@ jobs: steps: - name: Checkout repository - uses: actions/checkout@v5 + uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 - name: Setup PHP - uses: shivammathur/setup-php@v2 + uses: shivammathur/setup-php@bf6b4fbd49ca58e4608c9c89fba0b8d90bd2a39f # 2.35.5 with: php-version: 'latest' coverage: none @@ -48,7 +48,7 @@ jobs: phpcsstandards/phpcsextra:"${{ env.EXTRA_DEV }}" - name: Install Composer dependencies - uses: ramsey/composer-install@v3 + uses: ramsey/composer-install@3cf229dc2919194e9e36783941438d17239e8520 # 3.1.1 with: # Bust the cache at least once a month - output format: YYYY-MM. custom-cache-suffix: $(date -u "+%Y-%m") @@ -64,38 +64,38 @@ jobs: # Validate the Ruleset XML files. # @link http://xmlsoft.org/xmllint.html - name: Validate the WordPress rulesets - uses: phpcsstandards/xmllint-validate@v1 + uses: phpcsstandards/xmllint-validate@0fd9c4a9046055f621fca4bbdccb8eab1fd59fdc # v1.0.1 with: pattern: "./*/ruleset.xml" xsd-file: "vendor/squizlabs/php_codesniffer/phpcs.xsd" - name: Validate the sample ruleset - uses: phpcsstandards/xmllint-validate@v1 + uses: phpcsstandards/xmllint-validate@0fd9c4a9046055f621fca4bbdccb8eab1fd59fdc # v1.0.1 with: pattern: "phpcs.xml.dist.sample" xsd-file: "vendor/squizlabs/php_codesniffer/phpcs.xsd" # Validate the Documentation XML files. - name: Validate documentation against schema - uses: phpcsstandards/xmllint-validate@v1 + uses: phpcsstandards/xmllint-validate@0fd9c4a9046055f621fca4bbdccb8eab1fd59fdc # v1.0.1 with: pattern: "./WordPress/Docs/*/*Standard.xml" xsd-file: "vendor/phpcsstandards/phpcsdevtools/DocsXsd/phpcsdocs.xsd" - name: Validate Project PHPCS ruleset against schema - uses: phpcsstandards/xmllint-validate@v1 + uses: phpcsstandards/xmllint-validate@0fd9c4a9046055f621fca4bbdccb8eab1fd59fdc # v1.0.1 with: pattern: ".phpcs.xml.dist" xsd-file: "vendor/squizlabs/php_codesniffer/phpcs.xsd" - name: "Validate PHPUnit config for use with PHPUnit 8" - uses: phpcsstandards/xmllint-validate@v1 + uses: phpcsstandards/xmllint-validate@0fd9c4a9046055f621fca4bbdccb8eab1fd59fdc # v1.0.1 with: pattern: "phpunit.xml.dist" xsd-file: "vendor/phpunit/phpunit/schema/8.5.xsd" - name: "Validate PHPUnit config for use with PHPUnit 9" - uses: phpcsstandards/xmllint-validate@v1 + uses: phpcsstandards/xmllint-validate@0fd9c4a9046055f621fca4bbdccb8eab1fd59fdc # v1.0.1 with: pattern: "phpunit.xml.dist" xsd-file: "vendor/phpunit/phpunit/schema/9.2.xsd" @@ -115,7 +115,7 @@ jobs: steps: - name: Checkout code - uses: actions/checkout@v5 + uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 # Updating the lists can fail intermittently, typically after Microsoft has released a new package. # This should not be blocking for this job, so ignore any errors from this step. @@ -129,7 +129,7 @@ jobs: # Show XML violations inline in the file diff. - name: Enable showing XML issues inline - uses: korelstar/xmllint-problem-matcher@v1 + uses: korelstar/xmllint-problem-matcher@1bd292d642ddf3d369d02aaa8b262834d61198c0 # v1.2.0 - name: Check the code-style consistency of the xml files run: | @@ -153,10 +153,10 @@ jobs: steps: - name: Checkout repository - uses: actions/checkout@v5 + uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 - name: Set up PHP - uses: shivammathur/setup-php@v2 + uses: shivammathur/setup-php@bf6b4fbd49ca58e4608c9c89fba0b8d90bd2a39f # 2.35.5 with: php-version: ${{ matrix.php }} # Allow for PHP deprecation notices. @@ -176,7 +176,7 @@ jobs: run: composer config --unset lock - name: Install Composer dependencies - uses: ramsey/composer-install@v3 + uses: ramsey/composer-install@3cf229dc2919194e9e36783941438d17239e8520 # 3.1.1 with: composer-options: --no-dev # Bust the cache at least once a month - output format: YYYY-MM. @@ -234,10 +234,10 @@ jobs: steps: - name: Checkout code - uses: actions/checkout@v5 + uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 - name: Install PHP - uses: shivammathur/setup-php@v2 + uses: shivammathur/setup-php@bf6b4fbd49ca58e4608c9c89fba0b8d90bd2a39f # 2.35.5 with: php-version: 'latest' coverage: none @@ -247,7 +247,7 @@ jobs: # Dependencies need to be installed to make sure the PHPCS and PHPUnit classes are recognized. # @link https://github.com/marketplace/actions/install-php-dependencies-with-composer - name: Install Composer dependencies - uses: "ramsey/composer-install@v3" + uses: "ramsey/composer-install@3cf229dc2919194e9e36783941438d17239e8520" # 3.1.1 with: # Bust the cache at least once a month - output format: YYYY-MM. custom-cache-suffix: $(date -u "+%Y-%m") @@ -262,7 +262,7 @@ jobs: steps: - name: "Checkout" - uses: "actions/checkout@v5" + uses: "actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8" # v5.0.0 - name: "Search for misspellings" - uses: "crate-ci/typos@v1" + uses: "crate-ci/typos@85f62a8a84f939ae994ab3763f01a0296d61a7ee" # v1.36.2 diff --git a/.github/workflows/manage-labels.yml b/.github/workflows/manage-labels.yml index 56de1c5ac0..d6e989b20b 100644 --- a/.github/workflows/manage-labels.yml +++ b/.github/workflows/manage-labels.yml @@ -17,7 +17,7 @@ jobs: name: Clean up labels on PR merge steps: - - uses: mondeja/remove-labels-gh-action@v2 + - uses: mondeja/remove-labels-gh-action@b7118e4ba5dca74acf1059b3cb7660378ff9ab1a # v2.0.0 with: token: ${{ secrets.GITHUB_TOKEN }} labels: | @@ -31,7 +31,7 @@ jobs: name: Clean up labels on PR close steps: - - uses: mondeja/remove-labels-gh-action@v2 + - uses: mondeja/remove-labels-gh-action@b7118e4ba5dca74acf1059b3cb7660378ff9ab1a # v2.0.0 with: token: ${{ secrets.GITHUB_TOKEN }} labels: | @@ -46,7 +46,7 @@ jobs: name: Clean up labels on issue close steps: - - uses: mondeja/remove-labels-gh-action@v2 + - uses: mondeja/remove-labels-gh-action@b7118e4ba5dca74acf1059b3cb7660378ff9ab1a # v2.0.0 with: token: ${{ secrets.GITHUB_TOKEN }} labels: | diff --git a/.github/workflows/quicktest.yml b/.github/workflows/quicktest.yml index e777483c59..427d4404a1 100644 --- a/.github/workflows/quicktest.yml +++ b/.github/workflows/quicktest.yml @@ -30,10 +30,10 @@ jobs: steps: - name: Checkout repository - uses: actions/checkout@v5 + uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 - name: Set up PHP - uses: shivammathur/setup-php@v2 + uses: shivammathur/setup-php@bf6b4fbd49ca58e4608c9c89fba0b8d90bd2a39f # 2.35.5 with: php-version: ${{ matrix.php }} # With stable PHPCS dependencies, allow for PHP deprecation notices. @@ -46,7 +46,7 @@ jobs: run: composer config --unset lock - name: Install Composer dependencies - uses: ramsey/composer-install@v3 + uses: ramsey/composer-install@3cf229dc2919194e9e36783941438d17239e8520 # 3.1.1 with: # Bust the cache at least once a month - output format: YYYY-MM. custom-cache-suffix: $(date -u "+%Y-%m") @@ -73,7 +73,7 @@ jobs: - name: Send coverage report to Codecov if: ${{ success() && github.repository_owner == 'WordPress' && github.ref_name == 'develop' }} - uses: codecov/codecov-action@v5 + uses: codecov/codecov-action@5a1091511ad55cbe89839c7260b706298ca349f7 # v5.5.1 with: files: ./build/logs/clover.xml fail_ci_if_error: true diff --git a/.github/workflows/unit-tests.yml b/.github/workflows/unit-tests.yml index 3725c8c231..961b8173e6 100644 --- a/.github/workflows/unit-tests.yml +++ b/.github/workflows/unit-tests.yml @@ -74,7 +74,7 @@ jobs: steps: - name: Checkout repository - uses: actions/checkout@v5 + uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 # With stable PHPCS dependencies, allow for PHP deprecation notices. # Unit tests don't need to fail on those for stable releases where those issues won't get fixed anymore. @@ -88,7 +88,7 @@ jobs: fi - name: Set up PHP - uses: shivammathur/setup-php@v2 + uses: shivammathur/setup-php@bf6b4fbd49ca58e4608c9c89fba0b8d90bd2a39f # 2.35.5 with: php-version: ${{ matrix.php }} ini-values: ${{ steps.set_ini.outputs.PHP_INI }} @@ -108,7 +108,7 @@ jobs: run: composer config --unset lock - name: Install Composer dependencies - uses: ramsey/composer-install@v3 + uses: ramsey/composer-install@3cf229dc2919194e9e36783941438d17239e8520 # 3.1.1 with: # Bust the cache at least once a month - output format: YYYY-MM. custom-cache-suffix: $(date -u "+%Y-%m") @@ -135,7 +135,7 @@ jobs: - name: Send coverage report to Codecov if: ${{ success() && matrix.coverage == true && github.repository_owner == 'WordPress' }} - uses: codecov/codecov-action@v5 + uses: codecov/codecov-action@5a1091511ad55cbe89839c7260b706298ca349f7 # v5.5.1 with: files: ./build/logs/clover.xml fail_ci_if_error: true From d5a0adc9efe004560e926684661294dff2ca4354 Mon Sep 17 00:00:00 2001 From: jrfnl Date: Sat, 20 Sep 2025 02:13:05 +0200 Subject: [PATCH 067/105] Dependabot: update config This commit makes the following change to the Dependabot config: * It introduces a "group". By default Dependabot raises individual PRs for each update. Now, it will group updates to new minor or patch release for all action runners into a single PR. Updates to new major releases of action runners will still be raised as individual PRs. Refs: * https://docs.github.com/en/code-security/dependabot/dependabot-version-updates/optimizing-pr-creation-version-updates * https://docs.github.com/en/code-security/dependabot/working-with-dependabot/dependabot-options-reference --- .github/dependabot.yml | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/.github/dependabot.yml b/.github/dependabot.yml index 97c58b7822..2b9891a7f0 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -15,3 +15,9 @@ updates: prefix: "GH Actions:" labels: - "Type: Chores/Cleanup" + groups: + action-runners: + applies-to: version-updates + update-types: + - "minor" + - "patch" From 50492d6afce9750c3d3a7fbe89cb116efeb3d07a Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 29 Sep 2025 18:47:27 +0000 Subject: [PATCH 068/105] GH Actions: Bump crate-ci/typos in the action-runners group Bumps the action-runners group with 1 update: [crate-ci/typos](https://github.com/crate-ci/typos). Updates `crate-ci/typos` from 1.36.2 to 1.36.3 - [Release notes](https://github.com/crate-ci/typos/releases) - [Changelog](https://github.com/crate-ci/typos/blob/master/CHANGELOG.md) - [Commits](https://github.com/crate-ci/typos/compare/85f62a8a84f939ae994ab3763f01a0296d61a7ee...0c17dabcee8b8f1957fa917d17393a23e02e1583) --- updated-dependencies: - dependency-name: crate-ci/typos dependency-version: 1.36.3 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: action-runners ... Signed-off-by: dependabot[bot] --- .github/workflows/basic-qa.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/basic-qa.yml b/.github/workflows/basic-qa.yml index 5efcedda88..765ce8d586 100644 --- a/.github/workflows/basic-qa.yml +++ b/.github/workflows/basic-qa.yml @@ -265,4 +265,4 @@ jobs: uses: "actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8" # v5.0.0 - name: "Search for misspellings" - uses: "crate-ci/typos@85f62a8a84f939ae994ab3763f01a0296d61a7ee" # v1.36.2 + uses: "crate-ci/typos@0c17dabcee8b8f1957fa917d17393a23e02e1583" # v1.36.3 From 9f0c6a82c2242735b7bc5b3489bdd90107df65b2 Mon Sep 17 00:00:00 2001 From: jrfnl Date: Sat, 20 Sep 2025 02:15:03 +0200 Subject: [PATCH 069/105] GH Actions: do not persist credentials > By default, using `actions/checkout` causes a credential to be persisted in the checked-out repo's `.git/config`, so that subsequent `git` operations can be authenticated. > > Subsequent steps may accidentally publicly persist `.git/config`, e.g. by including it in a publicly accessible artifact via `actions/upload-artifact`. > > However, even without this, persisting the credential in the `.git/config` is non-ideal unless actually needed. > > **Remediation** > > Unless needed for `git` operations, `actions/checkout` should be used with `persist-credentials: false`. > > If the persisted credential is needed, it should be made explicit with `persist-credentials: true`. This has now been addressed in all workflows. Refs: * https://unit42.paloaltonetworks.com/github-repo-artifacts-leak-tokens/ * https://docs.zizmor.sh/audits/#artipacked --- .github/workflows/basic-qa.yml | 10 ++++++++++ .github/workflows/quicktest.yml | 2 ++ .github/workflows/unit-tests.yml | 2 ++ 3 files changed, 14 insertions(+) diff --git a/.github/workflows/basic-qa.yml b/.github/workflows/basic-qa.yml index 765ce8d586..f1219898fc 100644 --- a/.github/workflows/basic-qa.yml +++ b/.github/workflows/basic-qa.yml @@ -27,6 +27,8 @@ jobs: steps: - name: Checkout repository uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 + with: + persist-credentials: false - name: Setup PHP uses: shivammathur/setup-php@bf6b4fbd49ca58e4608c9c89fba0b8d90bd2a39f # 2.35.5 @@ -116,6 +118,8 @@ jobs: steps: - name: Checkout code uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 + with: + persist-credentials: false # Updating the lists can fail intermittently, typically after Microsoft has released a new package. # This should not be blocking for this job, so ignore any errors from this step. @@ -154,6 +158,8 @@ jobs: steps: - name: Checkout repository uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 + with: + persist-credentials: false - name: Set up PHP uses: shivammathur/setup-php@bf6b4fbd49ca58e4608c9c89fba0b8d90bd2a39f # 2.35.5 @@ -235,6 +241,8 @@ jobs: steps: - name: Checkout code uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 + with: + persist-credentials: false - name: Install PHP uses: shivammathur/setup-php@bf6b4fbd49ca58e4608c9c89fba0b8d90bd2a39f # 2.35.5 @@ -263,6 +271,8 @@ jobs: steps: - name: "Checkout" uses: "actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8" # v5.0.0 + with: + persist-credentials: false - name: "Search for misspellings" uses: "crate-ci/typos@0c17dabcee8b8f1957fa917d17393a23e02e1583" # v1.36.3 diff --git a/.github/workflows/quicktest.yml b/.github/workflows/quicktest.yml index 427d4404a1..5cf6b0fa03 100644 --- a/.github/workflows/quicktest.yml +++ b/.github/workflows/quicktest.yml @@ -31,6 +31,8 @@ jobs: steps: - name: Checkout repository uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 + with: + persist-credentials: false - name: Set up PHP uses: shivammathur/setup-php@bf6b4fbd49ca58e4608c9c89fba0b8d90bd2a39f # 2.35.5 diff --git a/.github/workflows/unit-tests.yml b/.github/workflows/unit-tests.yml index 961b8173e6..cda909983b 100644 --- a/.github/workflows/unit-tests.yml +++ b/.github/workflows/unit-tests.yml @@ -75,6 +75,8 @@ jobs: steps: - name: Checkout repository uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 + with: + persist-credentials: false # With stable PHPCS dependencies, allow for PHP deprecation notices. # Unit tests don't need to fail on those for stable releases where those issues won't get fixed anymore. From 9d7da9120f2c962b6bf0f72b4c4cbdc0e9fbc020 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 6 Oct 2025 09:09:41 +0000 Subject: [PATCH 070/105] GH Actions: Bump crate-ci/typos in the action-runners group Bumps the action-runners group with 1 update: [crate-ci/typos](https://github.com/crate-ci/typos). Updates `crate-ci/typos` from 1.36.3 to 1.37.2 - [Release notes](https://github.com/crate-ci/typos/releases) - [Changelog](https://github.com/crate-ci/typos/blob/master/CHANGELOG.md) - [Commits](https://github.com/crate-ci/typos/compare/0c17dabcee8b8f1957fa917d17393a23e02e1583...7436548694def3314aacd93ed06c721b1f91ea04) --- updated-dependencies: - dependency-name: crate-ci/typos dependency-version: 1.37.2 dependency-type: direct:production update-type: version-update:semver-minor dependency-group: action-runners ... Signed-off-by: dependabot[bot] --- .github/workflows/basic-qa.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/basic-qa.yml b/.github/workflows/basic-qa.yml index f1219898fc..bf3a7c5c00 100644 --- a/.github/workflows/basic-qa.yml +++ b/.github/workflows/basic-qa.yml @@ -275,4 +275,4 @@ jobs: persist-credentials: false - name: "Search for misspellings" - uses: "crate-ci/typos@0c17dabcee8b8f1957fa917d17393a23e02e1583" # v1.36.3 + uses: "crate-ci/typos@7436548694def3314aacd93ed06c721b1f91ea04" # v1.37.2 From 526cd3785b7322f1c3ad152bdc08212071db060f Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 13 Oct 2025 09:27:02 +0000 Subject: [PATCH 071/105] GH Actions: Bump crate-ci/typos in the action-runners group Bumps the action-runners group with 1 update: [crate-ci/typos](https://github.com/crate-ci/typos). Updates `crate-ci/typos` from 1.37.2 to 1.38.1 - [Release notes](https://github.com/crate-ci/typos/releases) - [Changelog](https://github.com/crate-ci/typos/blob/master/CHANGELOG.md) - [Commits](https://github.com/crate-ci/typos/compare/7436548694def3314aacd93ed06c721b1f91ea04...80c8a4945eec0f6d464eaf9e65ed98ef085283d1) --- updated-dependencies: - dependency-name: crate-ci/typos dependency-version: 1.38.1 dependency-type: direct:production update-type: version-update:semver-minor dependency-group: action-runners ... Signed-off-by: dependabot[bot] --- .github/workflows/basic-qa.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/basic-qa.yml b/.github/workflows/basic-qa.yml index bf3a7c5c00..e00b9e2d60 100644 --- a/.github/workflows/basic-qa.yml +++ b/.github/workflows/basic-qa.yml @@ -275,4 +275,4 @@ jobs: persist-credentials: false - name: "Search for misspellings" - uses: "crate-ci/typos@7436548694def3314aacd93ed06c721b1f91ea04" # v1.37.2 + uses: "crate-ci/typos@80c8a4945eec0f6d464eaf9e65ed98ef085283d1" # v1.38.1 From e331fe6f08a7fdd45a22bb41cb033e49b51bd8f6 Mon Sep 17 00:00:00 2001 From: Rodrigo Primo Date: Tue, 5 Aug 2025 16:27:08 -0300 Subject: [PATCH 072/105] WP/GetMetaSingle: simplify code using two class constants Now that support for PHP < 7.2 has been dropped in PR 2614, we can simplify the sniff code by defining the two different function signature formats as class constants. This was not possible before as PHP < 5.6 did not support defining class constants as arrays. --- WordPress/Sniffs/WP/GetMetaSingleSniff.php | 134 ++++++++------------- 1 file changed, 50 insertions(+), 84 deletions(-) diff --git a/WordPress/Sniffs/WP/GetMetaSingleSniff.php b/WordPress/Sniffs/WP/GetMetaSingleSniff.php index 243f272507..512d992ca2 100644 --- a/WordPress/Sniffs/WP/GetMetaSingleSniff.php +++ b/WordPress/Sniffs/WP/GetMetaSingleSniff.php @@ -33,6 +33,48 @@ final class GetMetaSingleSniff extends AbstractFunctionParameterSniff { */ const METRIC_NAME = 'get_*meta() function called with $single parameter'; + /** + * Relevant signature structure for specific meta functions. + * + * These functions use 'key' as the parameter name at position 2 and + * 'single' as the parameter name at position 3. + * + * @since 3.2.0 + * + * @var array> + */ + const SPECIFIC_META_FUNCTIONS_FORMAT = array( + 'condition' => array( + 'param_name' => 'key', + 'position' => 2, + ), + 'recommended' => array( + 'param_name' => 'single', + 'position' => 3, + ), + ); + + /** + * Relevant signature structure for generic meta functions. + * + * These functions use 'meta_key' as the parameter name at position 3 and + * 'single' as the parameter name at position 4. + * + * @since 3.2.0 + * + * @var array> + */ + const GENERIC_META_FUNCTIONS_FORMAT = array( + 'condition' => array( + 'param_name' => 'meta_key', + 'position' => 3, + ), + 'recommended' => array( + 'param_name' => 'single', + 'position' => 4, + ), + ); + /** * The group name for this group of functions. * @@ -45,10 +87,6 @@ final class GetMetaSingleSniff extends AbstractFunctionParameterSniff { /** * List of functions this sniff should examine. * - * {@internal Once support for PHP < 5.6 is dropped, it is possible to create two class constants - * representing the two different signatures of get meta functions to remove the duplication - * of the name and position of the parameters.} - * * @link https://developer.wordpress.org/reference/functions/get_comment_meta/ * @link https://developer.wordpress.org/reference/functions/get_metadata/ * @link https://developer.wordpress.org/reference/functions/get_metadata_default/ @@ -66,86 +104,14 @@ final class GetMetaSingleSniff extends AbstractFunctionParameterSniff { * the relevant parameters. */ protected $target_functions = array( - 'get_comment_meta' => array( - 'condition' => array( - 'param_name' => 'key', - 'position' => 2, - ), - 'recommended' => array( - 'param_name' => 'single', - 'position' => 3, - ), - ), - 'get_metadata' => array( - 'condition' => array( - 'param_name' => 'meta_key', - 'position' => 3, - ), - 'recommended' => array( - 'param_name' => 'single', - 'position' => 4, - ), - ), - 'get_metadata_default' => array( - 'condition' => array( - 'param_name' => 'meta_key', - 'position' => 3, - ), - 'recommended' => array( - 'param_name' => 'single', - 'position' => 4, - ), - ), - 'get_metadata_raw' => array( - 'condition' => array( - 'param_name' => 'meta_key', - 'position' => 3, - ), - 'recommended' => array( - 'param_name' => 'single', - 'position' => 4, - ), - ), - 'get_post_meta' => array( - 'condition' => array( - 'param_name' => 'key', - 'position' => 2, - ), - 'recommended' => array( - 'param_name' => 'single', - 'position' => 3, - ), - ), - 'get_site_meta' => array( - 'condition' => array( - 'param_name' => 'key', - 'position' => 2, - ), - 'recommended' => array( - 'param_name' => 'single', - 'position' => 3, - ), - ), - 'get_term_meta' => array( - 'condition' => array( - 'param_name' => 'key', - 'position' => 2, - ), - 'recommended' => array( - 'param_name' => 'single', - 'position' => 3, - ), - ), - 'get_user_meta' => array( - 'condition' => array( - 'param_name' => 'key', - 'position' => 2, - ), - 'recommended' => array( - 'param_name' => 'single', - 'position' => 3, - ), - ), + 'get_comment_meta' => self::SPECIFIC_META_FUNCTIONS_FORMAT, + 'get_metadata' => self::GENERIC_META_FUNCTIONS_FORMAT, + 'get_metadata_default' => self::GENERIC_META_FUNCTIONS_FORMAT, + 'get_metadata_raw' => self::GENERIC_META_FUNCTIONS_FORMAT, + 'get_post_meta' => self::SPECIFIC_META_FUNCTIONS_FORMAT, + 'get_site_meta' => self::SPECIFIC_META_FUNCTIONS_FORMAT, + 'get_term_meta' => self::SPECIFIC_META_FUNCTIONS_FORMAT, + 'get_user_meta' => self::SPECIFIC_META_FUNCTIONS_FORMAT, ); /** From a09975d17c87902b436ffd3db9a15ae156d5ee35 Mon Sep 17 00:00:00 2001 From: Rodrigo Primo Date: Fri, 17 Oct 2025 08:28:27 -0300 Subject: [PATCH 073/105] Fix version number in since tags --- WordPress/Sniffs/WP/GetMetaSingleSniff.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/WordPress/Sniffs/WP/GetMetaSingleSniff.php b/WordPress/Sniffs/WP/GetMetaSingleSniff.php index 512d992ca2..8a8ff32122 100644 --- a/WordPress/Sniffs/WP/GetMetaSingleSniff.php +++ b/WordPress/Sniffs/WP/GetMetaSingleSniff.php @@ -39,7 +39,7 @@ final class GetMetaSingleSniff extends AbstractFunctionParameterSniff { * These functions use 'key' as the parameter name at position 2 and * 'single' as the parameter name at position 3. * - * @since 3.2.0 + * @since 3.3.0 * * @var array> */ @@ -60,7 +60,7 @@ final class GetMetaSingleSniff extends AbstractFunctionParameterSniff { * These functions use 'meta_key' as the parameter name at position 3 and * 'single' as the parameter name at position 4. * - * @since 3.2.0 + * @since 3.3.0 * * @var array> */ From e53d4f914969987cfa993de482dcddf36ef08afb Mon Sep 17 00:00:00 2001 From: Rodrigo Primo Date: Mon, 20 Oct 2025 09:16:06 -0300 Subject: [PATCH 074/105] Change the order of the two class constants --- WordPress/Sniffs/WP/GetMetaSingleSniff.php | 28 +++++++++++----------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/WordPress/Sniffs/WP/GetMetaSingleSniff.php b/WordPress/Sniffs/WP/GetMetaSingleSniff.php index 8a8ff32122..af9f6c9267 100644 --- a/WordPress/Sniffs/WP/GetMetaSingleSniff.php +++ b/WordPress/Sniffs/WP/GetMetaSingleSniff.php @@ -34,44 +34,44 @@ final class GetMetaSingleSniff extends AbstractFunctionParameterSniff { const METRIC_NAME = 'get_*meta() function called with $single parameter'; /** - * Relevant signature structure for specific meta functions. + * Relevant signature structure for generic meta functions. * - * These functions use 'key' as the parameter name at position 2 and - * 'single' as the parameter name at position 3. + * These functions use 'meta_key' as the parameter name at position 3 and + * 'single' as the parameter name at position 4. * * @since 3.3.0 * * @var array> */ - const SPECIFIC_META_FUNCTIONS_FORMAT = array( + const GENERIC_META_FUNCTIONS_FORMAT = array( 'condition' => array( - 'param_name' => 'key', - 'position' => 2, + 'param_name' => 'meta_key', + 'position' => 3, ), 'recommended' => array( 'param_name' => 'single', - 'position' => 3, + 'position' => 4, ), ); /** - * Relevant signature structure for generic meta functions. + * Relevant signature structure for specific meta functions. * - * These functions use 'meta_key' as the parameter name at position 3 and - * 'single' as the parameter name at position 4. + * These functions use 'key' as the parameter name at position 2 and + * 'single' as the parameter name at position 3. * * @since 3.3.0 * * @var array> */ - const GENERIC_META_FUNCTIONS_FORMAT = array( + const SPECIFIC_META_FUNCTIONS_FORMAT = array( 'condition' => array( - 'param_name' => 'meta_key', - 'position' => 3, + 'param_name' => 'key', + 'position' => 2, ), 'recommended' => array( 'param_name' => 'single', - 'position' => 4, + 'position' => 3, ), ); From e3672da484eb3c90a2abaed736f7cc014c37e263 Mon Sep 17 00:00:00 2001 From: Rodrigo Primo Date: Mon, 20 Oct 2025 10:57:22 -0300 Subject: [PATCH 075/105] Add `private` visibility to the two new constants --- WordPress/Sniffs/WP/GetMetaSingleSniff.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/WordPress/Sniffs/WP/GetMetaSingleSniff.php b/WordPress/Sniffs/WP/GetMetaSingleSniff.php index af9f6c9267..76b576d109 100644 --- a/WordPress/Sniffs/WP/GetMetaSingleSniff.php +++ b/WordPress/Sniffs/WP/GetMetaSingleSniff.php @@ -43,7 +43,7 @@ final class GetMetaSingleSniff extends AbstractFunctionParameterSniff { * * @var array> */ - const GENERIC_META_FUNCTIONS_FORMAT = array( + private const GENERIC_META_FUNCTIONS_FORMAT = array( 'condition' => array( 'param_name' => 'meta_key', 'position' => 3, @@ -64,7 +64,7 @@ final class GetMetaSingleSniff extends AbstractFunctionParameterSniff { * * @var array> */ - const SPECIFIC_META_FUNCTIONS_FORMAT = array( + private const SPECIFIC_META_FUNCTIONS_FORMAT = array( 'condition' => array( 'param_name' => 'key', 'position' => 2, From 20b2c5a58609312f4b815a8d0d9610ecfa308467 Mon Sep 17 00:00:00 2001 From: Rodrigo Primo Date: Tue, 17 Sep 2024 10:41:55 -0700 Subject: [PATCH 076/105] Documentation: fix broken WordPress VIP links in sniff docblocks Update old https://vip.wordpress.com/documentation URLs to new https://docs.wpvip.com URLs in multiple sniff docblocks. The old links are redirecting to a generic page that doesn't provide any useful information about the related sniff. I was not able to find the corresponding new link for `EnqueuedResourcesSniff`, so I opted to remove the old link. --- WordPress/Sniffs/DB/DirectDatabaseQuerySniff.php | 2 +- WordPress/Sniffs/DB/SlowDBQuerySniff.php | 2 +- WordPress/Sniffs/DateTime/RestrictedFunctionsSniff.php | 2 +- WordPress/Sniffs/Security/PluginMenuSlugSniff.php | 2 +- WordPress/Sniffs/WP/CronIntervalSniff.php | 2 +- WordPress/Sniffs/WP/EnqueuedResourcesSniff.php | 2 -- WordPress/Sniffs/WP/PostsPerPageSniff.php | 2 +- 7 files changed, 6 insertions(+), 8 deletions(-) diff --git a/WordPress/Sniffs/DB/DirectDatabaseQuerySniff.php b/WordPress/Sniffs/DB/DirectDatabaseQuerySniff.php index a600e6ae83..1d05da486d 100644 --- a/WordPress/Sniffs/DB/DirectDatabaseQuerySniff.php +++ b/WordPress/Sniffs/DB/DirectDatabaseQuerySniff.php @@ -19,7 +19,7 @@ /** * Flag Database direct queries. * - * @link https://vip.wordpress.com/documentation/vip-go/code-review-blockers-warnings-notices/#direct-database-queries + * @link https://docs.wpvip.com/php_codesniffer/warnings/#h-direct-database-queries * * @since 0.3.0 * @since 0.6.0 Removed the add_unique_message() function as it is no longer needed. diff --git a/WordPress/Sniffs/DB/SlowDBQuerySniff.php b/WordPress/Sniffs/DB/SlowDBQuerySniff.php index 5cbd99ac61..061a3e7de8 100644 --- a/WordPress/Sniffs/DB/SlowDBQuerySniff.php +++ b/WordPress/Sniffs/DB/SlowDBQuerySniff.php @@ -14,7 +14,7 @@ /** * Flag potentially slow queries. * - * @link https://vip.wordpress.com/documentation/vip-go/code-review-blockers-warnings-notices/#uncached-pageload + * @link https://docs.wpvip.com/php_codesniffer/warnings/#h-functions-that-use-joins-taxonomy-relation-queries-cat-tax-queries-subselects-or-api-calls * * @since 0.3.0 * @since 0.13.0 Class name changed: this class is now namespaced. diff --git a/WordPress/Sniffs/DateTime/RestrictedFunctionsSniff.php b/WordPress/Sniffs/DateTime/RestrictedFunctionsSniff.php index 279da5735c..16c279b9bc 100644 --- a/WordPress/Sniffs/DateTime/RestrictedFunctionsSniff.php +++ b/WordPress/Sniffs/DateTime/RestrictedFunctionsSniff.php @@ -29,7 +29,7 @@ public function getGroups() { /* * Disallow the changing the timezone. * - * @link https://vip.wordpress.com/documentation/vip-go/code-review-blockers-warnings-notices/#manipulating-the-timezone-server-side + * @link https://docs.wpvip.com/php_codesniffer/errors/#h-manipulating-the-timezone-server-side */ 'timezone_change' => array( 'type' => 'error', diff --git a/WordPress/Sniffs/Security/PluginMenuSlugSniff.php b/WordPress/Sniffs/Security/PluginMenuSlugSniff.php index 0deac9e82c..7efb287f8c 100644 --- a/WordPress/Sniffs/Security/PluginMenuSlugSniff.php +++ b/WordPress/Sniffs/Security/PluginMenuSlugSniff.php @@ -15,7 +15,7 @@ /** * Warn about __FILE__ for page registration. * - * @link https://vip.wordpress.com/documentation/vip-go/code-review-blockers-warnings-notices/#using-__file__-for-page-registration + * @link https://docs.wpvip.com/php_codesniffer/warnings/#h-using-file-for-page-registration * * @since 0.3.0 * @since 0.11.0 Refactored to extend the new WordPressCS native diff --git a/WordPress/Sniffs/WP/CronIntervalSniff.php b/WordPress/Sniffs/WP/CronIntervalSniff.php index fd48e1a2f2..a93315daa9 100644 --- a/WordPress/Sniffs/WP/CronIntervalSniff.php +++ b/WordPress/Sniffs/WP/CronIntervalSniff.php @@ -22,7 +22,7 @@ /** * Flag cron schedules less than 15 minutes. * - * @link https://vip.wordpress.com/documentation/vip-go/code-review-blockers-warnings-notices/#cron-schedules-less-than-15-minutes-or-expensive-events + * @link https://docs.wpvip.com/php_codesniffer/warnings/#h-cron-schedules-less-than-15-minutes-or-expensive-events * * @since 0.3.0 * @since 0.11.0 - Extends the WordPressCS native `Sniff` class. diff --git a/WordPress/Sniffs/WP/EnqueuedResourcesSniff.php b/WordPress/Sniffs/WP/EnqueuedResourcesSniff.php index bc7e9c94fa..28142e8aac 100644 --- a/WordPress/Sniffs/WP/EnqueuedResourcesSniff.php +++ b/WordPress/Sniffs/WP/EnqueuedResourcesSniff.php @@ -18,8 +18,6 @@ /** * Makes sure scripts and styles are enqueued and not explicitly echo'd. * - * @link https://vip.wordpress.com/documentation/vip-go/code-review-blockers-warnings-notices/#inline-resources - * * @since 0.3.0 * @since 0.12.0 This class now extends the WordPressCS native `Sniff` class. * @since 0.13.0 Class name changed: this class is now namespaced. diff --git a/WordPress/Sniffs/WP/PostsPerPageSniff.php b/WordPress/Sniffs/WP/PostsPerPageSniff.php index e2575cbd43..6c62b920d9 100644 --- a/WordPress/Sniffs/WP/PostsPerPageSniff.php +++ b/WordPress/Sniffs/WP/PostsPerPageSniff.php @@ -16,7 +16,7 @@ /** * Flag returning high or infinite posts_per_page. * - * @link https://vip.wordpress.com/documentation/vip-go/code-review-blockers-warnings-notices/#no-limit-queries + * @link https://docs.wpvip.com/php_codesniffer/warnings/#h-no-limit-queries * * @since 0.3.0 * @since 0.13.0 Class name changed: this class is now namespaced. From aa5bafac1f9222abfe17b578e5c49617904db9e7 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 3 Nov 2025 09:15:50 +0000 Subject: [PATCH 077/105] GH Actions: Bump crate-ci/typos in the action-runners group Bumps the action-runners group with 1 update: [crate-ci/typos](https://github.com/crate-ci/typos). Updates `crate-ci/typos` from 1.38.1 to 1.39.0 - [Release notes](https://github.com/crate-ci/typos/releases) - [Changelog](https://github.com/crate-ci/typos/blob/master/CHANGELOG.md) - [Commits](https://github.com/crate-ci/typos/compare/80c8a4945eec0f6d464eaf9e65ed98ef085283d1...07d900b8fa1097806b8adb6391b0d3e0ac2fdea7) --- updated-dependencies: - dependency-name: crate-ci/typos dependency-version: 1.39.0 dependency-type: direct:production update-type: version-update:semver-minor dependency-group: action-runners ... Signed-off-by: dependabot[bot] --- .github/workflows/basic-qa.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/basic-qa.yml b/.github/workflows/basic-qa.yml index e00b9e2d60..b587ee2aec 100644 --- a/.github/workflows/basic-qa.yml +++ b/.github/workflows/basic-qa.yml @@ -275,4 +275,4 @@ jobs: persist-credentials: false - name: "Search for misspellings" - uses: "crate-ci/typos@80c8a4945eec0f6d464eaf9e65ed98ef085283d1" # v1.38.1 + uses: "crate-ci/typos@07d900b8fa1097806b8adb6391b0d3e0ac2fdea7" # v1.39.0 From 4639b05ff0fb0428ce8e4d357f2437b5f9356bda Mon Sep 17 00:00:00 2001 From: Rodrigo Primo Date: Thu, 6 Nov 2025 08:32:56 -0300 Subject: [PATCH 078/105] Security/ValidatedSanitizedInput: improve `InputNotValidated` error message The error message for `InputNotValidated` previously listed specific methods (isset() and empty()), but the list was incomplete. Rather than expanding it, this commit adopts a more generic message that won't require updates when new validation methods are added. Fixes 2641 Co-authored-by: Juliette <663378+jrfnl@users.noreply.github.com> --- WordPress/Sniffs/Security/ValidatedSanitizedInputSniff.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/WordPress/Sniffs/Security/ValidatedSanitizedInputSniff.php b/WordPress/Sniffs/Security/ValidatedSanitizedInputSniff.php index d3b7fe02f8..45ea8ce896 100644 --- a/WordPress/Sniffs/Security/ValidatedSanitizedInputSniff.php +++ b/WordPress/Sniffs/Security/ValidatedSanitizedInputSniff.php @@ -175,7 +175,7 @@ static function ( $var_name ) { if ( false === $validated ) { $this->phpcsFile->addError( - 'Detected usage of a possibly undefined superglobal array index: %s. Use isset() or empty() to check the index exists before using it', + 'Detected usage of a possibly undefined superglobal array index: %s. Check that the array index exists before using it.', $stackPtr, 'InputNotValidated', $error_data From e60764e002763c2d6e9d8a3252710aafffc5fb5b Mon Sep 17 00:00:00 2001 From: Rodrigo Primo Date: Tue, 19 Aug 2025 14:24:34 -0300 Subject: [PATCH 079/105] Utils/I18nTextDomainFixer: add tests for namespaced names There were already a few tests with namespaced names, so this commit adds only what was missing in the existing tests. --- .../Tests/Utils/I18nTextDomainFixerUnitTest.4.inc | 12 ++++++++++-- .../Utils/I18nTextDomainFixerUnitTest.4.inc.fixed | 12 ++++++++++-- .../Tests/Utils/I18nTextDomainFixerUnitTest.php | 2 ++ 3 files changed, 22 insertions(+), 4 deletions(-) diff --git a/WordPress/Tests/Utils/I18nTextDomainFixerUnitTest.4.inc b/WordPress/Tests/Utils/I18nTextDomainFixerUnitTest.4.inc index d33d0a18e0..26f6cdd71f 100644 --- a/WordPress/Tests/Utils/I18nTextDomainFixerUnitTest.4.inc +++ b/WordPress/Tests/Utils/I18nTextDomainFixerUnitTest.4.inc @@ -77,11 +77,11 @@ is_textdomain_loaded( 'some-other-plugin' ); * Incorrect text domain, should be replaced. */ load_textdomain( 'text-domain', '/path/to/file.mo' ); -load_plugin_textdomain( 'text-domain', false, '/languages/' ); +\load_plugin_textdomain( 'text-domain', false, '/languages/' ); load_muplugin_textdomain( 'other-text-domain', '/languages/' ); load_theme_textdomain( 'third-text-domain', '/path/to/languages/' ); load_child_theme_textdomain( 'text-domain', '/path/to/languages/' ); -unload_textdomain( 'text-domain' ); +unload_TEXTDOMAIN( 'text-domain' ); __( $text, 'text-domain' ); _e( $text, 'text-domain' ); @@ -281,5 +281,13 @@ __ ( $args ); +/* + * Safeguard correct handling of namespaced function calls (partially qualified is already tested above). + */ +\MyNamespace\load_textdomain( 'text-domain', '/path/to/file.mo' ); +namespace\__( $text, 'text-domain' ); +\ESC_HTML__( $text, 'text-domain' ); +\get_translations_for_domain(); + // phpcs:set WordPress.Utils.I18nTextDomainFixer old_text_domain[] // phpcs:set WordPress.Utils.I18nTextDomainFixer new_text_domain false diff --git a/WordPress/Tests/Utils/I18nTextDomainFixerUnitTest.4.inc.fixed b/WordPress/Tests/Utils/I18nTextDomainFixerUnitTest.4.inc.fixed index f7fd2c6f4e..98f6adabfd 100644 --- a/WordPress/Tests/Utils/I18nTextDomainFixerUnitTest.4.inc.fixed +++ b/WordPress/Tests/Utils/I18nTextDomainFixerUnitTest.4.inc.fixed @@ -77,11 +77,11 @@ is_textdomain_loaded( 'some-other-plugin' ); * Incorrect text domain, should be replaced. */ load_textdomain( 'something-else', '/path/to/file.mo' ); -load_plugin_textdomain( 'something-else', false, '/languages/' ); +\load_plugin_textdomain( 'something-else', false, '/languages/' ); load_muplugin_textdomain( 'something-else', '/languages/' ); load_theme_textdomain( 'something-else', '/path/to/languages/' ); load_child_theme_textdomain( 'something-else', '/path/to/languages/' ); -unload_textdomain( 'something-else' ); +unload_TEXTDOMAIN( 'something-else' ); __( $text, 'something-else' ); _e( $text, 'something-else' ); @@ -287,5 +287,13 @@ __ ( 'something-else' ); +/* + * Safeguard correct handling of namespaced function calls (partially qualified is already tested above). + */ +\MyNamespace\load_textdomain( 'text-domain', '/path/to/file.mo' ); +namespace\__( $text, 'text-domain' ); +\ESC_HTML__( $text, 'something-else' ); +\get_translations_for_domain( 'something-else' ); + // phpcs:set WordPress.Utils.I18nTextDomainFixer old_text_domain[] // phpcs:set WordPress.Utils.I18nTextDomainFixer new_text_domain false diff --git a/WordPress/Tests/Utils/I18nTextDomainFixerUnitTest.php b/WordPress/Tests/Utils/I18nTextDomainFixerUnitTest.php index a8c7c95e84..872050aa97 100644 --- a/WordPress/Tests/Utils/I18nTextDomainFixerUnitTest.php +++ b/WordPress/Tests/Utils/I18nTextDomainFixerUnitTest.php @@ -154,6 +154,8 @@ public function getErrorList( $testFile = '' ) { 245 => 1, 277 => 1, 278 => 1, + 289 => 1, + 290 => 1, ); default: From b39cffc323b2c5693849657afdcab444a24e84ad Mon Sep 17 00:00:00 2001 From: Rodrigo Primo Date: Thu, 21 Aug 2025 15:18:14 -0300 Subject: [PATCH 080/105] Security/NonceVerification: add tests for namespaced names Co-authored-by: Juliette <663378+jrfnl@users.noreply.github.com> --- .../Security/NonceVerificationUnitTest.1.inc | 171 +++++++++++++++++- .../Security/NonceVerificationUnitTest.php | 20 ++ 2 files changed, 188 insertions(+), 3 deletions(-) diff --git a/WordPress/Tests/Security/NonceVerificationUnitTest.1.inc b/WordPress/Tests/Security/NonceVerificationUnitTest.1.inc index aee51ae39a..fc688e09de 100644 --- a/WordPress/Tests/Security/NonceVerificationUnitTest.1.inc +++ b/WordPress/Tests/Security/NonceVerificationUnitTest.1.inc @@ -250,7 +250,7 @@ function allow_for_unslash_before_noncecheck() { } function allow_for_unslash_in_sanitization() { - $var = sanitize_text_field( wp_unslash( $_POST['foo'] ) ); // OK. + $var = sanitize_text_field( WP_UNSLASH( $_POST['foo'] ) ); // OK. wp_verify_nonce( $var ); echo $var; } @@ -314,7 +314,7 @@ function allow_in_array_key_exists_before_noncecheck() { } function allow_in_key_exists_before_noncecheck() { - if (key_exists('foo', $_POST['subset']) === false) { // OK. + if (Key_Exists('foo', $_POST['subset']) === false) { // OK. return; } @@ -369,7 +369,7 @@ function disallow_for_non_array_comparison_in_condition() { } function allow_for_array_comparison_in_condition_with_named_params() { - if ( array_keys( filter_value: 'my_action', array: $_GET['actions'], strict: true, ) ) { // OK. + if ( \array_KEYS( filter_value: 'my_action', array: $_GET['actions'], strict: true, ) ) { // OK. check_admin_referer( 'foo' ); foo(); } @@ -524,3 +524,168 @@ function different_function_name() { update_post_meta( (int) $_POST['id'], 'a_key', $_POST['a_value'] ); } // phpcs:set WordPress.Security.NonceVerification customNonceVerificationFunctions[] + +function test_fully_qualified_call_to_global_nonce_verification_function() { + if ( ! IS_NUMERIC( $_POST['foo'] ) ) { // OK. + return; + } + + \wp_verify_nonce( 'some_action' ); +} + +function test_namespace_relative_call_to_global_nonce_verification_function() { + if ( ! IS_NUMERIC( $_POST['foo'] ) ) { // Bad, but should become ok once the sniff is able to resolve relative namespaces. + return; + } + + namespace\wp_verify_nonce( 'some_action' ); +} + +function test_namespaced_calls_to_incorrect_nonce_verification_functions() { + if ( ! is_numeric( $_POST['foo'] ) ) { // Bad - none of the below are the WP global functions, so no nonce verification. + return; + } + + MyNamespace\wp_verify_nonce( 'some_action' ); + \MyNamespace\check_admin_referer( 'some_action' ); + namespace\Sub\check_ajax_referer( 'some_action' ); +} + +// phpcs:set WordPress.Security.NonceVerification customNonceVerificationFunctions[] my_nonce_check + +function test_namespace_relative_call_to_custom_nonce_verification_function() { + if ( ! is_int( $_POST['foo'] ) ) { // Bad, but should become ok once the sniff is able to resolve relative namespaces. + return; + } + + namespace\my_nonce_check( 'some_action' ); +} + +function test_namespaced_calls_to_incorrect_custom_nonce_verification_functions() { + if ( ! is_string( $_POST['foo'] ) ) { // Bad - none of the below are a custom nonce verification function. + return; + } + + MyNamespace\my_nonce_check( 'some_action' ); + \MyNamespace\my_nonce_check( 'some_action' ); + namespace\Sub\my_nonce_check( 'some_action' ); +} + +// phpcs:set WordPress.Security.NonceVerification customNonceVerificationFunctions[] + +function allow_fully_qualified_key_exists_functions() { + if ( \array_key_exists('foo', $_POST) === false ) { // OK. + return; + } + + \WP_VERIFY_NONCE( 'some_action' ); +} + +function allow_fully_qualified_key_exists_functions_with_mixed_case() { + if ( \Key_Exists('foo', $_POST) === false ) { // OK. + return; + } + + wp_verify_nonce( 'some_action' ); +} + +function allow_namespace_relative_call_to_global_key_exists_functions() { + if ( namespace\array_key_exists('foo', $_POST) === false ) { // Bad, but should become ok once the sniff is able to resolve relative namespaces. + return; + } + + wp_verify_nonce( 'some_action' ); +} + +function disallow_namespaced_key_exists_functions() { + if ( MyNamespace\array_key_exists( 'foo', $_POST ) === false // Bad. + || \MyNamespace\key_exists( 'foo', $_POST ) === false // Bad. + || namespace\Sub\key_exists( 'foo', $_POST ) === false // Bad. + ) { + return; + } + + wp_verify_nonce( 'some_action' ); +} + +function allow_fully_qualified_type_test_functions() { + if ( ! \is_numeric( $_POST['foo'] ) ) { // OK. + return; + } + + \wp_verify_nonce( 'some_action' ); +} + +function allow_fully_qualified_type_test_functions_uppercase() { + if ( ! \IS_int( $_POST['foo'] ) ) { // OK. + return; + } + + \wp_verify_nonce( 'some_action' ); +} + +function allow_namespace_relative_call_to_global_type_test_functions() { + if ( ! namespace\is_numeric( $_POST['foo'] ) ) { // Bad, but should become ok once the sniff is able to resolve relative namespaces. + return; + } + + \wp_verify_nonce( 'some_action' ); +} + +function disallow_namespaced_type_test_functions() { + if ( ! MyNamespace\is_bool( $_POST['foo'] ) // Bad. + || ! \MyNamespace\is_object( $_POST['foo'] ) // Bad. + || ! namespace\Sub\is_string( $_POST['foo'] ) ) // Bad. + { + return; + } + + \wp_verify_nonce( 'some_action' ); +} + +function allow_fully_qualified_array_comparison_functions() { + if ( \in_array( $_GET['action'], $valid_actions, true ) ) { // OK. + check_admin_referer( 'foo' ); + } +} + +function allow_namespace_relative_call_to_global_array_comparison_functions() { + if ( namespace\in_array( $_GET['action'], $valid_actions, true ) ) { // Bad, but should become ok once the sniff is able to resolve relative namespaces. + check_admin_referer( 'foo' ); + } +} + +function disallow_namespaced_array_comparison_functions() { + if ( MyNamespace\in_array( $_GET['action'], $valid_actions, true ) // Bad. + || \MyNamespace\array_search( array( 'subscribe', 'unsubscribe' ), $_GET['action'], true ) // Bad. + || namespace\Sub\array_keys( $_GET['actions'], 'my_action', true ) // Bad. + ) { + check_admin_referer( 'foo' ); + } +} + +function allow_fully_qualified_unslashing_functions() { + $var = \stripslashes_from_strings_only( $_POST['foo'] ); // OK. + wp_verify_nonce( $var ); + echo $var; +} + +function allow_fully_qualified_unslashing_functions_mixed_case() { + $var = \stripslashes_FROM_strings_ONLY( $_POST['foo'] ); // OK. + wp_verify_nonce( $var ); + echo $var; +} + +function allow_namespace_relative_call_to_global_unslashing_functions() { + $var = namespace\stripslashes_from_strings_only( $_POST['foo'] ); // Bad, but should become ok once the sniff is able to resolve relative namespaces. + wp_verify_nonce( $var ); + echo $var; +} + +function disallow_namespaced_unslashing_functions() { + $var = MyNamespace\stripslashes_from_strings_only( $_POST['foo'] ); // Bad. + $var = \MyNamespace\stripslashes_deep( $_POST['foo'] ); // Bad. + $var = namespace\Sub\wp_unslash( $_POST['foo'] ); // Bad. + wp_verify_nonce( $var ); + echo $var; +} diff --git a/WordPress/Tests/Security/NonceVerificationUnitTest.php b/WordPress/Tests/Security/NonceVerificationUnitTest.php index aa5e832e83..ea76b5a4b0 100644 --- a/WordPress/Tests/Security/NonceVerificationUnitTest.php +++ b/WordPress/Tests/Security/NonceVerificationUnitTest.php @@ -75,6 +75,22 @@ public function getErrorList( $testFile = '' ) { 470 => 1, 478 => 1, 524 => 2, + 537 => 1, + 545 => 1, + 557 => 1, + 565 => 1, + 593 => 1, + 601 => 1, + 602 => 1, + 603 => 1, + 628 => 1, + 636 => 1, + 637 => 1, + 638 => 1, + 680 => 1, + 686 => 1, + 687 => 1, + 688 => 1, ); case 'NonceVerificationUnitTest.2.inc': @@ -107,6 +123,10 @@ public function getWarningList( $testFile = '' ) { return array( 365 => 1, 379 => 1, + 653 => 1, + 659 => 1, + 660 => 1, + 661 => 1, ); case 'NonceVerificationUnitTest.4.inc': From a8d703c7370f5917c1b6a5f43d7ba18407978220 Mon Sep 17 00:00:00 2001 From: Rodrigo Primo Date: Thu, 21 Aug 2025 15:24:04 -0300 Subject: [PATCH 081/105] NamingConventions/ValidHookName: add tests for namespaced names --- .../NamingConventions/ValidHookNameUnitTest.1.inc | 15 +++++++++++++-- .../NamingConventions/ValidHookNameUnitTest.php | 1 + 2 files changed, 14 insertions(+), 2 deletions(-) diff --git a/WordPress/Tests/NamingConventions/ValidHookNameUnitTest.1.inc b/WordPress/Tests/NamingConventions/ValidHookNameUnitTest.1.inc index 830c3552d6..466c23e522 100644 --- a/WordPress/Tests/NamingConventions/ValidHookNameUnitTest.1.inc +++ b/WordPress/Tests/NamingConventions/ValidHookNameUnitTest.1.inc @@ -6,9 +6,9 @@ prefix_do_action( 'someAction' ); // Ok - not WP do_action. // Check for incorrect word separators. do_action( "admin_head-$hook_suffix" ); // Warning - use underscore. -do_action( 'admin_head.media.upload_popup' ); // Warning - use underscore. +DO_ACTION( 'admin_head.media.upload_popup' ); // Warning - use underscore. apply_filters( "bulk_actions {$this->screen->id}", $this->_actions ); // Warning - use underscore. -apply_filters( "current_theme/supports-{$feature}", true, $args, $_wp_theme_features[$feature] ); // Warning - use underscore. +\Apply_Filters( "current_theme/supports-{$feature}", true, $args, $_wp_theme_features[$feature] ); // Warning - use underscore. // Simple strings. do_action( "adminHead" ); // Error - use lowercase. @@ -121,3 +121,14 @@ do_action( 'admin_head_' . $fn( 'UPPERCASE', 'wrong-delimiter' ) . '_action' ); do_action_ref_array( hook: 'My-Hook', args: $args ); // OK. Well, not really, but using the wrong parameter name, so not our concern. do_action_ref_array( args: $args, hook_name: 'my_hook', ); // OK. do_action_ref_array( args: $args, hook_name: 'My-Hook', ); // Error - use lowercase + warning about dash. + +/* + * Safeguard correct handling of all types of namespaced function calls. + */ +\apply_filters( 'adminHead', $variable ); // Error. +MyNamespace\do_action( 'adminHead' ); // Ok. +\MyNamespace\do_action_ref_array( 'adminHead', array( $variable ) ); // Ok. +namespace\apply_filters_ref_array( 'adminHead', array( $variable ) ); // Ok. The sniff should start flagging this once it can resolve relative namespaces. +apply_filters( 'admin_head_' . MyNamespace\my_function('UPPERCASE') . '_action', $variable ); // Ok. +do_action( 'admin_head_' . \MyNamespace\my_function('UPPERCASE') . '_action' ); // Ok. +do_action_ref_array( 'admin_head_' . namespace\my_function('UPPERCASE') . '_action', array( $variable ) ); // Ok. diff --git a/WordPress/Tests/NamingConventions/ValidHookNameUnitTest.php b/WordPress/Tests/NamingConventions/ValidHookNameUnitTest.php index aac97da195..98649fb620 100644 --- a/WordPress/Tests/NamingConventions/ValidHookNameUnitTest.php +++ b/WordPress/Tests/NamingConventions/ValidHookNameUnitTest.php @@ -75,6 +75,7 @@ public function getErrorList( $testFile = 'ValidHookNameUnitTest.1.inc' ) { 114 => 1, 115 => 1, 123 => 1, + 128 => 1, ); case 'ValidHookNameUnitTest.2.inc': From 269da1b05570ed35f194da8255c0b35ca2ca2996 Mon Sep 17 00:00:00 2001 From: Rodrigo Primo Date: Thu, 21 Aug 2025 15:35:33 -0300 Subject: [PATCH 082/105] NamingConventions/PrefixAllGlobals: add tests for namespaced names --- .../PrefixAllGlobalsUnitTest.1.inc | 16 +++++++-- .../PrefixAllGlobalsUnitTest.3.inc | 34 ++++++++++++++++++- .../PrefixAllGlobalsUnitTest.php | 12 +++++-- 3 files changed, 57 insertions(+), 5 deletions(-) diff --git a/WordPress/Tests/NamingConventions/PrefixAllGlobalsUnitTest.1.inc b/WordPress/Tests/NamingConventions/PrefixAllGlobalsUnitTest.1.inc index 011e250b7f..707468c137 100644 --- a/WordPress/Tests/NamingConventions/PrefixAllGlobalsUnitTest.1.inc +++ b/WordPress/Tests/NamingConventions/PrefixAllGlobalsUnitTest.1.inc @@ -260,10 +260,10 @@ $GLOBALS[ $something ] = 'value'; // Warning. $GLOBALS[ "{$something}_something" ] = 'value'; // Warning. $GLOBALS[ ${$something} ] = 'value'; // Warning. -define( ${$something}, 'value' ); // Warning. +DEFINE( ${$something}, 'value' ); // Warning. define( $something, 'value' ); // Warning. define( $something . '_CONSTANT', 'value' ); // Warning. -define( "{$something}_CONSTANT", 'value' ); // Warning. +\Define( "{$something}_CONSTANT", 'value' ); // Warning. define( $something . '_CONSTANT', 'value' ); // Warning. do_action( "{$acronym_filter_var}_hook_name" ); // Warning. @@ -683,4 +683,16 @@ class Acronym_AsymmetricVisibilityProperties { public function __construct(public protected(set) int $foo = 0) {} // Ok. } +/* + * Safeguard correct handling of all types of namespaced function calls. + */ +\define('SOME_GLOBAL', [ 1, 2, 3 ]); // Bad. +MyNamespace\define('SOME_GLOBAL', [ 1, 2, 3 ]); // Ok. +\MyNamespace\define('SOME_GLOBAL', [ 1, 2, 3 ]); // Ok. +namespace\define('SOME_GLOBAL', [ 1, 2, 3 ]); // Ok. The sniff should start flagging this once it can resolve relative namespaces. +\do_action( 'plugin_action' ); // Bad. +MyNamespace\do_action( 'plugin_action' ); // Ok. +\MyNamespace\apply_filters( 'plugin_filter', $variable ); // Ok. +namespace\do_action_ref_array( 'plugin_action', array( $variable ) ); // Ok. The sniff should start flagging this once it can resolve relative namespaces. + // phpcs:set WordPress.NamingConventions.PrefixAllGlobals prefixes[] diff --git a/WordPress/Tests/NamingConventions/PrefixAllGlobalsUnitTest.3.inc b/WordPress/Tests/NamingConventions/PrefixAllGlobalsUnitTest.3.inc index be1eb3627f..e910701dba 100644 --- a/WordPress/Tests/NamingConventions/PrefixAllGlobalsUnitTest.3.inc +++ b/WordPress/Tests/NamingConventions/PrefixAllGlobalsUnitTest.3.inc @@ -12,7 +12,7 @@ class Some_Test extends \PHPUnit_Framework_TestCase { } } -$acronym_test = new class extends \PHPUnit_Framework_TestCase { +$acronym_test = new class extends \phpunit_framework_testcase { public function testPass() { define( 'SOME_GLOBAL', '4.0.0' ); @@ -21,4 +21,36 @@ $acronym_test = new class extends \PHPUnit_Framework_TestCase { } }; +// Test namespace resolution when the sniff checks the extending class. +class Extends_Namespaced_Class_Not_WP_Test extends WP_Font_Face_UnitTestCase { + + public function testPass() { + do_action( 'some-action', $something ); + } +} + +/* + * Safeguard correct handling of namespaced extending classes. + */ +class Extends_Partially_Qualified_Not_WP_Test extends MyNamespace\WP_UnitTestCase_Base { + + public function testPass() { + do_action( 'some-action', $something ); + } +} + +class Extends_Fully_Qualified_Not_WP_Test extends \MyNamespace\WP_Ajax_UnitTestCase { + + public function testPass() { + do_action( 'some-action', $something ); + } +} + +class Extends_Relative_Namespace_Not_WP_Test extends namespace\WP_Canonical_UnitTestCase { + + public function testPass() { + do_action( 'some-action', $something ); + } +} + // phpcs:set WordPress.NamingConventions.PrefixAllGlobals prefixes[] diff --git a/WordPress/Tests/NamingConventions/PrefixAllGlobalsUnitTest.php b/WordPress/Tests/NamingConventions/PrefixAllGlobalsUnitTest.php index b9beb09ff6..b93ad6216d 100644 --- a/WordPress/Tests/NamingConventions/PrefixAllGlobalsUnitTest.php +++ b/WordPress/Tests/NamingConventions/PrefixAllGlobalsUnitTest.php @@ -96,6 +96,16 @@ public function getErrorList( $testFile = 'PrefixAllGlobalsUnitTest.1.inc' ) { 616 => 1, 617 => 1, 633 => 1, + 689 => 1, + 693 => 1, + ); + + case 'PrefixAllGlobalsUnitTest.3.inc': + return array( + 28 => 1, + 38 => 1, + 45 => 1, + 52 => 1, ); case 'PrefixAllGlobalsUnitTest.4.inc': @@ -106,8 +116,6 @@ public function getErrorList( $testFile = 'PrefixAllGlobalsUnitTest.1.inc' ) { case 'PrefixAllGlobalsUnitTest.2.inc': // Namespaced - all OK, fall through to the default case. - case 'PrefixAllGlobalsUnitTest.3.inc': - // Test class - non-prefixed constant is fine, fall through to the default case. default: return array(); } From 4a34f38eee38e4abd553487f2c2120e75fc2b662 Mon Sep 17 00:00:00 2001 From: Rodrigo Primo Date: Thu, 21 Aug 2025 15:40:11 -0300 Subject: [PATCH 083/105] PHP/NoSilencedErrors: add tests for namespaced names Co-authored-by: Juliette <663378+jrfnl@users.noreply.github.com> --- WordPress/Tests/PHP/NoSilencedErrorsUnitTest.inc | 12 ++++++++++-- WordPress/Tests/PHP/NoSilencedErrorsUnitTest.php | 4 ++++ 2 files changed, 14 insertions(+), 2 deletions(-) diff --git a/WordPress/Tests/PHP/NoSilencedErrorsUnitTest.inc b/WordPress/Tests/PHP/NoSilencedErrorsUnitTest.inc index f007d150bd..27b3598537 100644 --- a/WordPress/Tests/PHP/NoSilencedErrorsUnitTest.inc +++ b/WordPress/Tests/PHP/NoSilencedErrorsUnitTest.inc @@ -12,7 +12,7 @@ if (@in_array($array, $needle)) { // Bad. } // File extension. -if ( @&file_exists( $filename ) && @ /*comment*/ is_readable( $filename ) ) { +if ( @&file_exists( $filename ) && @ /*comment*/ IS_READABLE( $filename ) ) { $file = @ \file( $filename ); } @@ -22,7 +22,7 @@ $fp = @fopen('https://www.example.com', 'r', false); // Directory extension. if (@is_dir($dir)) { - if ($dh = @\opendir($dir)) { + if ($dh = @\OPENDIR($dir)) { while (($file = @readdir($dh)) !== false) { // Bad. echo "filename: $file : filetype: " . @\filetype($dir . $file) . "\n"; } @@ -84,3 +84,11 @@ $decoded = @hex2bin( $data ); // phpcs:set WordPress.PHP.NoSilencedErrors context_length 0 echo @some_userland_function( $param ); // Bad. // phpcs:set WordPress.PHP.NoSilencedErrors context_length 6 + +/* + * Safeguard correct handling of namespaced function calls (fully qualified is already tested above). + */ +$file = @MyNS\MyClass::file_get_contents( $file ); // Bad. +$file = @MyNS\MyClass\file_exists( $file ); // Bad. +$file = @namespace\MyNS\MyClass::file( $file ); // Bad. +$file = @namespace\is_dir( $dir ); // The sniff should stop flagging this once it can resolve relative namespaces. diff --git a/WordPress/Tests/PHP/NoSilencedErrorsUnitTest.php b/WordPress/Tests/PHP/NoSilencedErrorsUnitTest.php index 7a576b992c..038c2c8d71 100644 --- a/WordPress/Tests/PHP/NoSilencedErrorsUnitTest.php +++ b/WordPress/Tests/PHP/NoSilencedErrorsUnitTest.php @@ -61,6 +61,10 @@ public function getWarningList() { 71 => 1, 78 => 1, 85 => 1, + 91 => 1, + 92 => 1, + 93 => 1, + 94 => 1, ); } } From 861c0e89482e182322ef9fcd1121a1c23ae56b8e Mon Sep 17 00:00:00 2001 From: Rodrigo Primo Date: Thu, 21 Aug 2025 15:51:17 -0300 Subject: [PATCH 084/105] WP/CronInterval: add tests for namespaced names --- WordPress/Tests/WP/CronIntervalUnitTest.inc | 39 +++++++++++++++++++-- WordPress/Tests/WP/CronIntervalUnitTest.php | 7 +++- 2 files changed, 42 insertions(+), 4 deletions(-) diff --git a/WordPress/Tests/WP/CronIntervalUnitTest.inc b/WordPress/Tests/WP/CronIntervalUnitTest.inc index e9541f49d2..5ebc161d4c 100644 --- a/WordPress/Tests/WP/CronIntervalUnitTest.inc +++ b/WordPress/Tests/WP/CronIntervalUnitTest.inc @@ -165,9 +165,9 @@ add_filter( 'cron_schedules', function ( $schedules ) { class FQNConstants { public function add_schedules() { add_filter( 'cron_schedules', array( $this, 'add_weekly_schedule' ) ); // Ok: > 15 min. - add_filter( 'cron_schedules', array( $this, 'add_eight_minute_schedule' ) ); // Warning: 8 min. - add_filter( 'cron_schedules', array( $this, 'add_hundred_minute_schedule' ) ); // Warning: time undetermined. - add_filter( 'cron_schedules', array( $this, 'sneaky_fake_wp_constant_schedule' ) ); // Warning: time undetermined. + \add_filter( 'cron_schedules', array( $this, 'add_eight_minute_schedule' ) ); // Warning: 8 min. + ADD_FILTER( 'cron_schedules', array( $this, 'add_hundred_minute_schedule' ) ); // Warning: time undetermined. + \Add_Filter( 'cron_schedules', array( $this, 'sneaky_fake_wp_constant_schedule' ) ); // Warning: time undetermined. } public function add_weekly_schedule( $schedules ) { @@ -316,6 +316,7 @@ function first_class_weekly_schedule( $schedules ) { } add_filter( 'cron_schedules', 'first_class_weekly_schedule'(...)); // Ok: > 15 min. add_filter( 'cron_schedules', first_class_weekly_schedule(...)); // Ok: > 15 min. +add_filter( 'cron_schedules', namespace\first_class_weekly_schedule(...)); // Ok: > 15 min. function first_class_six_min_schedule( $schedules ) { $schedules['every_6_mins'] = array( @@ -326,3 +327,35 @@ function first_class_six_min_schedule( $schedules ) { } add_filter( 'cron_schedules', first_class_six_min_schedule(...)); // Warning: 6 min. add_filter( 'cron_schedules', 'first_class_six_min_schedule'(...)); // Warning: 6 min. +add_filter( 'cron_schedules', \first_class_six_min_schedule(...)); // Warning: 6 min. +add_filter( 'cron_schedules', namespace\first_class_six_min_schedule(...)); // Warning: 6 min. + +/* + * The tests below document the current behavior of the sniff, even though they are false negatives. The sniff treats + * the first-class callable examples below as if referencing the global function first_class_six_min_schedule() + * and not a namespaced function with the same name. + * + * Related to: https://github.com/WordPress/WordPress-Coding-Standards/issues/2644. + */ +add_filter( 'cron_schedules', MyNamespace\first_class_weekly_schedule(...)); // False negative - Ok: > 15 min, but should be marked `ChangeDetected`. +add_filter( 'cron_schedules', \MyNamespace\first_class_weekly_schedule(...)); // False negative - Ok: > 15 min, but should be marked `ChangeDetected`. +add_filter( 'cron_schedules', namespace\Sub\first_class_weekly_schedule(...)); // False negative - Ok: > 15 min, but should be marked `ChangeDetected`. + +/* + * The tests below document the current behavior of the sniff, even though they are false positives. The sniff treats + * the first-class callable examples below as if referencing the global function first_class_six_min_schedule() + * and not a namespaced function with the same name. Fixing this incorrect behavior is not trivial. + * + * Related to: https://github.com/WordPress/WordPress-Coding-Standards/issues/2644. + */ +add_filter( 'cron_schedules', MyNamespace\first_class_six_min_schedule(...)); // False positive - `CronSchedulesInterval` warning (6 min), but should be `ChangeDetected`. +add_filter( 'cron_schedules', \MyNamespace\first_class_six_min_schedule(...)); // False positive - `CronSchedulesInterval` warning (6 min), but should be `ChangeDetected`. +add_filter( 'cron_schedules', namespace\Sub\first_class_six_min_schedule(...)); // False positive - `CronSchedulesInterval` warning (6 min), but should be `ChangeDetected`. + +/* + * Safeguard correct handling of all types of namespaced function calls (except FQN global function call which is + * handled above). + */ +MyNamespace\add_filter( 'cron_schedules', 'unknown_callback' ); // Ok. +\MyNamespace\add_filter( 'cron_schedules', 'unknown_callback' ); // Ok. +namespace\add_filter( 'cron_schedules', 'unknown_callback' ); // Ok. The sniff should start flagging this once it can resolve relative namespaces. diff --git a/WordPress/Tests/WP/CronIntervalUnitTest.php b/WordPress/Tests/WP/CronIntervalUnitTest.php index 81f02c2768..2417abaf41 100644 --- a/WordPress/Tests/WP/CronIntervalUnitTest.php +++ b/WordPress/Tests/WP/CronIntervalUnitTest.php @@ -65,8 +65,13 @@ public function getWarningList() { 286 => 1, 288 => 1, 290 => 1, - 327 => 1, 328 => 1, + 329 => 1, + 330 => 1, + 331 => 1, + 351 => 1, + 352 => 1, + 353 => 1, ); } } From b86f078f7607e376506eb32e83fcf0d0f053e626 Mon Sep 17 00:00:00 2001 From: Rodrigo Primo Date: Mon, 18 Aug 2025 16:22:44 -0300 Subject: [PATCH 085/105] WP/DiscouragedConstants: add tests for namespaced function calls Add tests safeguarding that namespaced calls to functions named `define` are handled correctly. --- .../Tests/WP/DiscouragedConstantsUnitTest.inc | 12 +++++- .../Tests/WP/DiscouragedConstantsUnitTest.php | 41 ++++++++++--------- 2 files changed, 31 insertions(+), 22 deletions(-) diff --git a/WordPress/Tests/WP/DiscouragedConstantsUnitTest.inc b/WordPress/Tests/WP/DiscouragedConstantsUnitTest.inc index ea8ae72524..50302d54fc 100644 --- a/WordPress/Tests/WP/DiscouragedConstantsUnitTest.inc +++ b/WordPress/Tests/WP/DiscouragedConstantsUnitTest.inc @@ -80,10 +80,10 @@ enum BACKGROUND_COLOR: string implements Colorful {} // Safeguard support for PHP 8.0+ named parameters. define( case_insensitive: false, value: 'something' ); // OK. Well, not really as missing a required param, but that's not the concern of this sniff. -define( case_insensitive: false, constant_name: 'STYLESHEETPATH', value: 'something' ); // Bad. +\DEFINE( case_insensitive: false, constant_name: 'STYLESHEETPATH', value: 'something' ); // Bad. // Safeguard that comments in the parameters are ignored. -define( +Define( // Name. 'STYLESHEETPATH', // Value. @@ -102,3 +102,11 @@ enum ContainsConst { } echo HEADER_TEXTCOLOR::$var; // OK. + +/* + * Safeguard correct handling of all types of namespaced function calls. + */ +\define( 'HEADER_IMAGE', 'something' ); // Bad. +\MyNamespace\define( 'TEMPLATEPATH', 'something' ); // Ok. +MyNamespace\define( 'PLUGINDIR', 'something' ); // Ok. +namespace\define( 'MUPLUGINDIR', 'something' ); // Ok. diff --git a/WordPress/Tests/WP/DiscouragedConstantsUnitTest.php b/WordPress/Tests/WP/DiscouragedConstantsUnitTest.php index e27fd838c2..138d0eb4ef 100644 --- a/WordPress/Tests/WP/DiscouragedConstantsUnitTest.php +++ b/WordPress/Tests/WP/DiscouragedConstantsUnitTest.php @@ -36,26 +36,27 @@ public function getErrorList() { */ public function getWarningList() { return array( - 50 => 1, - 51 => 1, - 52 => 1, - 53 => 1, - 54 => 1, - 55 => 1, - 56 => 1, - 57 => 1, - 58 => 1, - 59 => 1, - 60 => 1, - 61 => 1, - 63 => 1, - 64 => 1, - 66 => 1, - 67 => 1, - 71 => 1, - 72 => 1, - 83 => 1, - 88 => 1, + 50 => 1, + 51 => 1, + 52 => 1, + 53 => 1, + 54 => 1, + 55 => 1, + 56 => 1, + 57 => 1, + 58 => 1, + 59 => 1, + 60 => 1, + 61 => 1, + 63 => 1, + 64 => 1, + 66 => 1, + 67 => 1, + 71 => 1, + 72 => 1, + 83 => 1, + 88 => 1, + 109 => 1, ); } } From 22e4f55f711e9cee22e42ddcaf0f7bb99dfe147a Mon Sep 17 00:00:00 2001 From: Rodrigo Primo Date: Wed, 15 Oct 2025 14:21:10 -0300 Subject: [PATCH 086/105] WP/EnqueuedResourceParameters: fix some inaccuracies and typos in code comments --- .../Sniffs/WP/EnqueuedResourceParametersSniff.php | 14 ++++++++------ .../WP/EnqueuedResourceParametersUnitTest.1.inc | 2 +- 2 files changed, 9 insertions(+), 7 deletions(-) diff --git a/WordPress/Sniffs/WP/EnqueuedResourceParametersSniff.php b/WordPress/Sniffs/WP/EnqueuedResourceParametersSniff.php index 578517238a..0f92bc3791 100644 --- a/WordPress/Sniffs/WP/EnqueuedResourceParametersSniff.php +++ b/WordPress/Sniffs/WP/EnqueuedResourceParametersSniff.php @@ -15,10 +15,11 @@ use WordPressCS\WordPress\AbstractFunctionParameterSniff; /** - * This checks the enqueued 4th and 5th parameters to make sure the version and in_footer are set. + * This checks that the 4th ($ver) parameter is set for all enqueued resources and that the 5th ($in_footer) parameter + * is set for wp_register_script() and wp_enqueue_script(). * * If a source ($src) value is passed, then version ($ver) needs to have non-falsy value. - * If a source ($src) value is passed a check for in footer ($in_footer), warn the user if the value is falsy. + * If a source ($src) value is passed, then it is recommended to explicitly set the $in_footer parameter. * * @link https://developer.wordpress.org/reference/functions/wp_register_script/ * @link https://developer.wordpress.org/reference/functions/wp_enqueue_script/ @@ -66,7 +67,7 @@ final class EnqueuedResourceParametersSniff extends AbstractFunctionParameterSni /** * Token codes which are "safe" to accept to determine whether a version would evaluate to `false`. * - * This array is enriched with the several of the PHPCS token arrays in the register() method. + * This array is enriched with several of the PHPCS token arrays in the register() method. * * @var array */ @@ -88,7 +89,8 @@ final class EnqueuedResourceParametersSniff extends AbstractFunctionParameterSni /** * Returns an array of tokens this test wants to listen for. * - * Overloads and calls the parent method to allow for adding additional tokens to the $safe_tokens property. + * Overloads and calls the parent method to allow for adding additional tokens to the + * $false_tokens and $safe_tokens properties. * * @return array */ @@ -165,8 +167,8 @@ public function process_parameters( $stackPtr, $group_name, $matched_content, $p /* * In footer Check * - * Check to make sure that $in_footer is set to true. - * It will warn the user to make sure it is intended. + * Check to make sure that $in_footer is explicitly set. + * Warn the user if it is not set. * * Only wp_register_script and wp_enqueue_script need this check, * as this parameter is not available to wp_register_style and wp_enqueue_style. diff --git a/WordPress/Tests/WP/EnqueuedResourceParametersUnitTest.1.inc b/WordPress/Tests/WP/EnqueuedResourceParametersUnitTest.1.inc index 4a73b458d0..3b20ccc5d2 100644 --- a/WordPress/Tests/WP/EnqueuedResourceParametersUnitTest.1.inc +++ b/WordPress/Tests/WP/EnqueuedResourceParametersUnitTest.1.inc @@ -29,7 +29,7 @@ wp_register_script( 'someScript-js', 'https://example.com/someScript.js' , array wp_register_script( 'someScript-js', 'https://example.com/someScript.js' , array( 'jquery' ), function() { }, true ); // OK. wp_register_script( 'someScript-js', 'https://example.com/someScript.js' , array( 'jquery' ), $version, true ); // OK. -wp_register_script( 'someScript-js', 'https://example.com/someScript.js' , array( 'jquery' ), '1.1.0' ); // Warning - In Footer is set to a falsy (default) value. +wp_register_script( 'someScript-js', 'https://example.com/someScript.js' , array( 'jquery' ), '1.1.0' ); // Warning - $in_footer is not explicitly set. wp_register_script( 'someScript-js', 'https://example.com/someScript.js' , array( 'jquery' ), '1.1.0', false ); // OK. wp_register_script( 'someScript-js', 'https://example.com/someScript.js' , array( 'jquery' ), '1.1.0', null ); // OK. wp_register_script( 'someScript-js', 'https://example.com/someScript.js' , array( 'jquery' ), '1.1.0', 0 ); // OK. From c7c7e2d8019701c02b29793d4858f3f6e2431d1f Mon Sep 17 00:00:00 2001 From: Rodrigo Primo Date: Wed, 15 Oct 2025 15:04:32 -0300 Subject: [PATCH 087/105] WP/EnqueuedResourceParameters: fix handling of non-lowercased `null` This commit fixes how the sniff handles non-lowercased `null` when passed as the value of the `$ver` parameter. Now the sniff consistently handles `null` regardless of the case and always returns a warning. Before, it would return a warning only for lower-cased `null` and an error for all other variations of `null`. --- .../WP/EnqueuedResourceParametersSniff.php | 2 +- .../WP/EnqueuedResourceParametersUnitTest.1.inc | 3 +++ .../WP/EnqueuedResourceParametersUnitTest.php | 17 +++++++++-------- 3 files changed, 13 insertions(+), 9 deletions(-) diff --git a/WordPress/Sniffs/WP/EnqueuedResourceParametersSniff.php b/WordPress/Sniffs/WP/EnqueuedResourceParametersSniff.php index 0f92bc3791..a5141c5632 100644 --- a/WordPress/Sniffs/WP/EnqueuedResourceParametersSniff.php +++ b/WordPress/Sniffs/WP/EnqueuedResourceParametersSniff.php @@ -141,7 +141,7 @@ public function process_parameters( $stackPtr, $group_name, $matched_content, $p } } - if ( false === $version_param || 'null' === $version_param['clean'] ) { + if ( false === $version_param || 'null' === strtolower( $version_param['clean'] ) ) { $type = 'script'; if ( strpos( $matched_content, '_style' ) !== false ) { $type = 'style'; diff --git a/WordPress/Tests/WP/EnqueuedResourceParametersUnitTest.1.inc b/WordPress/Tests/WP/EnqueuedResourceParametersUnitTest.1.inc index 3b20ccc5d2..4d9325d16a 100644 --- a/WordPress/Tests/WP/EnqueuedResourceParametersUnitTest.1.inc +++ b/WordPress/Tests/WP/EnqueuedResourceParametersUnitTest.1.inc @@ -95,3 +95,6 @@ wp_register_script( 'someScript-js', 'https://example.com/someScript.js' , array wp_register_script( 'someScript-js', 'https://example.com/someScript.js' , array( 'jquery' ), (double) 0, true ); // Error - 0, false or NULL are not allowed. wp_register_script( 'someScript-js', 'https://example.com/someScript.js' , array( 'jquery' ), (binary) 0, true ); // Error - 0, false or NULL are not allowed. + +// Safeguard handling of non-lowercase `null`. +wp_register_script( 'someScript-js', 'https://example.com/someScript.js' , array( 'jquery' ), NULL, true ); // Warning - 0, false or NULL are not allowed. diff --git a/WordPress/Tests/WP/EnqueuedResourceParametersUnitTest.php b/WordPress/Tests/WP/EnqueuedResourceParametersUnitTest.php index 4273b3f016..df8db0e1de 100644 --- a/WordPress/Tests/WP/EnqueuedResourceParametersUnitTest.php +++ b/WordPress/Tests/WP/EnqueuedResourceParametersUnitTest.php @@ -70,14 +70,15 @@ public function getWarningList( $testFile = '' ) { switch ( $testFile ) { case 'EnqueuedResourceParametersUnitTest.1.inc': return array( - 3 => 2, - 11 => 1, - 32 => 1, - 39 => 2, - 42 => 1, - 45 => 1, - 66 => 2, - 77 => 1, + 3 => 2, + 11 => 1, + 32 => 1, + 39 => 2, + 42 => 1, + 45 => 1, + 66 => 2, + 77 => 1, + 100 => 1, ); default: From 668eed52bafa2127657bc2bce59027f3c0bab2ce Mon Sep 17 00:00:00 2001 From: Rodrigo Primo Date: Mon, 20 Oct 2025 13:40:15 -0300 Subject: [PATCH 088/105] Composer: raise the minimum supported PHPCS version to 3.13.4 This is necessary to benefit from the new way to tokenize fully qualified `\false` and `\null` introduced in 3.13.3 (PHPCSStandards/PHP_CodeSniffer 1206). It will simplify a fix for how `WordPress.WP.EnqueuedResourceParameters` handles fully qualified `\false` and `\null` (see 2630). Bumping the version to 3.13.4 instead of 3.13.3 as 3.13.4 contains a fix to a bug that affected 3.13.3 that prevents WPCS sniffs tests from executing (PHPCSStandards/PHP_CodeSniffer 1213). --- .github/CONTRIBUTING.md | 2 +- composer.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/CONTRIBUTING.md b/.github/CONTRIBUTING.md index 27df074f87..183033f863 100644 --- a/.github/CONTRIBUTING.md +++ b/.github/CONTRIBUTING.md @@ -62,7 +62,7 @@ When you introduce new `public` sniff properties, or your sniff extends a class ### Pre-requisites * WordPress-Coding-Standards -* PHP_CodeSniffer 3.13.0 or higher +* PHP_CodeSniffer 3.13.4 or higher * PHPCSUtils 1.1.0 or higher * PHPCSExtra 1.4.0 or higher * PHPUnit 8.x - 9.x diff --git a/composer.json b/composer.json index a5afb55f6b..6b3abd9d57 100644 --- a/composer.json +++ b/composer.json @@ -21,7 +21,7 @@ "ext-libxml": "*", "ext-tokenizer": "*", "ext-xmlreader": "*", - "squizlabs/php_codesniffer": "^3.13.0", + "squizlabs/php_codesniffer": "^3.13.4", "phpcsstandards/phpcsutils": "^1.1.0", "phpcsstandards/phpcsextra": "^1.4.0" }, From e0dd5d57222ad0856861a5da41d945ef41568e20 Mon Sep 17 00:00:00 2001 From: Rodrigo Primo Date: Thu, 14 Aug 2025 09:20:57 -0300 Subject: [PATCH 089/105] WP/EnqueuedResourceParameters: handle fully qualified `\false` and `\null` correctly Before this change passing `\false` or `\null` as the `$ver` parameter would result in a false negative. --- .../WP/EnqueuedResourceParametersSniff.php | 7 ++-- .../EnqueuedResourceParametersUnitTest.1.inc | 10 ++++++ .../WP/EnqueuedResourceParametersUnitTest.php | 35 ++++++++++--------- 3 files changed, 33 insertions(+), 19 deletions(-) diff --git a/WordPress/Sniffs/WP/EnqueuedResourceParametersSniff.php b/WordPress/Sniffs/WP/EnqueuedResourceParametersSniff.php index a5141c5632..28b4ba8d6b 100644 --- a/WordPress/Sniffs/WP/EnqueuedResourceParametersSniff.php +++ b/WordPress/Sniffs/WP/EnqueuedResourceParametersSniff.php @@ -54,14 +54,15 @@ final class EnqueuedResourceParametersSniff extends AbstractFunctionParameterSni ); /** - * False + the empty tokens array. + * False + T_NS_SEPARATOR + the empty tokens array. * * This array is enriched with the $emptyTokens array in the register() method. * * @var array */ private $false_tokens = array( - \T_FALSE => \T_FALSE, + \T_FALSE => \T_FALSE, + \T_NS_SEPARATOR => \T_NS_SEPARATOR, // Needed to handle fully qualified \false (PHPCS 3.x). ); /** @@ -141,7 +142,7 @@ public function process_parameters( $stackPtr, $group_name, $matched_content, $p } } - if ( false === $version_param || 'null' === strtolower( $version_param['clean'] ) ) { + if ( false === $version_param || strtolower( ltrim( $version_param['clean'], '\\' ) ) === 'null' ) { $type = 'script'; if ( strpos( $matched_content, '_style' ) !== false ) { $type = 'style'; diff --git a/WordPress/Tests/WP/EnqueuedResourceParametersUnitTest.1.inc b/WordPress/Tests/WP/EnqueuedResourceParametersUnitTest.1.inc index 4d9325d16a..03157513e4 100644 --- a/WordPress/Tests/WP/EnqueuedResourceParametersUnitTest.1.inc +++ b/WordPress/Tests/WP/EnqueuedResourceParametersUnitTest.1.inc @@ -98,3 +98,13 @@ wp_register_script( 'someScript-js', 'https://example.com/someScript.js' , array // Safeguard handling of non-lowercase `null`. wp_register_script( 'someScript-js', 'https://example.com/someScript.js' , array( 'jquery' ), NULL, true ); // Warning - 0, false or NULL are not allowed. + +/* + * Safeguard handling of fully qualified \true, \false and \null. + * Also safeguard that adding T_NS_SEPARATOR to $false_tokens doesn't cause false positives due to problems in is_falsy(). + */ +wp_register_script( 'someScript-js', 'https://example.com/someScript.js' , array( 'jquery' ), \FALSE, \true ); // Error - 0, false or NULL are not allowed. +wp_register_script( 'someScript-js', 'https://example.com/someScript.js' , array( 'jquery' ), \null, \TRUE ); // Warning - 0, false or NULL are not allowed. +wp_register_script( 'someScript-js', 'https://example.com/someScript.js' , array( 'jquery' ), \Null, true ); // Warning - 0, false or NULL are not allowed. +wp_register_script( 'someScript-js', 'https://example.com/someScript.js' , array( 'jquery' ), \true, \False ); // Ok. +wp_register_script( 'someScript-js', 'https://example.com/someScript.js' , array( 'jquery' ), \get_version(), \null ); // OK. diff --git a/WordPress/Tests/WP/EnqueuedResourceParametersUnitTest.php b/WordPress/Tests/WP/EnqueuedResourceParametersUnitTest.php index df8db0e1de..eaa719c19b 100644 --- a/WordPress/Tests/WP/EnqueuedResourceParametersUnitTest.php +++ b/WordPress/Tests/WP/EnqueuedResourceParametersUnitTest.php @@ -31,22 +31,23 @@ public function getErrorList( $testFile = '' ) { switch ( $testFile ) { case 'EnqueuedResourceParametersUnitTest.1.inc': return array( - 6 => 1, - 9 => 1, - 10 => 1, - 12 => 1, - 13 => 1, - 14 => 1, - 22 => 1, - 54 => 1, - 57 => 1, - 61 => 1, - 82 => 1, - 85 => 1, - 89 => 1, - 92 => 1, - 95 => 1, - 97 => 1, + 6 => 1, + 9 => 1, + 10 => 1, + 12 => 1, + 13 => 1, + 14 => 1, + 22 => 1, + 54 => 1, + 57 => 1, + 61 => 1, + 82 => 1, + 85 => 1, + 89 => 1, + 92 => 1, + 95 => 1, + 97 => 1, + 106 => 1, ); case 'EnqueuedResourceParametersUnitTest.2.inc': @@ -79,6 +80,8 @@ public function getWarningList( $testFile = '' ) { 66 => 2, 77 => 1, 100 => 1, + 107 => 1, + 108 => 1, ); default: From 282727a8ff9df986cbb151411d8085647cb1cbb7 Mon Sep 17 00:00:00 2001 From: Rodrigo Primo Date: Thu, 7 Aug 2025 09:03:02 -0300 Subject: [PATCH 090/105] DB/DirectDatabaseQuery: add tests for namespaced names --- .../DB/DirectDatabaseQueryUnitTest.1.inc | 98 ++++++++++++++++++- .../Tests/DB/DirectDatabaseQueryUnitTest.php | 10 ++ 2 files changed, 107 insertions(+), 1 deletion(-) diff --git a/WordPress/Tests/DB/DirectDatabaseQueryUnitTest.1.inc b/WordPress/Tests/DB/DirectDatabaseQueryUnitTest.1.inc index 1a6be76a5a..517cf56476 100644 --- a/WordPress/Tests/DB/DirectDatabaseQueryUnitTest.1.inc +++ b/WordPress/Tests/DB/DirectDatabaseQueryUnitTest.1.inc @@ -93,7 +93,7 @@ function cache_add_instead_of_set() { $b = function () { global $wpdb; - if ( ! ( $listofthings = wp_cache_get( $foo ) ) ) { + if ( ! ( $listofthings = \Wp_Cache_Get( $foo ) ) ) { $listofthings = $wpdb->get_col( 'SELECT something FROM somewhere WHERE someotherthing = 1' ); // Warning. wp_cache_set( 'foo', $listofthings ); } @@ -379,3 +379,99 @@ function methodNamesSameAsCacheFunctions() { return $listofthings; } + +/* + * Safeguard correct handling of namespaced function calls. The sniff deliberately does not distinguish between calls to + * WP global cache functions and calls to namespaced functions that mirror the name of the WP global cache functions as + * those are likely custom cache functions. This is consistent with the behavior for method calls (see the + * methodNamesSameAsCacheFunctions() test above). + */ +function callToFullyQualifiedCacheGetSet() { + global $wpdb; + + if ( ! ( $listofthings = \wp_cache_get( $foo ) ) ) { + $listofthings = $wpdb->get_col( 'SELECT something FROM somewhere WHERE someotherthing = 1' ); // Warning direct DB call. + \wp_cache_set( 'foo', $listofthings ); + } + + return $listofthings; +} + +function callToQualifiedNamespacedCacheGetSet() { + global $wpdb; + + if ( ! ( $listofthings = MyNamespace\wp_cache_get( $foo ) ) ) { + $listofthings = $wpdb->get_col( 'SELECT something FROM somewhere WHERE someotherthing = 1' ); // Warning direct DB call. + MyNamespace\wp_cache_add( 'foo', $listofthings ); + } + + return $listofthings; +} + +function callToFullyQualifiedNamespacedCacheGetSet() { + global $wpdb; + + if ( ! ( $listofthings = \MyNamespace\wp_cache_get( $foo ) ) ) { + $listofthings = $wpdb->get_col( 'SELECT something FROM somewhere WHERE someotherthing = 1' ); // Warning direct DB call. + \MyNamespace\wp_cache_set( 'foo', $listofthings ); + } + + return $listofthings; +} + +function callToRelativeNamespacedCacheGetSet() { + global $wpdb; + + if ( ! ( $listofthings = namespace\wp_cache_get( $foo ) ) ) { + $listofthings = $wpdb->get_col( 'SELECT something FROM somewhere WHERE someotherthing = 1' ); // Warning direct DB call. + namespace\wp_cache_add( 'foo', $listofthings ); + } + + return $listofthings; +} + +function callToMultiLevelNamespaceRelativeCacheGetSet() { + global $wpdb; + + if ( ! ( $listofthings = namespace\Sub\wp_cache_get( $foo ) ) ) { + $listofthings = $wpdb->get_col( 'SELECT something FROM somewhere WHERE someotherthing = 1' ); // Warning direct DB call. + namespace\Sub\wp_cache_set( 'foo', $listofthings ); + } + + return $listofthings; +} + +function callToFullyQualifiedCacheDelete() { + global $wpdb; + + $wpdb->query( 'SELECT X FROM Y' ); // Warning direct DB call. + \wp_cache_delete( 'key', 'group' ); +} + +function callToQualifiedNamespacedCacheDelete() { + global $wpdb; + + $wpdb->query( 'SELECT X FROM Y' ); // Warning direct DB call. + MyNamespace\clean_attachment_cache( 1 ); +} + +function callToFullyQualifiedNamespacedCacheDelete() { + global $wpdb; + + $wpdb->query( 'SELECT X FROM Y' ); // Warning direct DB call. + \MyNamespace\CLEAN_POST_CACHE( 1 ); +} + +function callToRelativeNamespacedCacheDelete() { + global $wpdb; + + $wpdb->query( 'SELECT X FROM Y' ); // Warning direct DB call. + namespace\clean_user_cache( 1 ); +} + +function callToMultiLevelNamespaceRelativeCacheDelete() { + global $wpdb; + + $wpdb->query( 'SELECT X FROM Y' ); // Warning direct DB call. + namespace\Sub\clean_blog_cache( 1 ); +} diff --git a/WordPress/Tests/DB/DirectDatabaseQueryUnitTest.php b/WordPress/Tests/DB/DirectDatabaseQueryUnitTest.php index e43fbb126b..709d66c0e6 100644 --- a/WordPress/Tests/DB/DirectDatabaseQueryUnitTest.php +++ b/WordPress/Tests/DB/DirectDatabaseQueryUnitTest.php @@ -99,6 +99,16 @@ public function getWarningList( $testFile = '' ) { 350 => 1, 364 => 2, 376 => 1, + 393 => 1, + 404 => 1, + 415 => 1, + 426 => 1, + 437 => 1, + 447 => 1, + 454 => 1, + 461 => 1, + 468 => 1, + 475 => 1, ); default: return array(); From 08c3d1b31e768602303d60897c68a711853dc916 Mon Sep 17 00:00:00 2001 From: jrfnl Date: Sun, 16 Nov 2025 05:30:07 +0100 Subject: [PATCH 091/105] Composer: update to PHPCSExtra 1.5.0 PHPCSExtra 1.5.0 has been released and offers 7 new sniffs, some of which we may want to use. Ref: https://github.com/PHPCSStandards/PHPCSExtra/releases/tag/1.5.0 --- .github/CONTRIBUTING.md | 2 +- composer.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/CONTRIBUTING.md b/.github/CONTRIBUTING.md index 183033f863..337db8e8fa 100644 --- a/.github/CONTRIBUTING.md +++ b/.github/CONTRIBUTING.md @@ -64,7 +64,7 @@ When you introduce new `public` sniff properties, or your sniff extends a class * WordPress-Coding-Standards * PHP_CodeSniffer 3.13.4 or higher * PHPCSUtils 1.1.0 or higher -* PHPCSExtra 1.4.0 or higher +* PHPCSExtra 1.5.0 or higher * PHPUnit 8.x - 9.x The WordPress Coding Standards use the `PHP_CodeSniffer` native unit test framework for unit testing the sniffs. diff --git a/composer.json b/composer.json index 6b3abd9d57..870a89a1b3 100644 --- a/composer.json +++ b/composer.json @@ -23,7 +23,7 @@ "ext-xmlreader": "*", "squizlabs/php_codesniffer": "^3.13.4", "phpcsstandards/phpcsutils": "^1.1.0", - "phpcsstandards/phpcsextra": "^1.4.0" + "phpcsstandards/phpcsextra": "^1.5.0" }, "require-dev": { "phpcompatibility/php-compatibility": "^9.0", From 2be483c4cf0a56521d0a738bce61dbf402df1bef Mon Sep 17 00:00:00 2001 From: jrfnl Date: Sun, 16 Nov 2025 05:41:22 +0100 Subject: [PATCH 092/105] WordPress-Extra: add some sniffs related to attribute formatting It's common for code to contain PHP 8.0 attributes, even if the code still needs to run on PHP < 8.0 as attributes are cross-version compatible in the sense that they won't cause parse errors on older PHP versions but will be seen as a comment. WordPress Core at this moment contains 193 attributes in 156 files. https://github.com/search?q=repo%3AWordPress%2Fwordpress-develop+%23%5B&type=code With this in mind, it makes sense to start adding some rules related to attributes formatting to WordPress-Extra. These rules should eventually be moved to WordPress-Core after a Make post. PHPCSExtra is starting to add some sniffs for attribute formatting. Though the set is nowhere near complete yet, these initial two sniffs should make a good addition for WPCS. * The `Universal.Attributes.BracketSpacing` demands no spacing on the inside of attribute brackets. While this may seem inconsistent with the otherwise space-richness of WordPressCS, if we look at prior art in WordPress Core, all attributes currently in WordPress Core comply with the "no spacing inside of the brackets" rule. This means that if/when the rule would move to the WordPress-Core ruleset, no code churn is expected as no fixes will be needed. * The `Universal.Attributes.DisallowAttributeParentheses` demands that attribute instantiations only have parentheses when parameters are passed. Again, this is 100% in line with prior art in WordPress Core. As a side-note: both the above rules are also in line with PERCS, which means that they don't raise the barrier to entry for new contributors to WordPress. --- WordPress-Extra/ruleset.xml | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/WordPress-Extra/ruleset.xml b/WordPress-Extra/ruleset.xml index f2b1b9e5ba..a939d1eb95 100644 --- a/WordPress-Extra/ruleset.xml +++ b/WordPress-Extra/ruleset.xml @@ -202,4 +202,10 @@ + + + + + + From efc55822e333b7cdbdbfc4673c5386c08567ca60 Mon Sep 17 00:00:00 2001 From: jrfnl Date: Tue, 18 Nov 2025 18:48:35 +0100 Subject: [PATCH 093/105] GH Actions: update for the release of PHP 8.5 ... which is expected to be released this Thursday. * Builds against PHP 8.5 are no longer allowed to fail. * Update PHP version on which code coverage is run (high should now be 8.5). * Add _allowed to fail_ build against PHP 8.6. * Update "tested against" badge in the README. --- .github/workflows/unit-tests.yml | 10 +++++----- README.md | 2 +- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/.github/workflows/unit-tests.yml b/.github/workflows/unit-tests.yml index cda909983b..443f6e3ccb 100644 --- a/.github/workflows/unit-tests.yml +++ b/.github/workflows/unit-tests.yml @@ -26,7 +26,7 @@ jobs: runs-on: ubuntu-latest strategy: matrix: - php: [ '7.3', '7.4', '8.0', '8.1', '8.2', '8.3', '8.5' ] + php: [ '7.3', '7.4', '8.0', '8.1', '8.2', '8.3', '8.4', '8.6' ] dependencies: [ 'lowest', 'stable' ] extensions: [ '' ] coverage: [false] @@ -41,11 +41,11 @@ jobs: dependencies: 'lowest' extensions: '' coverage: true - - php: '8.4' + - php: '8.5' dependencies: 'stable' extensions: '' coverage: true - - php: '8.4' + - php: '8.5' dependencies: 'lowest' extensions: '' coverage: true @@ -59,7 +59,7 @@ jobs: dependencies: 'dev' extensions: '' coverage: false - - php: '8.4' + - php: '8.5' dependencies: 'dev' extensions: '' coverage: false @@ -70,7 +70,7 @@ jobs: name: PHP ${{ matrix.php }} on PHPCS ${{ matrix.dependencies }} - continue-on-error: ${{ matrix.php == '8.5' }} + continue-on-error: ${{ matrix.php == '8.6' }} steps: - name: Checkout repository diff --git a/README.md b/README.md index 6cefe96d81..5ebe6c660c 100644 --- a/README.md +++ b/README.md @@ -10,7 +10,7 @@ [![codecov.io](https://codecov.io/gh/WordPress/WordPress-Coding-Standards/graph/badge.svg?token=UzFYn0RzVG&branch=develop)](https://codecov.io/gh/WordPress/WordPress-Coding-Standards?branch=develop) [![Minimum PHP Version](https://img.shields.io/packagist/php-v/wp-coding-standards/wpcs.svg?maxAge=3600)](https://packagist.org/packages/wp-coding-standards/wpcs) -[![Tested on PHP 7.2 to 8.4](https://img.shields.io/badge/tested%20on-PHP%207.2%20|%207.3%20|%207.4%20|%208.0%20|%208.1%20|%208.2%20|%208.3%20|%208.4-green.svg?maxAge=2419200)](https://github.com/WordPress/WordPress-Coding-Standards/actions/workflows/unit-tests.yml) +[![Tested on PHP 7.2 to 8.5](https://img.shields.io/badge/tested%20on-PHP%207.2%20|%207.3%20|%207.4%20|%208.0%20|%208.1%20|%208.2%20|%208.3%20|%208.4%20|%208.5-green.svg?maxAge=2419200)](https://github.com/WordPress/WordPress-Coding-Standards/actions/workflows/unit-tests.yml) [![License: MIT](https://poser.pugx.org/wp-coding-standards/wpcs/license)](https://github.com/WordPress/WordPress-Coding-Standards/blob/develop/LICENSE) [![Total Downloads](https://poser.pugx.org/wp-coding-standards/wpcs/downloads)](https://packagist.org/packages/wp-coding-standards/wpcs/stats) From f2a4a1c976c6b85d35f27c4bfc10a036d48ac7aa Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 18 Nov 2025 18:06:52 +0000 Subject: [PATCH 094/105] GH Actions: Bump the action-runners group with 2 updates Bumps the action-runners group with 2 updates: [actions/checkout](https://github.com/actions/checkout) and [crate-ci/typos](https://github.com/crate-ci/typos). Updates `actions/checkout` from 5.0.0 to 5.0.1 - [Release notes](https://github.com/actions/checkout/releases) - [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md) - [Commits](https://github.com/actions/checkout/compare/08c6903cd8c0fde910a37f88322edcfb5dd907a8...93cb6efe18208431cddfb8368fd83d5badbf9bfd) Updates `crate-ci/typos` from 1.39.0 to 1.39.2 - [Release notes](https://github.com/crate-ci/typos/releases) - [Changelog](https://github.com/crate-ci/typos/blob/master/CHANGELOG.md) - [Commits](https://github.com/crate-ci/typos/compare/07d900b8fa1097806b8adb6391b0d3e0ac2fdea7...626c4bedb751ce0b7f03262ca97ddda9a076ae1c) --- updated-dependencies: - dependency-name: actions/checkout dependency-version: 5.0.1 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: action-runners - dependency-name: crate-ci/typos dependency-version: 1.39.2 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: action-runners ... Signed-off-by: dependabot[bot] --- .github/workflows/basic-qa.yml | 12 ++++++------ .github/workflows/quicktest.yml | 2 +- .github/workflows/unit-tests.yml | 2 +- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/.github/workflows/basic-qa.yml b/.github/workflows/basic-qa.yml index b587ee2aec..4a5acbdc0c 100644 --- a/.github/workflows/basic-qa.yml +++ b/.github/workflows/basic-qa.yml @@ -26,7 +26,7 @@ jobs: steps: - name: Checkout repository - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 + uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd # v5.0.1 with: persist-credentials: false @@ -117,7 +117,7 @@ jobs: steps: - name: Checkout code - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 + uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd # v5.0.1 with: persist-credentials: false @@ -157,7 +157,7 @@ jobs: steps: - name: Checkout repository - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 + uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd # v5.0.1 with: persist-credentials: false @@ -240,7 +240,7 @@ jobs: steps: - name: Checkout code - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 + uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd # v5.0.1 with: persist-credentials: false @@ -270,9 +270,9 @@ jobs: steps: - name: "Checkout" - uses: "actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8" # v5.0.0 + uses: "actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd" # v5.0.1 with: persist-credentials: false - name: "Search for misspellings" - uses: "crate-ci/typos@07d900b8fa1097806b8adb6391b0d3e0ac2fdea7" # v1.39.0 + uses: "crate-ci/typos@626c4bedb751ce0b7f03262ca97ddda9a076ae1c" # v1.39.2 diff --git a/.github/workflows/quicktest.yml b/.github/workflows/quicktest.yml index 5cf6b0fa03..7139b1d536 100644 --- a/.github/workflows/quicktest.yml +++ b/.github/workflows/quicktest.yml @@ -30,7 +30,7 @@ jobs: steps: - name: Checkout repository - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 + uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd # v5.0.1 with: persist-credentials: false diff --git a/.github/workflows/unit-tests.yml b/.github/workflows/unit-tests.yml index cda909983b..f8942cbb6e 100644 --- a/.github/workflows/unit-tests.yml +++ b/.github/workflows/unit-tests.yml @@ -74,7 +74,7 @@ jobs: steps: - name: Checkout repository - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 + uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd # v5.0.1 with: persist-credentials: false From a54427a16c998ae295694e6e620178b4f5ae5013 Mon Sep 17 00:00:00 2001 From: jrfnl Date: Sun, 23 Nov 2025 03:56:17 +0100 Subject: [PATCH 095/105] CS: start using PHPCompatibility 10 Long anticipated, finally here: PHPCompatibility 10.0.0-alpha1 :tada: PHPCompatibility 10.0.0 brings huge improvements in both what is being detected (> 50 new sniffs), as well as the detection accuracy for pre-existing sniffs. Even though still "unstable", it is stable enough for our purposes and the advantages of using it outweigh the disadvantage of it being an unstable version. By setting the `minimum-stability` and `prefer-stable` settings in the `composer.json`, we can ensure that we don't get the `dev-develop` branch, but rather get a `10.0.0` tag, unstable or not. And what with the improved detection, a number of new PHP token constants previously not flagged, are now flagged, so let's ignore them as PHPCS polyfills these. Ref: * https://github.com/PHPCompatibility/PHPCompatibility/wiki/Upgrading-to-PHPCompatibility-10.0 * https://github.com/PHPCompatibility/PHPCompatibility/releases/tag/10.0.0-alpha1 --- .phpcs.xml.dist | 13 +++++++++++++ composer.json | 4 +++- 2 files changed, 16 insertions(+), 1 deletion(-) diff --git a/.phpcs.xml.dist b/.phpcs.xml.dist index ed1ea01065..b14c3862b0 100644 --- a/.phpcs.xml.dist +++ b/.phpcs.xml.dist @@ -57,7 +57,20 @@ + + + + + + + + + + + + + diff --git a/composer.json b/composer.json index 870a89a1b3..898bf88b73 100644 --- a/composer.json +++ b/composer.json @@ -26,7 +26,7 @@ "phpcsstandards/phpcsextra": "^1.5.0" }, "require-dev": { - "phpcompatibility/php-compatibility": "^9.0", + "phpcompatibility/php-compatibility": "^10.0.0@dev", "phpunit/phpunit": "^8.0 || ^9.0", "phpcsstandards/phpcsdevtools": "^1.2.0", "php-parallel-lint/php-parallel-lint": "^1.4.0", @@ -36,6 +36,8 @@ "ext-iconv": "For improved results", "ext-mbstring": "For improved results" }, + "minimum-stability": "dev", + "prefer-stable": true, "config": { "allow-plugins": { "dealerdirect/phpcodesniffer-composer-installer": true From b207c17edf61235368e136a38e2a2129a7d6c582 Mon Sep 17 00:00:00 2001 From: jrfnl Date: Sun, 23 Nov 2025 10:56:59 +0100 Subject: [PATCH 096/105] NamingConventions/PrefixAllGlobals: update the functions list based on WP 6.9.0-RC2 Based on a scan of WP Core at commit WordPress/wordpress-develop@87e656 using a preliminary sniff created for issue 1803. --- .../NamingConventions/PrefixAllGlobalsSniff.php | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/WordPress/Sniffs/NamingConventions/PrefixAllGlobalsSniff.php b/WordPress/Sniffs/NamingConventions/PrefixAllGlobalsSniff.php index 686075042c..fb5b1bdb02 100644 --- a/WordPress/Sniffs/NamingConventions/PrefixAllGlobalsSniff.php +++ b/WordPress/Sniffs/NamingConventions/PrefixAllGlobalsSniff.php @@ -149,7 +149,7 @@ final class PrefixAllGlobalsSniff extends AbstractFunctionParameterSniff { * Only overrulable constants are listed, i.e. those defined within core within * a `if ( ! defined() ) {}` wrapper. * - * {@internal To be updated after every major release. Last updated for WordPress 6.8.1.} + * {@internal To be updated after every major release. Last updated for WordPress 6.9.0-RC2.} * * @since 1.0.0 * @since 3.0.0 Renamed from `$whitelisted_core_constants` to `$allowed_core_constants`. @@ -203,7 +203,7 @@ final class PrefixAllGlobalsSniff extends AbstractFunctionParameterSniff { * * Note: deprecated functions should still be included in this list as plugins may support older WP versions. * - * {@internal To be updated after every major release. Last updated for WordPress 6.8.1.} + * {@internal To be updated after every major release. Last updated for WordPress 6.9.0-RC2.} * * @since 3.0.0. * @@ -342,7 +342,11 @@ final class PrefixAllGlobalsSniff extends AbstractFunctionParameterSniff { 'wp_cache_flush_group' => true, 'wp_cache_flush_runtime' => true, 'wp_cache_get_multiple' => true, + 'wp_cache_get_multiple_salted' => true, + 'wp_cache_get_salted' => true, 'wp_cache_set_multiple' => true, + 'wp_cache_set_multiple_salted' => true, + 'wp_cache_set_salted' => true, 'wp_cache_supports' => true, 'wp_check_password' => true, 'wp_clear_auth_cookie' => true, @@ -392,7 +396,7 @@ final class PrefixAllGlobalsSniff extends AbstractFunctionParameterSniff { * * Note: deprecated classes should still be included in this list as plugins may support older WP versions. * - * {@internal To be updated after every major release. Last updated for WordPress 6.8.1.} + * {@internal To be updated after every major release. Last updated for WordPress 6.9.0-RC2.} * * @since 3.0.0. * @@ -407,6 +411,7 @@ final class PrefixAllGlobalsSniff extends AbstractFunctionParameterSniff { 'TwentyTwenty_Walker_Comment' => true, 'TwentyTwenty_Walker_Page' => true, 'Twenty_Twenty_One_Customize' => true, + 'WP_Block_Cloner' => true, 'WP_User_Search' => true, 'wp_atom_server' => true, // Deprecated. ); From 5bb8db0e577b8aeeebdcf402ccda7d034e252ebb Mon Sep 17 00:00:00 2001 From: jrfnl Date: Sun, 23 Nov 2025 11:57:24 +0100 Subject: [PATCH 097/105] WP/ClassNameCase: update the class lists based on WP 6.9.0-RC2 Based on a scan of WP Core at commit WordPress/wordpress-develop@87e656 using a preliminary sniff created for issue 1803. --- WordPress/Sniffs/WP/ClassNameCaseSniff.php | 37 ++++++++++++++++++---- 1 file changed, 30 insertions(+), 7 deletions(-) diff --git a/WordPress/Sniffs/WP/ClassNameCaseSniff.php b/WordPress/Sniffs/WP/ClassNameCaseSniff.php index 1c3ce88f24..ef8170e275 100644 --- a/WordPress/Sniffs/WP/ClassNameCaseSniff.php +++ b/WordPress/Sniffs/WP/ClassNameCaseSniff.php @@ -25,7 +25,7 @@ final class ClassNameCaseSniff extends AbstractClassRestrictionsSniff { * * Note: this list will be enhanced in the class constructor. * - * {@internal To be updated after every major release. Last updated for WordPress 6.8.1.} + * {@internal To be updated after every major release. Last updated for WordPress 6.9.0-RC2.} * * @since 3.0.0 * @@ -115,6 +115,10 @@ final class ClassNameCaseSniff extends AbstractClassRestrictionsSniff { 'Walker_Page', 'Walker_PageDropdown', 'WP', + 'WP_Abilities_Registry', + 'WP_Ability', + 'WP_Ability_Categories_Registry', + 'WP_Ability_Category', 'WP_Admin_Bar', 'WP_Ajax_Response', 'WP_Ajax_Upgrader_Skin', @@ -124,6 +128,7 @@ final class ClassNameCaseSniff extends AbstractClassRestrictionsSniff { 'WP_Block', 'WP_Block_Bindings_Registry', 'WP_Block_Bindings_Source', + 'WP_Block_Cloner', 'WP_Block_Editor_Context', 'WP_Block_List', 'WP_Block_Metadata_Registry', @@ -132,6 +137,7 @@ final class ClassNameCaseSniff extends AbstractClassRestrictionsSniff { 'WP_Block_Parser_Frame', 'WP_Block_Pattern_Categories_Registry', 'WP_Block_Patterns_Registry', + 'WP_Block_Processor', 'WP_Block_Styles_Registry', 'WP_Block_Supports', 'WP_Block_Template', @@ -269,6 +275,9 @@ final class ClassNameCaseSniff extends AbstractClassRestrictionsSniff { 'WP_Privacy_Policy_Content', 'WP_Privacy_Requests_Table', 'WP_Query', + 'WP_REST_Abilities_V1_Categories_Controller', + 'WP_REST_Abilities_V1_List_Controller', + 'WP_REST_Abilities_V1_Run_Controller', 'WP_REST_Application_Passwords_Controller', 'WP_REST_Attachments_Controller', 'WP_REST_Autosaves_Controller', @@ -423,7 +432,7 @@ final class ClassNameCaseSniff extends AbstractClassRestrictionsSniff { * * Note: this list will be enhanced in the class constructor. * - * {@internal To be updated after every major release. Last updated for WordPress 6.8.1.} + * {@internal To be updated after every major release. Last updated for WordPress 6.9.0-RC2.} * * @since 3.0.0 * @@ -455,7 +464,7 @@ final class ClassNameCaseSniff extends AbstractClassRestrictionsSniff { * * Note: this list will be enhanced in the class constructor. * - * {@internal To be updated after every major release. Last updated for WordPress 6.8.1.} + * {@internal To be updated after every major release. Last updated for WordPress 6.9.0-RC2.} * * @since 3.1.0 * @@ -477,7 +486,7 @@ final class ClassNameCaseSniff extends AbstractClassRestrictionsSniff { * * Note: this list will be enhanced in the class constructor. * - * {@internal To be updated after every major release. Last updated for WordPress 6.8.1.} + * {@internal To be updated after every major release. Last updated for WordPress 6.9.0-RC2.} * * @since 3.0.0 * @@ -513,7 +522,7 @@ final class ClassNameCaseSniff extends AbstractClassRestrictionsSniff { * * Note: this list will be enhanced in the class constructor. * - * {@internal To be updated after every major release. Last updated for WordPress 6.8.1.} + * {@internal To be updated after every major release. Last updated for WordPress 6.9.0-RC2.} * * @since 3.0.0 * @@ -521,9 +530,16 @@ final class ClassNameCaseSniff extends AbstractClassRestrictionsSniff { * The constructor will add the lowercased class name as a key to each entry. */ private $phpmailer_classes = array( + // Classes. + 'PHPMailer\\PHPMailer\\DSNConfigurator', 'PHPMailer\\PHPMailer\\Exception', + 'PHPMailer\\PHPMailer\\OAuth', 'PHPMailer\\PHPMailer\\PHPMailer', + 'PHPMailer\\PHPMailer\\POP3', 'PHPMailer\\PHPMailer\\SMTP', + + // Interfaces. + 'PHPMailer\\PHPMailer\\OAuthTokenProvider', ); /** @@ -531,7 +547,7 @@ final class ClassNameCaseSniff extends AbstractClassRestrictionsSniff { * * Note: this list will be enhanced in the class constructor. * - * {@internal To be updated after every major release. Last updated for WordPress 6.8.1.} + * {@internal To be updated after every major release. Last updated for WordPress 6.9.0-RC2.} * * @since 3.0.0 * @@ -675,7 +691,7 @@ final class ClassNameCaseSniff extends AbstractClassRestrictionsSniff { * * Note: this list will be enhanced in the class constructor. * - * {@internal To be updated after every major release. Last updated for WordPress 6.8.1.} + * {@internal To be updated after every major release. Last updated for WordPress 6.9.0-RC2.} * * @since 3.0.0 * @@ -690,6 +706,8 @@ final class ClassNameCaseSniff extends AbstractClassRestrictionsSniff { 'SimplePie\Cache\Base', 'SimplePie\Cache\DataCache', 'SimplePie\Cache\NameFilter', + 'SimplePie\HTTP\Client', + 'SimplePie\HTTP\Response', 'SimplePie\RegistryAware', // Classes, SimplePie v1. @@ -750,7 +768,12 @@ final class ClassNameCaseSniff extends AbstractClassRestrictionsSniff { 'SimplePie\Exception', 'SimplePie\File', 'SimplePie\Gzdecode', + 'SimplePie\HTTP\ClientException', + 'SimplePie\HTTP\FileClient', 'SimplePie\HTTP\Parser', + 'SimplePie\HTTP\Psr7Response', + 'SimplePie\HTTP\Psr18Client', + 'SimplePie\HTTP\RawTextResponse', 'SimplePie\IRI', 'SimplePie\Item', 'SimplePie\Locator', From 48a519f4c20e9aacb9602eb7904da3f2506d3a85 Mon Sep 17 00:00:00 2001 From: jrfnl Date: Sun, 23 Nov 2025 12:29:14 +0100 Subject: [PATCH 098/105] WP/DeprecatedFunctions: update the functions list based on WP 6.9.0-RC2 Based on a scan of WP Core at commit WordPress/wordpress-develop@87e656 using a preliminary sniff created for issue 1803. Includes tests. --- WordPress/Sniffs/WP/DeprecatedFunctionsSniff.php | 14 +++++++++++++- .../Tests/WP/DeprecatedFunctionsUnitTest.1.inc | 3 +++ WordPress/Tests/WP/DeprecatedFunctionsUnitTest.php | 5 +++-- 3 files changed, 19 insertions(+), 3 deletions(-) diff --git a/WordPress/Sniffs/WP/DeprecatedFunctionsSniff.php b/WordPress/Sniffs/WP/DeprecatedFunctionsSniff.php index 745b9ea206..6b74d6294b 100644 --- a/WordPress/Sniffs/WP/DeprecatedFunctionsSniff.php +++ b/WordPress/Sniffs/WP/DeprecatedFunctionsSniff.php @@ -43,7 +43,7 @@ final class DeprecatedFunctionsSniff extends AbstractFunctionRestrictionsSniff { * To retrieve a function list for comparison, the following tool is available: * https://github.com/JDGrimes/wp-deprecated-code-scanner * - * {@internal To be updated after every major release. Last updated for WordPress 6.8.1.} + * {@internal To be updated after every major release. Last updated for WordPress 6.9.0-RC2.} * * @var array */ @@ -1708,6 +1708,18 @@ final class DeprecatedFunctionsSniff extends AbstractFunctionRestrictionsSniff { 'alt' => 'wp_enqueue_classic_theme_styles()', 'version' => '6.8.0', ), + + // WP 6.9.0. + // Note: the deprecation of the (polyfilled) `utf8_encode()` and `utf8_decode()` functions is deliberately + // not listed here as these are polyfills for the PHP native functions, not WP native functions. + 'seems_utf8' => array( + 'alt' => 'wp_is_valid_utf8()', + 'version' => '6.9.0', + ), + 'wp_print_auto_sizes_contain_css_fix' => array( + 'alt' => 'wp_enqueue_img_auto_sizes_contain_css_fix()', + 'version' => '6.9.0', + ), ); /** diff --git a/WordPress/Tests/WP/DeprecatedFunctionsUnitTest.1.inc b/WordPress/Tests/WP/DeprecatedFunctionsUnitTest.1.inc index 5d8281d6cb..4abf47c46d 100644 --- a/WordPress/Tests/WP/DeprecatedFunctionsUnitTest.1.inc +++ b/WordPress/Tests/WP/DeprecatedFunctionsUnitTest.1.inc @@ -441,3 +441,6 @@ wp_targeted_link_rel(); wp_targeted_link_rel_callback(); /* ============ WP 6.8 ============ */ wp_add_editor_classic_theme_styles(); +/* ============ WP 6.9 ============ */ +seems_utf8(); +wp_print_auto_sizes_contain_css_fix(); diff --git a/WordPress/Tests/WP/DeprecatedFunctionsUnitTest.php b/WordPress/Tests/WP/DeprecatedFunctionsUnitTest.php index fb53e37231..7813bede2d 100644 --- a/WordPress/Tests/WP/DeprecatedFunctionsUnitTest.php +++ b/WordPress/Tests/WP/DeprecatedFunctionsUnitTest.php @@ -110,14 +110,15 @@ public function getWarningList( $testFile = '' ) { switch ( $testFile ) { case 'DeprecatedFunctionsUnitTest.1.inc': $start_line = 426; - $end_line = 443; + $end_line = 446; $warnings = array_fill( $start_line, ( ( $end_line - $start_line ) + 1 ), 1 ); // Unset the lines related to version comments. unset( $warnings[429], $warnings[432], - $warnings[442] + $warnings[442], + $warnings[444] ); return $warnings; From 75539a4b2754883d61961f75ac49b4253c2b6db9 Mon Sep 17 00:00:00 2001 From: jrfnl Date: Sun, 23 Nov 2025 12:37:14 +0100 Subject: [PATCH 099/105] WP/DeprecatedParameters: update the functions list based on WP 6.9.0-RC2 Based on a scan of WP Core at commit WordPress/wordpress-develop@87e656 using a preliminary sniff created for issue 1803. Includes tests. --- WordPress/Sniffs/WP/DeprecatedParametersSniff.php | 9 ++++++++- WordPress/Tests/WP/DeprecatedParametersUnitTest.inc | 1 + WordPress/Tests/WP/DeprecatedParametersUnitTest.php | 1 + 3 files changed, 10 insertions(+), 1 deletion(-) diff --git a/WordPress/Sniffs/WP/DeprecatedParametersSniff.php b/WordPress/Sniffs/WP/DeprecatedParametersSniff.php index 9db68986e3..265035f249 100644 --- a/WordPress/Sniffs/WP/DeprecatedParametersSniff.php +++ b/WordPress/Sniffs/WP/DeprecatedParametersSniff.php @@ -50,7 +50,7 @@ final class DeprecatedParametersSniff extends AbstractFunctionParameterSniff { * * The functions are ordered alphabetically. * - * {@internal To be updated after every major release. Last updated for WordPress 6.8.1.} + * {@internal To be updated after every major release. Last updated for WordPress 6.9.0-RC2.} * * @since 0.12.0 * @@ -86,6 +86,13 @@ final class DeprecatedParametersSniff extends AbstractFunctionParameterSniff { 'version' => '5.9.0', ), ), + '_wp_can_use_pcre_u' => array( + 1 => array( + 'name' => 'set', + 'value' => null, + 'version' => '6.9.0', + ), + ), '_wp_post_revision_fields' => array( 2 => array( 'name' => 'deprecated', diff --git a/WordPress/Tests/WP/DeprecatedParametersUnitTest.inc b/WordPress/Tests/WP/DeprecatedParametersUnitTest.inc index 1fc0c27b04..027a2a47cc 100644 --- a/WordPress/Tests/WP/DeprecatedParametersUnitTest.inc +++ b/WordPress/Tests/WP/DeprecatedParametersUnitTest.inc @@ -99,3 +99,4 @@ global_terms( $foo, 'deprecated' ); // All will give an WARNING as they have been deprecated after WP 6.5. inject_ignored_hooked_blocks_metadata_attributes('', 'deprecated'); wp_render_elements_support_styles('deprecated'); +_wp_can_use_pcre_u('deprecated'); diff --git a/WordPress/Tests/WP/DeprecatedParametersUnitTest.php b/WordPress/Tests/WP/DeprecatedParametersUnitTest.php index 3d516ec983..5d120db624 100644 --- a/WordPress/Tests/WP/DeprecatedParametersUnitTest.php +++ b/WordPress/Tests/WP/DeprecatedParametersUnitTest.php @@ -54,6 +54,7 @@ public function getWarningList() { return array( 100 => 1, 101 => 1, + 102 => 1, ); } } From 5ffaf4a4e54a64d758c3a507333929980a172773 Mon Sep 17 00:00:00 2001 From: jrfnl Date: Sun, 23 Nov 2025 12:40:44 +0100 Subject: [PATCH 100/105] Various sniffs: update docs ... to document when the lists were verified against WP Core last. --- WordPress/Sniffs/NamingConventions/ValidPostTypeSlugSniff.php | 2 +- WordPress/Sniffs/WP/CapabilitiesSniff.php | 2 +- WordPress/Sniffs/WP/DeprecatedClassesSniff.php | 2 +- WordPress/Sniffs/WP/DeprecatedParameterValuesSniff.php | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/WordPress/Sniffs/NamingConventions/ValidPostTypeSlugSniff.php b/WordPress/Sniffs/NamingConventions/ValidPostTypeSlugSniff.php index 67c90225a4..f5cb955b03 100644 --- a/WordPress/Sniffs/NamingConventions/ValidPostTypeSlugSniff.php +++ b/WordPress/Sniffs/NamingConventions/ValidPostTypeSlugSniff.php @@ -63,7 +63,7 @@ final class ValidPostTypeSlugSniff extends AbstractFunctionParameterSniff { * * Source: {@link https://developer.wordpress.org/reference/functions/register_post_type/#reserved-post-types} * - * {@internal To be updated after every major release. Last updated for WordPress 6.8.1.} + * {@internal To be updated after every major release. Last updated for WordPress 6.9.0-RC2.} * * @since 2.2.0 * diff --git a/WordPress/Sniffs/WP/CapabilitiesSniff.php b/WordPress/Sniffs/WP/CapabilitiesSniff.php index fc2b0b34a9..758359f9c6 100644 --- a/WordPress/Sniffs/WP/CapabilitiesSniff.php +++ b/WordPress/Sniffs/WP/CapabilitiesSniff.php @@ -173,7 +173,7 @@ final class CapabilitiesSniff extends AbstractFunctionParameterSniff { * * List is sorted alphabetically. * - * {@internal To be updated after every major release. Last updated for WordPress 6.8.1.} + * {@internal To be updated after every major release. Last updated for WordPress 6.9.0-RC2.} * * @since 3.0.0 * diff --git a/WordPress/Sniffs/WP/DeprecatedClassesSniff.php b/WordPress/Sniffs/WP/DeprecatedClassesSniff.php index 8f67cb48f4..eec0d8f7cc 100644 --- a/WordPress/Sniffs/WP/DeprecatedClassesSniff.php +++ b/WordPress/Sniffs/WP/DeprecatedClassesSniff.php @@ -41,7 +41,7 @@ final class DeprecatedClassesSniff extends AbstractClassRestrictionsSniff { * * Version numbers should be fully qualified. * - * {@internal To be updated after every major release. Last updated for WordPress 6.8.1.} + * {@internal To be updated after every major release. Last updated for WordPress 6.9.0-RC2.} * * @var array */ diff --git a/WordPress/Sniffs/WP/DeprecatedParameterValuesSniff.php b/WordPress/Sniffs/WP/DeprecatedParameterValuesSniff.php index a4013892e0..1eefb6596c 100644 --- a/WordPress/Sniffs/WP/DeprecatedParameterValuesSniff.php +++ b/WordPress/Sniffs/WP/DeprecatedParameterValuesSniff.php @@ -43,7 +43,7 @@ final class DeprecatedParameterValuesSniff extends AbstractFunctionParameterSnif * looking for `_deprecated_argument()`. * The list is sorted alphabetically by function name. * - * {@internal To be updated after every major release. Last updated for WordPress 6.8.1.} + * {@internal To be updated after every major release. Last updated for WordPress 6.9.0-RC2.} * * @since 1.0.0 * @since 3.0.0 The format of the value has changed to support function calls From 1f16cb62a7d6a15e68fc2fe8214eb206248921ca Mon Sep 17 00:00:00 2001 From: jrfnl Date: Sun, 23 Nov 2025 14:30:13 +0100 Subject: [PATCH 101/105] GH Actions: improve "don't run on forks" conditions Remove the conditions containing a hard-coded repository name in favour of a more generic condition which should safeguard that select steps don't run on forks just the same. --- .github/workflows/manage-labels.yml | 6 +++--- .github/workflows/quicktest.yml | 6 +++--- .github/workflows/unit-tests.yml | 6 +++--- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/.github/workflows/manage-labels.yml b/.github/workflows/manage-labels.yml index d6e989b20b..a0385ae6fa 100644 --- a/.github/workflows/manage-labels.yml +++ b/.github/workflows/manage-labels.yml @@ -12,7 +12,7 @@ on: jobs: on-pr-merge: runs-on: ubuntu-latest - if: github.repository_owner == 'WordPress' && github.event.pull_request.merged == true + if: github.event.repository.fork == false && github.event.pull_request.merged == true name: Clean up labels on PR merge @@ -26,7 +26,7 @@ jobs: on-pr-close: runs-on: ubuntu-latest - if: github.repository_owner == 'WordPress' && github.event_name == 'pull_request_target' && github.event.pull_request.merged == false + if: github.event.repository.fork == false && github.event_name == 'pull_request_target' && github.event.pull_request.merged == false name: Clean up labels on PR close @@ -41,7 +41,7 @@ jobs: on-issue-close: runs-on: ubuntu-latest - if: github.repository_owner == 'WordPress' && github.event.issue.state == 'closed' + if: github.event.repository.fork == false && github.event.issue.state == 'closed' name: Clean up labels on issue close diff --git a/.github/workflows/quicktest.yml b/.github/workflows/quicktest.yml index 7139b1d536..7190d0fac9 100644 --- a/.github/workflows/quicktest.yml +++ b/.github/workflows/quicktest.yml @@ -66,15 +66,15 @@ jobs: run: composer lint - name: Run the unit tests without code coverage - if: ${{ github.repository_owner != 'WordPress' || github.ref_name != 'develop' }} + if: ${{ github.event.repository.fork == true || github.ref_name != 'develop' }} run: composer run-tests - name: Run the unit tests with code coverage - if: ${{ github.repository_owner == 'WordPress' && github.ref_name == 'develop' }} + if: ${{ github.event.repository.fork == false && github.ref_name == 'develop' }} run: composer coverage - name: Send coverage report to Codecov - if: ${{ success() && github.repository_owner == 'WordPress' && github.ref_name == 'develop' }} + if: ${{ success() && github.event.repository.fork == false && github.ref_name == 'develop' }} uses: codecov/codecov-action@5a1091511ad55cbe89839c7260b706298ca349f7 # v5.5.1 with: files: ./build/logs/clover.xml diff --git a/.github/workflows/unit-tests.yml b/.github/workflows/unit-tests.yml index f8942cbb6e..54339f4a9e 100644 --- a/.github/workflows/unit-tests.yml +++ b/.github/workflows/unit-tests.yml @@ -128,15 +128,15 @@ jobs: run: composer lint -- --checkstyle | cs2pr - name: Run the unit tests without code coverage - if: ${{ matrix.coverage == false || github.repository_owner != 'WordPress' }} + if: ${{ matrix.coverage == false || github.event.repository.fork == true }} run: composer run-tests - name: Run the unit tests with code coverage - if: ${{ matrix.coverage == true && github.repository_owner == 'WordPress' }} + if: ${{ matrix.coverage == true && github.event.repository.fork == false }} run: composer coverage - name: Send coverage report to Codecov - if: ${{ success() && matrix.coverage == true && github.repository_owner == 'WordPress' }} + if: ${{ success() && matrix.coverage == true && github.event.repository.fork == false }} uses: codecov/codecov-action@5a1091511ad55cbe89839c7260b706298ca349f7 # v5.5.1 with: files: ./build/logs/clover.xml From 13e2eda2ad3b7479e828e46c2251032cd50f230c Mon Sep 17 00:00:00 2001 From: jrfnl Date: Sun, 23 Nov 2025 13:58:42 +0100 Subject: [PATCH 102/105] DB/DirectDatabaseQuery: allow for more caching functions While updating the pluggable function list for WP 6.9, I noticed there are now more cache functions in WP. Based on the docs: * [`wp_cache_get_multiple()`](https://developer.wordpress.org/reference/functions/wp_cache_get_multiple/) was added in WP 5.5.0. * [`wp_cache_get_multiple_salted()`](https://developer.wordpress.org/reference/functions/wp_cache_get_multiple_salted/) was added in WP 6.9.0. * [`wp_cache_get_salted()`](https://developer.wordpress.org/reference/functions/wp_cache_get_salted/) was added in WP 6.9.0. * [`wp_cache_add_multiple()`](https://developer.wordpress.org/reference/functions/wp_cache_add_multiple/) was added in WP 6.0.0. * [`wp_cache_set_multiple()`](https://developer.wordpress.org/reference/functions/wp_cache_set_multiple/) was added in WP 6.0.0. * [`wp_cache_set_multiple_salted()`](https://developer.wordpress.org/reference/functions/wp_cache_set_multiple_salted/) was added in WP 6.9.0. * [`wp_cache_set_salted()`](https://developer.wordpress.org/reference/functions/wp_cache_set_salted/) was added in WP 6.9.0. * [`wp_cache_delete_multiple()`](https://developer.wordpress.org/reference/functions/wp_cache_delete_multiple/) was added in WP 6.0.0. * [`wp_cache_flush_group()`](https://developer.wordpress.org/reference/functions/wp_cache_flush_group/) was added in WP 6.1.0. * [`wp_cache_flush_runtime()`](https://developer.wordpress.org/reference/functions/wp_cache_flush_runtime/) was added in WP 6.0.0. This commit adds these functions to the appropriate lists for the sniff to take into account. Includes tests. --- .../Sniffs/DB/DirectDatabaseQuerySniff.php | 40 ++++++++++++------- .../DB/DirectDatabaseQueryUnitTest.1.inc | 31 ++++++++++++++ .../Tests/DB/DirectDatabaseQueryUnitTest.php | 4 ++ 3 files changed, 60 insertions(+), 15 deletions(-) diff --git a/WordPress/Sniffs/DB/DirectDatabaseQuerySniff.php b/WordPress/Sniffs/DB/DirectDatabaseQuerySniff.php index 1d05da486d..3271a41874 100644 --- a/WordPress/Sniffs/DB/DirectDatabaseQuerySniff.php +++ b/WordPress/Sniffs/DB/DirectDatabaseQuerySniff.php @@ -82,7 +82,10 @@ final class DirectDatabaseQuerySniff extends Sniff { * @var array */ protected $cacheGetFunctions = array( - 'wp_cache_get' => true, + 'wp_cache_get' => true, + 'wp_cache_get_multiple' => true, + 'wp_cache_get_multiple_salted' => true, + 'wp_cache_get_salted' => true, ); /** @@ -95,8 +98,12 @@ final class DirectDatabaseQuerySniff extends Sniff { * @var array */ protected $cacheSetFunctions = array( - 'wp_cache_set' => true, - 'wp_cache_add' => true, + 'wp_cache_add' => true, + 'wp_cache_add_multiple' => true, + 'wp_cache_set' => true, + 'wp_cache_set_multiple' => true, + 'wp_cache_set_multiple_salted' => true, + 'wp_cache_set_salted' => true, ); /** @@ -109,18 +116,21 @@ final class DirectDatabaseQuerySniff extends Sniff { * @var array */ protected $cacheDeleteFunctions = array( - 'wp_cache_delete' => true, - 'clean_attachment_cache' => true, - 'clean_blog_cache' => true, - 'clean_bookmark_cache' => true, - 'clean_category_cache' => true, - 'clean_comment_cache' => true, - 'clean_network_cache' => true, - 'clean_object_term_cache' => true, - 'clean_page_cache' => true, - 'clean_post_cache' => true, - 'clean_term_cache' => true, - 'clean_user_cache' => true, + 'wp_cache_delete' => true, + 'wp_cache_delete_multiple' => true, + 'wp_cache_flush_group' => true, + 'wp_cache_flush_runtime' => true, + 'clean_attachment_cache' => true, + 'clean_blog_cache' => true, + 'clean_bookmark_cache' => true, + 'clean_category_cache' => true, + 'clean_comment_cache' => true, + 'clean_network_cache' => true, + 'clean_object_term_cache' => true, + 'clean_page_cache' => true, + 'clean_post_cache' => true, + 'clean_term_cache' => true, + 'clean_user_cache' => true, ); /** diff --git a/WordPress/Tests/DB/DirectDatabaseQueryUnitTest.1.inc b/WordPress/Tests/DB/DirectDatabaseQueryUnitTest.1.inc index 517cf56476..b8081ec578 100644 --- a/WordPress/Tests/DB/DirectDatabaseQueryUnitTest.1.inc +++ b/WordPress/Tests/DB/DirectDatabaseQueryUnitTest.1.inc @@ -475,3 +475,34 @@ function callToMultiLevelNamespaceRelativeCacheDelete() { $wpdb->query( 'SELECT X FROM Y' ); // Warning direct DB call. namespace\Sub\clean_blog_cache( 1 ); } + +// Handle more caching functions. +function cache_multiple() { + global $wpdb; + $data = wp_cache_get_multiple( ['keyA', 'keyB'] ); + if ( false !== $data ) { + $data = $wpdb->get_results( $query ); // Warning direct DB call. + \wp_cache_add_multiple( $data ); + } +} + +function cache_multiple_salted() { + global $wpdb; + $data = \wp_cache_get_multiple_salted( ...$params ); + if ( false !== $data ) { + $data = $wpdb->get_col( $query ); // Warning direct DB call. + wp_cache_set_multiple_salted( ...$params ); + } +} + +function cache_delete_multiple() { + global $wpdb; + $wpdb->replace( $query ); // Warning direct DB call. + WP_cache_delete_multiple( ['keyA', 'keyB'] ); +} + +function cache_flush_group() { + global $wpdb; + $wpdb->delete( $query ); // Warning direct DB call. + wp_cache_flush_group( 'group' ); +} diff --git a/WordPress/Tests/DB/DirectDatabaseQueryUnitTest.php b/WordPress/Tests/DB/DirectDatabaseQueryUnitTest.php index 709d66c0e6..5a4fda7f4a 100644 --- a/WordPress/Tests/DB/DirectDatabaseQueryUnitTest.php +++ b/WordPress/Tests/DB/DirectDatabaseQueryUnitTest.php @@ -109,6 +109,10 @@ public function getWarningList( $testFile = '' ) { 461 => 1, 468 => 1, 475 => 1, + 484 => 1, + 493 => 1, + 500 => 1, + 506 => 1, ); default: return array(); From e2e4d2abdcce4142c105e857693ed504f67750c1 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 24 Nov 2025 09:11:57 +0000 Subject: [PATCH 103/105] GH Actions: Bump actions/checkout from 5.0.1 to 6.0.0 Bumps [actions/checkout](https://github.com/actions/checkout) from 5.0.1 to 6.0.0. - [Release notes](https://github.com/actions/checkout/releases) - [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md) - [Commits](https://github.com/actions/checkout/compare/93cb6efe18208431cddfb8368fd83d5badbf9bfd...1af3b93b6815bc44a9784bd300feb67ff0d1eeb3) --- updated-dependencies: - dependency-name: actions/checkout dependency-version: 6.0.0 dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] --- .github/workflows/basic-qa.yml | 10 +++++----- .github/workflows/quicktest.yml | 2 +- .github/workflows/unit-tests.yml | 2 +- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/.github/workflows/basic-qa.yml b/.github/workflows/basic-qa.yml index 4a5acbdc0c..10a1ec6263 100644 --- a/.github/workflows/basic-qa.yml +++ b/.github/workflows/basic-qa.yml @@ -26,7 +26,7 @@ jobs: steps: - name: Checkout repository - uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd # v5.0.1 + uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0 with: persist-credentials: false @@ -117,7 +117,7 @@ jobs: steps: - name: Checkout code - uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd # v5.0.1 + uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0 with: persist-credentials: false @@ -157,7 +157,7 @@ jobs: steps: - name: Checkout repository - uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd # v5.0.1 + uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0 with: persist-credentials: false @@ -240,7 +240,7 @@ jobs: steps: - name: Checkout code - uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd # v5.0.1 + uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0 with: persist-credentials: false @@ -270,7 +270,7 @@ jobs: steps: - name: "Checkout" - uses: "actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd" # v5.0.1 + uses: "actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3" # v6.0.0 with: persist-credentials: false diff --git a/.github/workflows/quicktest.yml b/.github/workflows/quicktest.yml index 7139b1d536..3476438685 100644 --- a/.github/workflows/quicktest.yml +++ b/.github/workflows/quicktest.yml @@ -30,7 +30,7 @@ jobs: steps: - name: Checkout repository - uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd # v5.0.1 + uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0 with: persist-credentials: false diff --git a/.github/workflows/unit-tests.yml b/.github/workflows/unit-tests.yml index f8942cbb6e..4195c65305 100644 --- a/.github/workflows/unit-tests.yml +++ b/.github/workflows/unit-tests.yml @@ -74,7 +74,7 @@ jobs: steps: - name: Checkout repository - uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd # v5.0.1 + uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0 with: persist-credentials: false From 7f36b9d608f0afe39222f190419707f9fb6fe0d3 Mon Sep 17 00:00:00 2001 From: jrfnl Date: Sun, 23 Nov 2025 10:58:51 +0100 Subject: [PATCH 104/105] Update the minimum_wp_version to WP 6.6 The minimum version should be three versions behind the latest WP release, so what with 6.9.0 slated for release on Dec 2nd, it should now become 6.6. Includes updating the tests to match. Previous: 2121, 2321. 2436, 2553 --- WordPress/Helpers/MinimumWPVersionTrait.php | 2 +- WordPress/Tests/WP/DeprecatedFunctionsUnitTest.1.inc | 8 ++++---- WordPress/Tests/WP/DeprecatedFunctionsUnitTest.php | 8 ++++---- WordPress/Tests/WP/DeprecatedParametersUnitTest.inc | 4 ++-- WordPress/Tests/WP/DeprecatedParametersUnitTest.php | 3 +-- 5 files changed, 12 insertions(+), 13 deletions(-) diff --git a/WordPress/Helpers/MinimumWPVersionTrait.php b/WordPress/Helpers/MinimumWPVersionTrait.php index 74f0a2370b..b651e80bb6 100644 --- a/WordPress/Helpers/MinimumWPVersionTrait.php +++ b/WordPress/Helpers/MinimumWPVersionTrait.php @@ -79,7 +79,7 @@ trait MinimumWPVersionTrait { * * @var string WordPress version. */ - private $default_minimum_wp_version = '6.5'; + private $default_minimum_wp_version = '6.6'; /** * Overrule the minimum supported WordPress version with a command-line/config value. diff --git a/WordPress/Tests/WP/DeprecatedFunctionsUnitTest.1.inc b/WordPress/Tests/WP/DeprecatedFunctionsUnitTest.1.inc index 4abf47c46d..57a44658ef 100644 --- a/WordPress/Tests/WP/DeprecatedFunctionsUnitTest.1.inc +++ b/WordPress/Tests/WP/DeprecatedFunctionsUnitTest.1.inc @@ -418,14 +418,14 @@ the_block_template_skip_link(); wp_admin_bar_header(); wp_img_tag_add_decoding_attr(); wp_update_https_detection_errors(); - -/* - * Warning. - */ /* ============ WP 6.5 ============ */ block_core_file_ensure_interactivity_dependency(); block_core_image_ensure_interactivity_dependency(); block_core_query_ensure_interactivity_dependency(); + +/* + * Warning. + */ /* ============ WP 6.6 ============ */ wp_interactivity_process_directives_of_interactive_blocks(); wp_render_elements_support(); diff --git a/WordPress/Tests/WP/DeprecatedFunctionsUnitTest.php b/WordPress/Tests/WP/DeprecatedFunctionsUnitTest.php index 7813bede2d..6931a37a9b 100644 --- a/WordPress/Tests/WP/DeprecatedFunctionsUnitTest.php +++ b/WordPress/Tests/WP/DeprecatedFunctionsUnitTest.php @@ -32,7 +32,7 @@ public function getErrorList( $testFile = '' ) { switch ( $testFile ) { case 'DeprecatedFunctionsUnitTest.1.inc': $start_line = 8; - $end_line = 420; + $end_line = 424; $errors = array_fill( $start_line, ( ( $end_line - $start_line ) + 1 ), 1 ); // Unset the lines related to version comments. @@ -84,7 +84,8 @@ public function getErrorList( $testFile = '' ) { $errors[373], $errors[383], $errors[386], - $errors[410] + $errors[410], + $errors[421] ); return $errors; @@ -109,13 +110,12 @@ public function getErrorList( $testFile = '' ) { public function getWarningList( $testFile = '' ) { switch ( $testFile ) { case 'DeprecatedFunctionsUnitTest.1.inc': - $start_line = 426; + $start_line = 430; $end_line = 446; $warnings = array_fill( $start_line, ( ( $end_line - $start_line ) + 1 ), 1 ); // Unset the lines related to version comments. unset( - $warnings[429], $warnings[432], $warnings[442], $warnings[444] diff --git a/WordPress/Tests/WP/DeprecatedParametersUnitTest.inc b/WordPress/Tests/WP/DeprecatedParametersUnitTest.inc index 027a2a47cc..40d309e71a 100644 --- a/WordPress/Tests/WP/DeprecatedParametersUnitTest.inc +++ b/WordPress/Tests/WP/DeprecatedParametersUnitTest.inc @@ -95,8 +95,8 @@ wp_title_rss( 'deprecated' ); wp_upload_bits( '', 'deprecated' ); xfn_check( '', '', 'deprecated' ); global_terms( $foo, 'deprecated' ); - -// All will give an WARNING as they have been deprecated after WP 6.5. inject_ignored_hooked_blocks_metadata_attributes('', 'deprecated'); + +// All will give an WARNING as they have been deprecated after WP 6.6. wp_render_elements_support_styles('deprecated'); _wp_can_use_pcre_u('deprecated'); diff --git a/WordPress/Tests/WP/DeprecatedParametersUnitTest.php b/WordPress/Tests/WP/DeprecatedParametersUnitTest.php index 5d120db624..9f4d2d87d1 100644 --- a/WordPress/Tests/WP/DeprecatedParametersUnitTest.php +++ b/WordPress/Tests/WP/DeprecatedParametersUnitTest.php @@ -28,7 +28,7 @@ final class DeprecatedParametersUnitTest extends AbstractSniffUnitTest { */ public function getErrorList() { $start_line = 42; - $end_line = 97; + $end_line = 98; $errors = array_fill( $start_line, ( ( $end_line - $start_line ) + 1 ), 1 ); $errors[22] = 1; @@ -52,7 +52,6 @@ public function getErrorList() { */ public function getWarningList() { return array( - 100 => 1, 101 => 1, 102 => 1, ); From 12e293615615458658f670865d6f8dcfc802417e Mon Sep 17 00:00:00 2001 From: jrfnl Date: Sun, 23 Nov 2025 14:46:50 +0100 Subject: [PATCH 105/105] Changelog for the release of WordPressCS 3.3.0 Release date tentatively set to this Tuesday November 25th. Already includes entry for PR 2656 on the assumption that it will be merged in time for the release. Includes removing a stray header. Includes minor formatting consistency fixes for the file. --- CHANGELOG.md | 80 ++++++++++++++++++++++++++++++++++++++++++---------- 1 file changed, 65 insertions(+), 15 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index c8e96a8a7c..d08d7fbc7c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,69 @@ This projects adheres to [Semantic Versioning](https://semver.org/) and [Keep a _No documentation available about unreleased changes as of yet._ +## [3.3.0] - 2025-11-25 + +### Added +- Support for attributes on anonymous classes (PHP 8.0) and `readonly` anonymous classes (PHP 8.3) to the `WordPress.Security.EscapeOutput` sniff. Props [@rodrigoprimo]. [#2559] +- Support for handling "exit as a function call" (PHP 8.4) to the `WordPress.Security.EscapeOutput` sniff. [#2563] +- WordPress-Extra: the following sniffs have been added to the ruleset: `Universal.Attributes.BracketSpacing` and `Universal.Attributes.DisallowAttributeParentheses`. [#2646] + +### Changed +- The minimum supported PHP version is now PHP 7.2 (was PHP 5.4). [#2614] +- The minimum required `PHP_CodeSniffer` version to 3.13.4 (was 3.13.0). [#2630] +- The minimum required `PHPCSExtra` version to 1.5.0 (was 1.4.0). [#2646] +- The default value for `minimum_wp_version`, as used by a [number of sniffs detecting usage of deprecated WP features](https://github.com/WordPress/WordPress-Coding-Standards/wiki/Customizable-sniff-properties#various-sniffs-set-the-minimum-supported-wp-version), has been updated to `6.6`. [#2656] +- `WordPress.DB.DirectDatabaseQuery` will now recognize more caching functions, like the `wp_cache_*_multiple()` functions as added in WordPress 6.0 and the `wp_cache_*_salted()` functions as added in WordPress 6.9. [#2654] +- `WordPress.NamingConventions.PrefixAllGlobals` has been updated to recognize pluggable functions introduced in WP up to WP 6.9.0. [#2652] +- `WordPress.WP.ClassNameCase` has been updated to recognize classes introduced in WP up to WP 6.9.0. [#2652] +- `WordPress.WP.DeprecatedFunctions` now detects functions deprecated in WordPress up to WP 6.9.0. [#2652] +- `WordPress.WP.DeprecatedParameters` now detects parameters deprecated in WordPress up to WP 6.9.0. [#2652] +- `WordPress.Security.ValidatedSanitizedInput`: improved the clarity of the error message for the `InputNotValidated` error code. Props [@rodrigoprimo]. [#2642] +- README: updated `testVersion` recommendations for PHPCompatibility. Props [@johnjago]. [#2471] +- Example ruleset: updated the `minimum_wp_version` and `testVersion` recommendations. [#2608] +- All sniffs are now also being tested against PHP 8.5 for consistent sniff results. [#2649] +- Various housekeeping, including documentation and test improvements. Includes contributions by [@rodrigoprimo]. + +### Deprecated +- The WordPress.PHP.POSIXFunctions sniff (as it is no longer relevant). [#2616] + +### Removed +- `wp_kses_allowed_html()` from the list of escaping functions. [#2566] + This affects the `WordPress.Security.EscapeOutput` sniff. + +### Fixed +- `WordPress.DB.DirectDatabaseQuery`: false positive when function call to caching functions did not use the canonical function name. Props [@rodrigoprimo]. [#2613] +- `WordPress.DB.DirectDatabaseQuery`: potential false negative when a class property or constant would mirror the name of one of the caching functions. Props [@rodrigoprimo]. [#2615] +- `WordPress.DB.PreparedSQL`: false positive for correctly escaped SQL snippets when the function call did not use the canonical function name. Props [@rodrigoprimo]. [#2570] +- `WordPress.DB.PreparedSQLPlaceholders`: improved handling of fully qualified calls to global functions. Props [@rodrigoprimo]. [#2569] +- `WordPress.Security.EscapeOutput`: expanded protection against false positives for `*::class`. Props [@rodrigoprimo]. [#2605] +- `WordPress.Security.NonceVerification`: false positive when nonce checking function call did not use the canonical function name. Props [@rodrigoprimo]. [#2572] +- `WordPress.WP.EnqueuedResourceParameters`: the sniff could cause a PHP 8.5 deprecation notice if the _code under scan_ contained one of the deprecated type casts. [#2573] +- `WordPress.WP.EnqueuedResourceParameters`: improved recognition of non-lowercase and fully qualified `true`/`false`/`null` when passed as the `$ver` parameter value. Props [@rodrigoprimo]. [#2630] + +[#2471]: https://github.com/WordPress/WordPress-Coding-Standards/pull/2471 +[#2559]: https://github.com/WordPress/WordPress-Coding-Standards/pull/2559 +[#2563]: https://github.com/WordPress/WordPress-Coding-Standards/pull/2563 +[#2566]: https://github.com/WordPress/WordPress-Coding-Standards/pull/2566 +[#2569]: https://github.com/WordPress/WordPress-Coding-Standards/pull/2569 +[#2570]: https://github.com/WordPress/WordPress-Coding-Standards/pull/2570 +[#2572]: https://github.com/WordPress/WordPress-Coding-Standards/pull/2572 +[#2573]: https://github.com/WordPress/WordPress-Coding-Standards/pull/2573 +[#2605]: https://github.com/WordPress/WordPress-Coding-Standards/pull/2605 +[#2608]: https://github.com/WordPress/WordPress-Coding-Standards/pull/2608 +[#2613]: https://github.com/WordPress/WordPress-Coding-Standards/pull/2613 +[#2614]: https://github.com/WordPress/WordPress-Coding-Standards/pull/2614 +[#2615]: https://github.com/WordPress/WordPress-Coding-Standards/pull/2615 +[#2616]: https://github.com/WordPress/WordPress-Coding-Standards/pull/2616 +[#2630]: https://github.com/WordPress/WordPress-Coding-Standards/pull/2630 +[#2642]: https://github.com/WordPress/WordPress-Coding-Standards/pull/2642 +[#2646]: https://github.com/WordPress/WordPress-Coding-Standards/pull/2646 +[#2649]: https://github.com/WordPress/WordPress-Coding-Standards/pull/2649 +[#2652]: https://github.com/WordPress/WordPress-Coding-Standards/pull/2652 +[#2654]: https://github.com/WordPress/WordPress-Coding-Standards/pull/2654 +[#2656]: https://github.com/WordPress/WordPress-Coding-Standards/pull/2656 + + ## [3.2.0] - 2025-07-24 ### Added @@ -39,10 +102,7 @@ _No documentation available about unreleased changes as of yet._ - Various housekeeping, including documentation and test improvements. Includes contributions by [@rodrigoprimo] and [@szepeviktor]. - All sniffs are now also being tested against PHP 8.4 for consistent sniff results. [#2511] -### Deprecated - ### Removed - - The `Generic.Functions.CallTimePassByReference` has been removed from the `WordPress-Extra` ruleset. Props [@rodrigoprimo]. [#2536] This sniff was dated anyway and deprecated in PHP_CodeSniffer. If you need to check if your code is PHP cross-version compatible, use the [PHPCompatibility] standard instead. @@ -79,7 +139,6 @@ _No documentation available about unreleased changes as of yet._ - The `sanitize_locale_name()` function to the list of known "sanitize & unslash" functions. Props [@Chouby] ### Changed - - The minimum required `PHP_CodeSniffer` version to 3.9.0 (was 3.7.2). - The minimum required `PHPCSUtils` version to 1.0.10 (was 1.0.8). - The minimum required `PHPCSExtra` version to 1.2.1 (was 1.1.0). @@ -96,24 +155,20 @@ _No documentation available about unreleased changes as of yet._ - Various housekeeping, includes a contribution from [@rodrigoprimo]. ### Fixed - - `WordPress.WP.PostsPerPage` could potentially result in an `Internal.Exception` when encountering a query string which doesn't include the value for `posts_per_page` in the query string. Props [@anomiex] for reporting. ## [3.0.1] - 2023-09-14 ### Added - - In WordPressCS 3.0.0, the functionality of the `WordPress.Security.EscapeOutput` sniff was updated to report unescaped message parameters passed to exceptions created in `throw` statements. This specific violation now has a separate error code: `ExceptionNotEscaped`. This will allow users to ignore or exclude that specific error code. Props [@anomiex]. The error code(s) for other escaping issues flagged by the sniff remain unchanged. ### Changed - - Updated the CI workflow to test the example ruleset for issues. - Funding files and updates in the Readme about funding the project. ### Fixed - - Fixed a sniff name in the `phpcs.xml.dist.sample` file (case-sensitive sniff name). Props [@dawidurbanski]. @@ -135,7 +190,6 @@ In all cases, please read the complete changelog carefully before you upgrade. ### Added - - Dependencies on the following packages: [PHPCSUtils](https://phpcsutils.com/), [PHPCSExtra](https://github.com/PHPCSStandards/PHPCSExtra) and the [Composer PHPCS plugin]. - A best effort has been made to add support for the new PHP syntaxes/features to all WordPressCS native sniffs and utility functions (or to verify/improve existing support). While support in external sniffs used by WordPressCS has not be exhaustively verified, a lot of work has been done to try and add support for new PHP syntaxes to those as well. @@ -222,7 +276,6 @@ More information is available in the [Upgrade Guide to WordPressCS 3.0.0 for Dev ### Changed - - As of this version, installation via Composer is the only supported manner of installation. Installing in a different manner (git clone/PEAR/PHAR) is still possible, but no longer supported. - The minimum required `PHP_CodeSniffer` version to 3.7.2 (was 3.3.1). @@ -311,9 +364,7 @@ More information is available in the [Upgrade Guide to WordPressCS 3.0.0 for Dev - `AbstractFunctionRestrictionsSniff`: The `whitelist` key in the `$groups` array property has been renamed to `allow`. - The `WordPress.NamingConventions.ValidFunctionName` sniff no longer extends the similar PHPCS native `PEAR` sniff. - ### Removed - - Support for the deprecated, old-style WordPressCS native ignore annotations. Use the PHPCS native selective ignore annotations instead. - The following WordPressCS native sniffs have been removed: - The `WordPress.Arrays.CommaAfterArrayItem` sniff (replaced by the `NormalizedArrays.Arrays.CommaAfterLast` and the `Universal.WhiteSpace.CommaSpacing` sniffs). @@ -369,9 +420,7 @@ More information is available in the [Upgrade Guide to WordPressCS 3.0.0 for Dev - `WordPressCS\WordPress\Sniff::valid_direct_scope()` method (use the `PHPCSUtils\Utils\Scopes::validDirectScope()` method instead). - Unused dev-only files in the (now removed) `bin` directory. - ### Fixed - - All sniffs which, in one way or another, check whether code represents a short list or a short array will now do so more accurately. This fixes various false positives and false negatives. - Sniffs supporting the `minimum_wp_version` property (previously `minimum_supported_version`) will no longer throw a "passing null to non-nullable" deprecation notice on PHP 8.1+. @@ -693,7 +742,6 @@ If you are a maintainer of an external standard based on WordPressCS and any of ### Changes since 2.0.0-RC1 #### Fixed - - `WordPress-Extra`: Reverted back to including the `Squiz.WhiteSpace.LanguageConstructSpacing` sniff instead of the new `Generic.WhiteSpace.LanguageConstructSpacing` sniff as the new sniff is not (yet) available when the PEAR install of PHPCS is used. ### Changes since 1.2.1 @@ -1667,6 +1715,7 @@ Initial tagged release. [PHPCompatibility]: https://github.com/PHPCompatibility/PHPCompatibility [Unreleased]: https://github.com/WordPress/WordPress-Coding-Standards/compare/main...HEAD +[3.3.0]: https://github.com/WordPress/WordPress-Coding-Standards/compare/3.2.0...3.3.0 [3.2.0]: https://github.com/WordPress/WordPress-Coding-Standards/compare/3.1.0...3.2.0 [3.1.0]: https://github.com/WordPress/WordPress-Coding-Standards/compare/3.0.1...3.1.0 [3.0.1]: https://github.com/WordPress/WordPress-Coding-Standards/compare/3.0.0...3.0.1 @@ -1714,6 +1763,7 @@ Initial tagged release. [@Ipstenu]: https://github.com/Ipstenu [@jaymcp]: https://github.com/jaymcp [@JDGrimes]: https://github.com/JDGrimes +[@johnjago]: https://github.com/johnjago [@jrfnl]: https://github.com/jrfnl [@khacoder]: https://github.com/khacoder [@Luc45]: https://github.com/Luc45