From 27701fdf8d98f3c69067b41d49d8db986aa6855a Mon Sep 17 00:00:00 2001 From: Rodrigo Primo Date: Thu, 21 Aug 2025 16:08:21 -0300 Subject: [PATCH 001/108] Security/EscapeOutput: add tests for namespaced names --- .../Tests/Security/EscapeOutputUnitTest.1.inc | 69 ++++++++++++++++++- .../Tests/Security/EscapeOutputUnitTest.php | 29 +++++++- 2 files changed, 95 insertions(+), 3 deletions(-) diff --git a/WordPress/Tests/Security/EscapeOutputUnitTest.1.inc b/WordPress/Tests/Security/EscapeOutputUnitTest.1.inc index 52c3a59976..0f20839189 100644 --- a/WordPress/Tests/Security/EscapeOutputUnitTest.1.inc +++ b/WordPress/Tests/Security/EscapeOutputUnitTest.1.inc @@ -258,7 +258,7 @@ echo esc_html_x( $some_nasty_var, 'context' ); // Ok. 1, 19 => 1, @@ -160,10 +163,34 @@ public function getErrorList( $testFile = '' ) { 655 => 1, 657 => 1, 663 => 1, - 664 => 1, + // PHPCS 3.13.3 changed the tokenization of FQN exit/die it impacts directly how this test case + // behaves (see https://github.com/PHPCSStandards/PHP_CodeSniffer/issues/1201). + 664 => version_compare( $phpcs_version, '3.13.3', '>=' ) ? 1 : 0, 672 => 1, 673 => 1, 678 => 1, + 694 => 1, + 700 => 1, + 701 => 1, + 702 => 1, + 703 => 1, + 709 => 1, + 710 => 1, + 711 => 1, + 712 => 1, + 717 => 1, + 726 => 1, + 728 => 1, + 729 => 1, + 730 => 1, + 731 => 1, + 737 => 1, + 738 => 1, + 739 => 1, + 740 => 1, + 741 => 1, + 747 => 1, + 751 => 1, ); case 'EscapeOutputUnitTest.6.inc': From 322829bf6471d4113cd56eb4abe2a381847db224 Mon Sep 17 00:00:00 2001 From: Rodrigo Primo Date: Fri, 14 Nov 2025 11:30:00 -0300 Subject: [PATCH 002/108] Security/EscapeOutput: add edge case tests for basename( __FILE__ ) pattern Add tests to ensure the `basename( __FILE__ )` pattern recognition in `_deprecated_file()` only applies to global `basename()` function calls, not to other constructs that might look similar. --- .../Tests/Security/EscapeOutputUnitTest.1.inc | 14 ++++++++++++++ WordPress/Tests/Security/EscapeOutputUnitTest.php | 9 +++++++++ 2 files changed, 23 insertions(+) diff --git a/WordPress/Tests/Security/EscapeOutputUnitTest.1.inc b/WordPress/Tests/Security/EscapeOutputUnitTest.1.inc index 0f20839189..afb3e51700 100644 --- a/WordPress/Tests/Security/EscapeOutputUnitTest.1.inc +++ b/WordPress/Tests/Security/EscapeOutputUnitTest.1.inc @@ -752,3 +752,17 @@ namespace\Sub\user_error( $message ); // Ok. namespace\_deprecated_file( basename( __FILE__ ), '1.3.0' ); // Ok. namespace\_DEPRECATED_FILE( $file, '1.3.0' ); // Ok. The sniff should start flagging this once it can resolve relative namespaces. namespace\Sub\_deprecated_file( $file, '1.3.0' ); // Ok. + +/* + * Safeguard that the basename( __FILE__ ) pattern recognition in _deprecated_file() only applies to + * the global basename() function and not to other constructs. + */ +_deprecated_file( $obj->basename( __FILE__ ), '1.3.0' ); // Bad. +_deprecated_file( $obj?->basename( __FILE__ ), '1.3.0' ); // Bad. +_deprecated_file( MyClass::basename( __FILE__ ), '1.3.0' ); // Bad. +_deprecated_file( BASENAME, __FILE__ ); // Bad. +_deprecated_file( MyNamespace\basename( __FILE__ ), '1.3.0' ); // Bad. +_deprecated_file( \MyNamespace\basename( __FILE__ ), '1.3.0' ); // Bad. +_deprecated_file( namespace\basename( __FILE__ ), '1.3.0' ); // Bad. We might want to update the regex so that the sniff stop flagging this once it can resolve relative namespaces. +_deprecated_file( namespace\Sub\basename( __FILE__ ), '1.3.0' ); // Bad. +_deprecated_file( basename(...), '1.3.0' ); // Bad. diff --git a/WordPress/Tests/Security/EscapeOutputUnitTest.php b/WordPress/Tests/Security/EscapeOutputUnitTest.php index fc5200ccd8..39d0c46a5a 100644 --- a/WordPress/Tests/Security/EscapeOutputUnitTest.php +++ b/WordPress/Tests/Security/EscapeOutputUnitTest.php @@ -191,6 +191,15 @@ public function getErrorList( $testFile = '' ) { 741 => 1, 747 => 1, 751 => 1, + 760 => 1, + 761 => 1, + 762 => 1, + 763 => 1, + 764 => 1, + 765 => 1, + 766 => 1, + 767 => 1, + 768 => 1, ); case 'EscapeOutputUnitTest.6.inc': From 7d2d6ddd596260bf3e17029eb27c8e2f9ffdc84c Mon Sep 17 00:00:00 2001 From: Rodrigo Primo Date: Tue, 25 Nov 2025 10:53:14 -0300 Subject: [PATCH 003/108] Fix two typos in release checklist document --- .github/release-checklist.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/release-checklist.md b/.github/release-checklist.md index 37426e0d86..f7b0ba62d5 100644 --- a/.github/release-checklist.md +++ b/.github/release-checklist.md @@ -32,7 +32,7 @@ PR for tracking changes for the x.x.x release. Target release date: **DOW MONTH - [ ] `$wp_time_constants` in `WordPress.WP.CronInterval` - PR #xxx - [ ] `$known_test_classes` in `IsUnitTestTrait` - PR #xxx - [ ] ...etc... -- [ ] Verify there there has been no vandalism on the wiki (and if so, remove/fix it). +- [ ] Verify that there has been no vandalism on the wiki (and if so, remove/fix it). ### Release prep @@ -69,7 +69,7 @@ PR for tracking changes for the x.x.x release. Target release date: **DOW MONTH - [ ] 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]. +- [ ] Submit for the ["Monthly Dev Roundup"][dev-roundup]. [phpcs-releases]: https://github.com/PHPCSStandards/PHP_CodeSniffer/releases [phpcsutils-releases]: https://github.com/PHPCSStandards/PHPCSUtils/releases From 25151d81c99416f23544e5a5a411865027bab6c8 Mon Sep 17 00:00:00 2001 From: Rodrigo Primo Date: Tue, 25 Nov 2025 12:32:50 -0300 Subject: [PATCH 004/108] Update .github/release-checklist.md Co-authored-by: Juliette <663378+jrfnl@users.noreply.github.com> --- .github/release-checklist.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/release-checklist.md b/.github/release-checklist.md index f7b0ba62d5..c7ce0e5914 100644 --- a/.github/release-checklist.md +++ b/.github/release-checklist.md @@ -32,7 +32,7 @@ PR for tracking changes for the x.x.x release. Target release date: **DOW MONTH - [ ] `$wp_time_constants` in `WordPress.WP.CronInterval` - PR #xxx - [ ] `$known_test_classes` in `IsUnitTestTrait` - PR #xxx - [ ] ...etc... -- [ ] Verify that there has been no vandalism on the wiki (and if so, remove/fix it). +- [ ] Verify there has been no vandalism on the wiki (and if so, remove/fix it). ### Release prep From f51cb5d6acba9cdab5f572f0f8de11265bceb2fc Mon Sep 17 00:00:00 2001 From: Rodrigo Primo Date: Thu, 21 Aug 2025 16:47:14 -0300 Subject: [PATCH 005/108] WP/AlternativeFunctions: add tests for namespaced names --- WordPress/Tests/WP/AlternativeFunctionsUnitTest.inc | 11 ++++++++++- WordPress/Tests/WP/AlternativeFunctionsUnitTest.php | 1 + 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/WordPress/Tests/WP/AlternativeFunctionsUnitTest.inc b/WordPress/Tests/WP/AlternativeFunctionsUnitTest.inc index a88e5638a9..6296d75e22 100644 --- a/WordPress/Tests/WP/AlternativeFunctionsUnitTest.inc +++ b/WordPress/Tests/WP/AlternativeFunctionsUnitTest.inc @@ -32,7 +32,7 @@ file_get_contents( $local_file, true ); // OK. file_get_contents( $url, false ); // Warning. file_get_contents(); // OK - no params, so nothing to do. file_get_contents( 'http://remoteurl.com/file/?w=1' ); // Warning. -file_get_contents( 'https://wordpress.org' ); // Warning. +\file_GET_contents( 'https://wordpress.org' ); // Warning. file_get_contents(ABSPATH . 'wp-admin/css/some-file.css'); // OK. file_get_contents(MYABSPATH . 'plugin-file.json'); // Warning. file_get_contents( MUPLUGINDIR . 'some-file.xml' ); // OK. @@ -147,3 +147,12 @@ file_get_contents( // Not using plugin_dir_path() for reasons. $url ); // Warning. + +/* + * Safeguard correct handling of all types of namespaced function calls + */ +\curl_init(); +MyNamespace\parse_url( 'http://example.com/' ); +\MyNamespace\json_encode( $data ); +namespace\unlink(); // The sniff should start flagging this once it can resolve relative namespaces. +namespace\Sub\strip_tags( $string ); diff --git a/WordPress/Tests/WP/AlternativeFunctionsUnitTest.php b/WordPress/Tests/WP/AlternativeFunctionsUnitTest.php index b0f1bf96aa..e660886adb 100644 --- a/WordPress/Tests/WP/AlternativeFunctionsUnitTest.php +++ b/WordPress/Tests/WP/AlternativeFunctionsUnitTest.php @@ -89,6 +89,7 @@ public function getWarningList() { 131 => 1, 142 => 1, 146 => 1, + 154 => 1, ); } } From 15c8cb7928d4a7dc7caaf33cc47c1798891f1ea0 Mon Sep 17 00:00:00 2001 From: Rodrigo Primo Date: Tue, 16 Sep 2025 15:38:49 -0300 Subject: [PATCH 006/108] WP/AlternativeFunctions: improve regex to distinguish global WP constants/functions from non-WP class-based ones This commit changes two regexes used to identify global WP constants and functions to prevent the sniff from incorrectly identifying class constants/methods with the same names as WordPress globals as being WordPress globals. This is done by adding a negative lookbehind to ensure the searched strings are not preceded by an object operator, null-safe object operator, or scope resolution operator. Fixes part of 2603 --- WordPress/Sniffs/WP/AlternativeFunctionsSniff.php | 4 ++-- WordPress/Tests/WP/AlternativeFunctionsUnitTest.inc | 11 +++++++++++ WordPress/Tests/WP/AlternativeFunctionsUnitTest.php | 6 ++++++ 3 files changed, 19 insertions(+), 2 deletions(-) diff --git a/WordPress/Sniffs/WP/AlternativeFunctionsSniff.php b/WordPress/Sniffs/WP/AlternativeFunctionsSniff.php index 40fb0c61c2..b773036576 100644 --- a/WordPress/Sniffs/WP/AlternativeFunctionsSniff.php +++ b/WordPress/Sniffs/WP/AlternativeFunctionsSniff.php @@ -283,7 +283,7 @@ public function process_matched_token( $stackPtr, $group_name, $matched_content } $contains_wp_path_constant = preg_match( - '`\b(?:ABSPATH|WP_(?:CONTENT|PLUGIN)_DIR|WPMU_PLUGIN_DIR|TEMPLATEPATH|STYLESHEETPATH|(?:MU)?PLUGINDIR)\b`', + '`(?|::)\b(?:ABSPATH|WP_(?:CONTENT|PLUGIN)_DIR|WPMU_PLUGIN_DIR|TEMPLATEPATH|STYLESHEETPATH|(?:MU)?PLUGINDIR)\b`', $filename_param['clean'] ); if ( 1 === $contains_wp_path_constant ) { @@ -292,7 +292,7 @@ public function process_matched_token( $stackPtr, $group_name, $matched_content } $contains_wp_path_function_call = preg_match( - '`(?:get_home_path|plugin_dir_path|get_(?:stylesheet|template)_directory|wp_upload_dir)\s*\(`i', + '`(?|::)(?:get_home_path|plugin_dir_path|get_(?:stylesheet|template)_directory|wp_upload_dir)\s*\(`i', $filename_param['clean'] ); if ( 1 === $contains_wp_path_function_call ) { diff --git a/WordPress/Tests/WP/AlternativeFunctionsUnitTest.inc b/WordPress/Tests/WP/AlternativeFunctionsUnitTest.inc index 6296d75e22..067178fb7a 100644 --- a/WordPress/Tests/WP/AlternativeFunctionsUnitTest.inc +++ b/WordPress/Tests/WP/AlternativeFunctionsUnitTest.inc @@ -156,3 +156,14 @@ MyNamespace\parse_url( 'http://example.com/' ); \MyNamespace\json_encode( $data ); namespace\unlink(); // The sniff should start flagging this once it can resolve relative namespaces. namespace\Sub\strip_tags( $string ); + +/* + * Safeguard that the sniff does not incorrectly ignore class methods/constants with the same + * name as WordPress global functions/constants when used in file_get_contents(). + */ +file_get_contents( MyClass::wp_upload_dir() . 'subdir/file.inc' ); +file_get_contents( $this->GET_HOME_PATH() . 'subdir/file.inc' ); +file_get_contents( $this?->plugin_dir_path() . 'subdir/file.inc' ); +file_get_contents( MyClass::ABSPATH . 'subdir/file.inc' ); +file_get_contents( $this->WPMU_PLUGIN_DIR . 'subdir/file.inc' ); +file_get_contents( $this?->TEMPLATEPATH . 'subdir/file.inc' ); diff --git a/WordPress/Tests/WP/AlternativeFunctionsUnitTest.php b/WordPress/Tests/WP/AlternativeFunctionsUnitTest.php index e660886adb..7aa4dccbb9 100644 --- a/WordPress/Tests/WP/AlternativeFunctionsUnitTest.php +++ b/WordPress/Tests/WP/AlternativeFunctionsUnitTest.php @@ -90,6 +90,12 @@ public function getWarningList() { 142 => 1, 146 => 1, 154 => 1, + 164 => 1, + 165 => 1, + 166 => 1, + 167 => 1, + 168 => 1, + 169 => 1, ); } } From e95a98f54046bd0aa9e98fc66ff3ab023e0fd381 Mon Sep 17 00:00:00 2001 From: Rodrigo Primo Date: Mon, 24 Nov 2025 12:32:47 -0300 Subject: [PATCH 007/108] WP/AlternativeFunctions: fix handling of FQN references to global stream constants This commit fixes the handling of fully qualified name (FQN) references to the global PHP stream constants `\STDIN`, `\STDOUT`, and `\STDERR` by normalizing the passed parameter before checking it against the allowed list. Tests have been added to cover all namespace forms of references to the global PHP stream constants. --- WordPress/Sniffs/WP/AlternativeFunctionsSniff.php | 4 +++- WordPress/Tests/WP/AlternativeFunctionsUnitTest.inc | 13 +++++++++++++ WordPress/Tests/WP/AlternativeFunctionsUnitTest.php | 4 ++++ 3 files changed, 20 insertions(+), 1 deletion(-) diff --git a/WordPress/Sniffs/WP/AlternativeFunctionsSniff.php b/WordPress/Sniffs/WP/AlternativeFunctionsSniff.php index b773036576..9a0a2a9d03 100644 --- a/WordPress/Sniffs/WP/AlternativeFunctionsSniff.php +++ b/WordPress/Sniffs/WP/AlternativeFunctionsSniff.php @@ -353,7 +353,9 @@ public function process_matched_token( $stackPtr, $group_name, $matched_content */ protected function is_local_data_stream( $clean_param_value ) { - $stripped = TextStrings::stripQuotes( $clean_param_value ); + $stripped = TextStrings::stripQuotes( $clean_param_value ); + $clean_param_value = ltrim( $clean_param_value, '\\' ); + if ( isset( $this->allowed_local_streams[ $stripped ] ) || isset( $this->allowed_local_stream_constants[ $clean_param_value ] ) ) { diff --git a/WordPress/Tests/WP/AlternativeFunctionsUnitTest.inc b/WordPress/Tests/WP/AlternativeFunctionsUnitTest.inc index 067178fb7a..70b67b1071 100644 --- a/WordPress/Tests/WP/AlternativeFunctionsUnitTest.inc +++ b/WordPress/Tests/WP/AlternativeFunctionsUnitTest.inc @@ -167,3 +167,16 @@ file_get_contents( $this?->plugin_dir_path() . 'subdir/file.inc' ); file_get_contents( MyClass::ABSPATH . 'subdir/file.inc' ); file_get_contents( $this->WPMU_PLUGIN_DIR . 'subdir/file.inc' ); file_get_contents( $this?->TEMPLATEPATH . 'subdir/file.inc' ); + +/* + * Safeguard correct handling of namespaced variants of STDIN/STDOUT/STDERR constants. + * + * Note: passing stream resources to these functions is not valid PHP and will be addressed in + * https://github.com/WordPress/WordPress-Coding-Standards/issues/2602. These tests document the current behavior of the + * sniff. + */ +fopen( \STDIN, 'r' ); +file_put_contents( MyNamespace\STDOUT, $data ); +file_get_contents( \MyNamespace\STDIN ); +file_put_contents( namespace\STDERR, $data ); // The sniff should not flag this once it can resolve relative namespaces. +readfile( namespace\Sub\STDIN ); diff --git a/WordPress/Tests/WP/AlternativeFunctionsUnitTest.php b/WordPress/Tests/WP/AlternativeFunctionsUnitTest.php index 7aa4dccbb9..58f4083729 100644 --- a/WordPress/Tests/WP/AlternativeFunctionsUnitTest.php +++ b/WordPress/Tests/WP/AlternativeFunctionsUnitTest.php @@ -96,6 +96,10 @@ public function getWarningList() { 167 => 1, 168 => 1, 169 => 1, + 179 => 1, + 180 => 1, + 181 => 1, + 182 => 1, ); } } From bce2f34eb9bbfdf070b23a182b1574cf414f1cb1 Mon Sep 17 00:00:00 2001 From: Rodrigo Primo Date: Wed, 26 Nov 2025 10:05:39 -0300 Subject: [PATCH 008/108] Update `minimum_wp_version` and `testVersion` in `phpcs.xml.dist.sample` This commit updates the example `phpcs.xml.dist.sample` file to reflect that WP 6.6 is now the minimum supported version (three versions behind the latest release). It also updates the `testVersion` property from `7.0-` to `7.2-` since WP 6.6 dropped support for PHP 7.0 and 7.1 (https://make.wordpress.org/core/2024/04/08/dropping-support-for-php-7-1/). --- 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 cfb232b862..60b9c27e9d 100644 --- a/phpcs.xml.dist.sample +++ b/phpcs.xml.dist.sample @@ -78,7 +78,7 @@ https://github.com/PHPCompatibility/PHPCompatibility --> - + From e78587a9bd44e4e566ea1c33353922e08889d6be Mon Sep 17 00:00:00 2001 From: Rodrigo Primo Date: Wed, 26 Nov 2025 10:07:14 -0300 Subject: [PATCH 009/108] Add item about `phpcs.xml.dist.sample` to the release checklist This commit adds an item to verify if the `minimum_wp_version` and `testVersion` properties in `phpcs.xml.dist.sample` need updating as part of the release process. --- .github/release-checklist.md | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/release-checklist.md b/.github/release-checklist.md index c7ce0e5914..234999b496 100644 --- a/.github/release-checklist.md +++ b/.github/release-checklist.md @@ -15,6 +15,7 @@ PR for tracking changes for the x.x.x release. Target release date: **DOW MONTH - [ ] PHPCSUtils: check if there have been [releases][phpcsutils-releases] since the last WordPressCS release and update WordPressCS code to take advantage of any new utilities - PR #xxx - [ ] PHPCSExtra: check if there have been [releases][phpcsextra-releases] since the last WordPressCS release and check through the changelog to see if there is anything WordPressCS could take advantage of - PR #xxx - [ ] Check if the minimum WP version property needs updating in `MinimumWPVersionTrait::$default_minimum_wp_version` and if so, action it - PR #xxx +- [ ] Check if the `minimum_wp_version` and `testVersion` properties in `phpcs.xml.dist.sample` need updating and if so, action it - PR #xxx - [ ] Check if any of the list based sniffs need updating and if so, action it. :pencil2: Make sure the "last updated" annotation in the docblocks for these lists has also been updated! List based sniffs: From 7a6c2e5f738cd60a88756fc40d2c4bd6311faa5d Mon Sep 17 00:00:00 2001 From: Rodrigo Primo Date: Mon, 17 Nov 2025 10:34:08 -0300 Subject: [PATCH 010/108] WP/DiscouragedFunctions: rename test case file Doing this to be able to move an intentional syntax error test to its own file. --- ...inc => DiscouragedFunctionsUnitTest.1.inc} | 0 .../Tests/WP/DiscouragedFunctionsUnitTest.php | 30 ++++++++++++------- 2 files changed, 19 insertions(+), 11 deletions(-) rename WordPress/Tests/WP/{DiscouragedFunctionsUnitTest.inc => DiscouragedFunctionsUnitTest.1.inc} (100%) diff --git a/WordPress/Tests/WP/DiscouragedFunctionsUnitTest.inc b/WordPress/Tests/WP/DiscouragedFunctionsUnitTest.1.inc similarity index 100% rename from WordPress/Tests/WP/DiscouragedFunctionsUnitTest.inc rename to WordPress/Tests/WP/DiscouragedFunctionsUnitTest.1.inc diff --git a/WordPress/Tests/WP/DiscouragedFunctionsUnitTest.php b/WordPress/Tests/WP/DiscouragedFunctionsUnitTest.php index 825ff39702..e780d96c4b 100644 --- a/WordPress/Tests/WP/DiscouragedFunctionsUnitTest.php +++ b/WordPress/Tests/WP/DiscouragedFunctionsUnitTest.php @@ -36,18 +36,26 @@ 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( - 3 => 1, - 4 => 1, - 20 => 1, - 33 => 1, - 34 => 1, - 53 => 1, - 62 => 1, - 65 => 1, - ); + public function getWarningList( $testFile = '' ) { + switch ( $testFile ) { + case 'DiscouragedFunctionsUnitTest.1.inc': + return array( + 3 => 1, + 4 => 1, + 20 => 1, + 33 => 1, + 34 => 1, + 53 => 1, + 62 => 1, + 65 => 1, + ); + + default: + return array(); + } } } From 214ff6f021057a48fbcd335d8e907d4ab8705a9a Mon Sep 17 00:00:00 2001 From: Rodrigo Primo Date: Mon, 17 Nov 2025 10:36:35 -0300 Subject: [PATCH 011/108] WP/DiscouragedFunctions: move syntax error test to its own file --- WordPress/Tests/WP/DiscouragedFunctionsUnitTest.1.inc | 4 ---- WordPress/Tests/WP/DiscouragedFunctionsUnitTest.2.inc | 8 ++++++++ 2 files changed, 8 insertions(+), 4 deletions(-) create mode 100644 WordPress/Tests/WP/DiscouragedFunctionsUnitTest.2.inc diff --git a/WordPress/Tests/WP/DiscouragedFunctionsUnitTest.1.inc b/WordPress/Tests/WP/DiscouragedFunctionsUnitTest.1.inc index 66a33f4984..b434371143 100644 --- a/WordPress/Tests/WP/DiscouragedFunctionsUnitTest.1.inc +++ b/WordPress/Tests/WP/DiscouragedFunctionsUnitTest.1.inc @@ -63,7 +63,3 @@ wp_reset_query(); // OK, excluded group. // Safeguard that a function used as a PHP 8.1+ first class callable is also flagged. call_user_func( query_posts(...), $param ); // Warning. - -// Live coding/parse error. -// This has to be the last test in the file!!! -\query_posts diff --git a/WordPress/Tests/WP/DiscouragedFunctionsUnitTest.2.inc b/WordPress/Tests/WP/DiscouragedFunctionsUnitTest.2.inc new file mode 100644 index 0000000000..0476780120 --- /dev/null +++ b/WordPress/Tests/WP/DiscouragedFunctionsUnitTest.2.inc @@ -0,0 +1,8 @@ + Date: Tue, 9 Sep 2025 11:12:03 -0300 Subject: [PATCH 012/108] Tests: non-standard case function call tests for sniffs extending `AbstractFunctionRestrictionsSniff` This commit ensures that the tests for all sniffs extending the `AbstractFunctionRestrictionsSniff` class contain a test with a non-standard case, an unqualified, and a fully qualified function call. In some cases, it was possible to update an existing test, and in other cases, it was necessary to add a new one. For small test files, new tests were inserted alongside related existing tests (rather than appended at the end) to keep similar test cases grouped. The improved test organization should outweigh the added review complexity due to the need to update line numbers in test expectations. Two sniffs that extend `AbstractFunctionRestrictionsSniff` will be addressed separately: `WordPress.Security.EscapeOutput` and `WordPress.WP.AlternativeFunctions`. --- WordPress/Tests/DB/RestrictedFunctionsUnitTest.inc | 4 ++-- WordPress/Tests/DateTime/RestrictedFunctionsUnitTest.inc | 3 ++- WordPress/Tests/DateTime/RestrictedFunctionsUnitTest.php | 1 + WordPress/Tests/PHP/DevelopmentFunctionsUnitTest.inc | 2 +- WordPress/Tests/PHP/DiscouragedPHPFunctionsUnitTest.inc | 4 ++-- WordPress/Tests/PHP/DontExtractUnitTest.inc | 2 ++ WordPress/Tests/PHP/DontExtractUnitTest.php | 4 +++- WordPress/Tests/PHP/POSIXFunctionsUnitTest.inc | 4 ++-- WordPress/Tests/PHP/RestrictedPHPFunctionsUnitTest.inc | 2 ++ WordPress/Tests/PHP/RestrictedPHPFunctionsUnitTest.php | 4 +++- WordPress/Tests/Security/SafeRedirectUnitTest.inc | 2 ++ WordPress/Tests/Security/SafeRedirectUnitTest.php | 6 ++++-- WordPress/Tests/WP/DeprecatedFunctionsUnitTest.1.inc | 1 + WordPress/Tests/WP/DeprecatedFunctionsUnitTest.2.inc | 1 + WordPress/Tests/WP/DeprecatedFunctionsUnitTest.php | 3 ++- WordPress/Tests/WP/DiscouragedFunctionsUnitTest.1.inc | 4 ++-- 16 files changed, 32 insertions(+), 15 deletions(-) diff --git a/WordPress/Tests/DB/RestrictedFunctionsUnitTest.inc b/WordPress/Tests/DB/RestrictedFunctionsUnitTest.inc index 3bebe1fdc2..2a039f9a06 100644 --- a/WordPress/Tests/DB/RestrictedFunctionsUnitTest.inc +++ b/WordPress/Tests/DB/RestrictedFunctionsUnitTest.inc @@ -23,8 +23,8 @@ prefix_mysql_info(); // Ok. // MYSQL Extension. mysql_affected_rows(); -mysql_connect(); -mysql_close(); +Mysql_CONNECT(); +\MYSQL_close(); mysql_fetch_row(); mysql_info(); mysql_numrows(); diff --git a/WordPress/Tests/DateTime/RestrictedFunctionsUnitTest.inc b/WordPress/Tests/DateTime/RestrictedFunctionsUnitTest.inc index f96842c9e7..c002d706dc 100644 --- a/WordPress/Tests/DateTime/RestrictedFunctionsUnitTest.inc +++ b/WordPress/Tests/DateTime/RestrictedFunctionsUnitTest.inc @@ -5,13 +5,14 @@ date_default_timezone_set( 'Foo/Bar' ); // Bad. $date = new DateTime(); $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' ), 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' ); +\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 a2f29c2364..8a37da1c3a 100644 --- a/WordPress/Tests/DateTime/RestrictedFunctionsUnitTest.php +++ b/WordPress/Tests/DateTime/RestrictedFunctionsUnitTest.php @@ -30,6 +30,7 @@ public function getErrorList() { 3 => 1, 8 => 2, 14 => 1, + 15 => 1, ); } diff --git a/WordPress/Tests/PHP/DevelopmentFunctionsUnitTest.inc b/WordPress/Tests/PHP/DevelopmentFunctionsUnitTest.inc index ada6fa9b4a..bdc7c22cc1 100644 --- a/WordPress/Tests/PHP/DevelopmentFunctionsUnitTest.inc +++ b/WordPress/Tests/PHP/DevelopmentFunctionsUnitTest.inc @@ -30,7 +30,7 @@ phpinfo(); // Ok - within excluded group. // Reset group exclusions. // phpcs:set WordPress.PHP.DevelopmentFunctions exclude[] -trigger_error(); // Error. +\TRIGGER_ERROR(); // Error. phpinfo(); // Error. Wrapper_Class::var_dump(); // OK, not the native PHP function. diff --git a/WordPress/Tests/PHP/DiscouragedPHPFunctionsUnitTest.inc b/WordPress/Tests/PHP/DiscouragedPHPFunctionsUnitTest.inc index 84b7378b65..492c779524 100644 --- a/WordPress/Tests/PHP/DiscouragedPHPFunctionsUnitTest.inc +++ b/WordPress/Tests/PHP/DiscouragedPHPFunctionsUnitTest.inc @@ -7,7 +7,7 @@ namespace\serialize( $value ); // The sniff should start flagging this once it c serialize(); // Warning. \serialize( $value ); // Warning. -unserialize(); // Warning. +UNserialize(); // Warning. urlencode(); // Warning. rawurlencode(); // Ok. @@ -19,7 +19,7 @@ ini_restore(); // Warning. magic_quotes_runtime(); // Warning. set_magic_quotes_runtime(); // Warning. apache_setenv(); // Warning. -putenv(); // Warning. +\PUTENV(); // Warning. set_include_path(); // Warning. restore_include_path(); // Warning. diff --git a/WordPress/Tests/PHP/DontExtractUnitTest.inc b/WordPress/Tests/PHP/DontExtractUnitTest.inc index 7cf000403c..79bb1d3bf0 100644 --- a/WordPress/Tests/PHP/DontExtractUnitTest.inc +++ b/WordPress/Tests/PHP/DontExtractUnitTest.inc @@ -1,6 +1,7 @@ 1 ) ); // Bad. +exTRAct( array( 'a' => 1 ) ); // Bad. // Similarly named functions or methods however are fine. my_extract(); // Ok. @@ -12,6 +13,7 @@ $my_object->extract(); // Ok. * Safeguard correct handling of all types of namespaced function calls. */ \extract( array( 'a' => 1 ) ); +\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 f9a1df7494..52d6fdeb65 100644 --- a/WordPress/Tests/PHP/DontExtractUnitTest.php +++ b/WordPress/Tests/PHP/DontExtractUnitTest.php @@ -30,7 +30,9 @@ final class DontExtractUnitTest extends AbstractSniffUnitTest { public function getErrorList() { return array( 3 => 1, - 14 => 1, + 4 => 1, + 15 => 1, + 16 => 1, ); } diff --git a/WordPress/Tests/PHP/POSIXFunctionsUnitTest.inc b/WordPress/Tests/PHP/POSIXFunctionsUnitTest.inc index b3bb11a71c..32902c7952 100644 --- a/WordPress/Tests/PHP/POSIXFunctionsUnitTest.inc +++ b/WordPress/Tests/PHP/POSIXFunctionsUnitTest.inc @@ -13,9 +13,9 @@ $title = preg_split( 'cool', get_the_title() ); // Good. if ( ereg( '[A-Za-z]+', $title, $regs ) ) // Bad, ereg deprecated. Use preg_match instead. die( $regs ); -if ( eregi( '[a-z]+', $title, $regs ) ) {} // Bad, eregi deprecated. Use preg_match instead. +if ( \EREGI( '[a-z]+', $title, $regs ) ) {} // Bad, eregi deprecated. Use preg_match instead. -$title = ereg_replace( 'cool', 'not cool', get_the_title() ); // Bad, ereg_replace has been deprecated. Use preg_replace instead. +$title = ereg_REPLACE( 'cool', 'not cool', get_the_title() ); // Bad, ereg_replace has been deprecated. Use preg_replace instead. $title = eregi_replace( 'cool', 'not cool', get_the_title() ); // Bad, eregi_replace also deprecated. Use preg_replace instead. diff --git a/WordPress/Tests/PHP/RestrictedPHPFunctionsUnitTest.inc b/WordPress/Tests/PHP/RestrictedPHPFunctionsUnitTest.inc index 09465fa6c5..88c02ba80d 100644 --- a/WordPress/Tests/PHP/RestrictedPHPFunctionsUnitTest.inc +++ b/WordPress/Tests/PHP/RestrictedPHPFunctionsUnitTest.inc @@ -3,11 +3,13 @@ add_action( 'widgets_init', create_function( '', // Error. 'return register_widget( "time_more_on_time_widget" );' ) ); +CREATE_function( '', '' ); // Error. /* * Safeguard correct handling of all types of namespaced function calls. */ \create_function('', 'return;'); +\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 5cfa75ae51..a596706030 100644 --- a/WordPress/Tests/PHP/RestrictedPHPFunctionsUnitTest.php +++ b/WordPress/Tests/PHP/RestrictedPHPFunctionsUnitTest.php @@ -28,7 +28,9 @@ final class RestrictedPHPFunctionsUnitTest extends AbstractSniffUnitTest { public function getErrorList() { return array( 3 => 1, - 10 => 1, + 6 => 1, + 11 => 1, + 12 => 1, ); } diff --git a/WordPress/Tests/Security/SafeRedirectUnitTest.inc b/WordPress/Tests/Security/SafeRedirectUnitTest.inc index 3d8d19c02a..3f72f1b33c 100644 --- a/WordPress/Tests/Security/SafeRedirectUnitTest.inc +++ b/WordPress/Tests/Security/SafeRedirectUnitTest.inc @@ -1,12 +1,14 @@ 1, - 9 => 1, + 3 => 1, + 4 => 1, + 10 => 1, + 11 => 1, ); } } diff --git a/WordPress/Tests/WP/DeprecatedFunctionsUnitTest.1.inc b/WordPress/Tests/WP/DeprecatedFunctionsUnitTest.1.inc index 57a44658ef..291eefdc78 100644 --- a/WordPress/Tests/WP/DeprecatedFunctionsUnitTest.1.inc +++ b/WordPress/Tests/WP/DeprecatedFunctionsUnitTest.1.inc @@ -444,3 +444,4 @@ wp_add_editor_classic_theme_styles(); /* ============ WP 6.9 ============ */ seems_utf8(); wp_print_auto_sizes_contain_css_fix(); +wp_PRINT_auto_SIZES_contain_CSS_fix(); diff --git a/WordPress/Tests/WP/DeprecatedFunctionsUnitTest.2.inc b/WordPress/Tests/WP/DeprecatedFunctionsUnitTest.2.inc index 6c2a7bb8e1..0125f2962c 100644 --- a/WordPress/Tests/WP/DeprecatedFunctionsUnitTest.2.inc +++ b/WordPress/Tests/WP/DeprecatedFunctionsUnitTest.2.inc @@ -4,6 +4,7 @@ * Safeguard correct handling of all types of namespaced function calls. */ \the_category_ID(); +\THE_category_id(); MyNamespace\the_category_ID(); \MyNamespace\the_category_ID(); namespace\the_category_ID(); // The sniff should start flagging this once it can resolve relative namespaces. diff --git a/WordPress/Tests/WP/DeprecatedFunctionsUnitTest.php b/WordPress/Tests/WP/DeprecatedFunctionsUnitTest.php index 6931a37a9b..2d75be123c 100644 --- a/WordPress/Tests/WP/DeprecatedFunctionsUnitTest.php +++ b/WordPress/Tests/WP/DeprecatedFunctionsUnitTest.php @@ -93,6 +93,7 @@ public function getErrorList( $testFile = '' ) { case 'DeprecatedFunctionsUnitTest.2.inc': return array( 6 => 1, + 7 => 1, ); default: @@ -111,7 +112,7 @@ public function getWarningList( $testFile = '' ) { switch ( $testFile ) { case 'DeprecatedFunctionsUnitTest.1.inc': $start_line = 430; - $end_line = 446; + $end_line = 447; $warnings = array_fill( $start_line, ( ( $end_line - $start_line ) + 1 ), 1 ); // Unset the lines related to version comments. diff --git a/WordPress/Tests/WP/DiscouragedFunctionsUnitTest.1.inc b/WordPress/Tests/WP/DiscouragedFunctionsUnitTest.1.inc index b434371143..9d7a422080 100644 --- a/WordPress/Tests/WP/DiscouragedFunctionsUnitTest.1.inc +++ b/WordPress/Tests/WP/DiscouragedFunctionsUnitTest.1.inc @@ -1,7 +1,7 @@ Date: Mon, 17 Nov 2025 11:04:08 -0300 Subject: [PATCH 013/108] Tests: add `namespace\Sub\` tests for sniffs extending `AbstractFunctionRestrictionsSniff` This commit adds `namespace\Sub\function_name()` test cases to all test files for sniffs extending `AbstractFunctionRestrictionsSniff`. Two sniffs that extend `AbstractFunctionRestrictionsSniff` will be addressed separately: `WordPress.Security.EscapeOutput` and `WordPress.WP.AlternativeFunctions`. --- .../Tests/DB/RestrictedFunctionsUnitTest.inc | 1 + .../DateTime/RestrictedFunctionsUnitTest.inc | 1 + .../PHP/DevelopmentFunctionsUnitTest.inc | 1 + .../PHP/DiscouragedPHPFunctionsUnitTest.inc | 16 ++++++++++---- WordPress/Tests/PHP/DontExtractUnitTest.inc | 1 + .../Tests/PHP/POSIXFunctionsUnitTest.inc | 1 + .../PHP/RestrictedPHPFunctionsUnitTest.inc | 1 + .../Tests/Security/SafeRedirectUnitTest.inc | 1 + .../WP/DeprecatedFunctionsUnitTest.2.inc | 1 + .../WP/DiscouragedFunctionsUnitTest.1.inc | 21 +++++++++++++------ .../Tests/WP/DiscouragedFunctionsUnitTest.php | 2 +- 11 files changed, 36 insertions(+), 11 deletions(-) diff --git a/WordPress/Tests/DB/RestrictedFunctionsUnitTest.inc b/WordPress/Tests/DB/RestrictedFunctionsUnitTest.inc index 2a039f9a06..c4e195fd45 100644 --- a/WordPress/Tests/DB/RestrictedFunctionsUnitTest.inc +++ b/WordPress/Tests/DB/RestrictedFunctionsUnitTest.inc @@ -102,3 +102,4 @@ Myfictional(); // OK. MyNamespace\mysql_connect(); \MyNamespace\mysql_connect(); namespace\mysql_connect(); // The sniff should start flagging this once it can resolve relative namespaces. +namespace\Sub\mysql_connect(); diff --git a/WordPress/Tests/DateTime/RestrictedFunctionsUnitTest.inc b/WordPress/Tests/DateTime/RestrictedFunctionsUnitTest.inc index c002d706dc..d2c9e1f160 100644 --- a/WordPress/Tests/DateTime/RestrictedFunctionsUnitTest.inc +++ b/WordPress/Tests/DateTime/RestrictedFunctionsUnitTest.inc @@ -16,3 +16,4 @@ $post_data['post_title'] = sprintf( __( 'Draft created on %1$s at %2$s' ), gmdat 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. +namespace\Sub\date_default_timezone_set( 'Foo/Bar' ); diff --git a/WordPress/Tests/PHP/DevelopmentFunctionsUnitTest.inc b/WordPress/Tests/PHP/DevelopmentFunctionsUnitTest.inc index bdc7c22cc1..daa215fe1d 100644 --- a/WordPress/Tests/PHP/DevelopmentFunctionsUnitTest.inc +++ b/WordPress/Tests/PHP/DevelopmentFunctionsUnitTest.inc @@ -43,3 +43,4 @@ $wrapper ->var_dump(); // OK, not the native PHP function. MyNamespace\var_dump( $value ); \MyNamespace\var_dump( $value ); namespace\var_dump( $value ); // The sniff should start flagging this once it can resolve relative namespaces. +namespace\Sub\var_dump( $value ); diff --git a/WordPress/Tests/PHP/DiscouragedPHPFunctionsUnitTest.inc b/WordPress/Tests/PHP/DiscouragedPHPFunctionsUnitTest.inc index 492c779524..636c384e60 100644 --- a/WordPress/Tests/PHP/DiscouragedPHPFunctionsUnitTest.inc +++ b/WordPress/Tests/PHP/DiscouragedPHPFunctionsUnitTest.inc @@ -1,9 +1,9 @@ extract(); // Ok. 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. +namespace\Sub\extract( array( 'a' => 1 ) ); diff --git a/WordPress/Tests/PHP/POSIXFunctionsUnitTest.inc b/WordPress/Tests/PHP/POSIXFunctionsUnitTest.inc index 32902c7952..a50f77a6fa 100644 --- a/WordPress/Tests/PHP/POSIXFunctionsUnitTest.inc +++ b/WordPress/Tests/PHP/POSIXFunctionsUnitTest.inc @@ -32,3 +32,4 @@ sql_regcase( 'Foo - bar.'); // Bad. Deprecated. MyNamespace\split( ':', $date ); \MyNamespace\split( ':', $date ); namespace\split( ':', $date ); // The sniff should start flagging this once it can resolve relative namespaces. +namespace\Sub\split( ':', $date ); diff --git a/WordPress/Tests/PHP/RestrictedPHPFunctionsUnitTest.inc b/WordPress/Tests/PHP/RestrictedPHPFunctionsUnitTest.inc index 88c02ba80d..bada4800a3 100644 --- a/WordPress/Tests/PHP/RestrictedPHPFunctionsUnitTest.inc +++ b/WordPress/Tests/PHP/RestrictedPHPFunctionsUnitTest.inc @@ -13,3 +13,4 @@ CREATE_function( '', '' ); // Error. MyNamespace\create_function('', 'return;'); \MyNamespace\create_function('', 'return;'); namespace\create_function('', 'return;'); // The sniff should start flagging this once it can resolve relative namespaces. +namespace\Sub\create_function('', 'return;'); diff --git a/WordPress/Tests/Security/SafeRedirectUnitTest.inc b/WordPress/Tests/Security/SafeRedirectUnitTest.inc index 3f72f1b33c..28d8a7b0a8 100644 --- a/WordPress/Tests/Security/SafeRedirectUnitTest.inc +++ b/WordPress/Tests/Security/SafeRedirectUnitTest.inc @@ -12,3 +12,4 @@ wp_safe_redirect( $location ); // OK. MyNamespace\wp_redirect( $location ); \MyNamespace\wp_redirect( $location ); namespace\wp_redirect( $location ); // The sniff should start flagging this once it can resolve relative namespaces. +namespace\Sub\wp_redirect( $location ); diff --git a/WordPress/Tests/WP/DeprecatedFunctionsUnitTest.2.inc b/WordPress/Tests/WP/DeprecatedFunctionsUnitTest.2.inc index 0125f2962c..fbdb4650a3 100644 --- a/WordPress/Tests/WP/DeprecatedFunctionsUnitTest.2.inc +++ b/WordPress/Tests/WP/DeprecatedFunctionsUnitTest.2.inc @@ -8,3 +8,4 @@ MyNamespace\the_category_ID(); \MyNamespace\the_category_ID(); namespace\the_category_ID(); // The sniff should start flagging this once it can resolve relative namespaces. +namespace\Sub\the_category_ID(); diff --git a/WordPress/Tests/WP/DiscouragedFunctionsUnitTest.1.inc b/WordPress/Tests/WP/DiscouragedFunctionsUnitTest.1.inc index 9d7a422080..6a2194a64e 100644 --- a/WordPress/Tests/WP/DiscouragedFunctionsUnitTest.1.inc +++ b/WordPress/Tests/WP/DiscouragedFunctionsUnitTest.1.inc @@ -12,12 +12,12 @@ $obj->query_posts(); // OK, not the global function. MyClass::wp_reset_query(); // OK, not the global function. $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. + + + + + + // Ensure the sniff doesn't act on functions not listed in the target functions array. query_post(); // OK, not one of the target functions. @@ -63,3 +63,12 @@ wp_reset_query(); // OK, excluded group. // Safeguard that a function used as a PHP 8.1+ first class callable is also flagged. call_user_func( query_posts(...), $param ); // Warning. + +/* + * Safeguard correct handling of all types of namespaced function calls. + */ +\query_POSTS(); // Warning. +MyNamespace\query_posts(); // OK, not the global function. +\MyNamespace\query_posts(); // OK, not the global function. +namespace\query_posts(); // OK, not the global function. +namespace\Sub\query_posts(); // OK, not the global function. diff --git a/WordPress/Tests/WP/DiscouragedFunctionsUnitTest.php b/WordPress/Tests/WP/DiscouragedFunctionsUnitTest.php index e780d96c4b..67031257c3 100644 --- a/WordPress/Tests/WP/DiscouragedFunctionsUnitTest.php +++ b/WordPress/Tests/WP/DiscouragedFunctionsUnitTest.php @@ -46,12 +46,12 @@ public function getWarningList( $testFile = '' ) { return array( 3 => 1, 4 => 1, - 20 => 1, 33 => 1, 34 => 1, 53 => 1, 62 => 1, 65 => 1, + 70 => 1, ); default: From a6c038010416bb20616eab3a27d05847f72eeb9c Mon Sep 17 00:00:00 2001 From: Rodrigo Primo Date: Mon, 17 Nov 2025 11:39:12 -0300 Subject: [PATCH 014/108] Tests: vary function names in namespace tests for sniffs extending `AbstractFunctionRestrictionsSniff` As suggested in 2581, for sniffs that check multiple functions, the namespace name tests now use different function names rather than repeatedly testing the same function. Two sniffs that extend `AbstractFunctionRestrictionsSniff` will be addressed separately: `WordPress.Security.EscapeOutput` and `WordPress.WP.AlternativeFunctions`. --- WordPress/Tests/DB/RestrictedFunctionsUnitTest.inc | 8 ++++---- WordPress/Tests/DateTime/RestrictedFunctionsUnitTest.inc | 4 ++-- WordPress/Tests/PHP/DevelopmentFunctionsUnitTest.inc | 8 ++++---- WordPress/Tests/PHP/DiscouragedPHPFunctionsUnitTest.inc | 8 ++++---- WordPress/Tests/PHP/POSIXFunctionsUnitTest.inc | 8 ++++---- WordPress/Tests/WP/DeprecatedFunctionsUnitTest.2.inc | 8 ++++---- WordPress/Tests/WP/DiscouragedFunctionsUnitTest.1.inc | 4 ++-- 7 files changed, 24 insertions(+), 24 deletions(-) diff --git a/WordPress/Tests/DB/RestrictedFunctionsUnitTest.inc b/WordPress/Tests/DB/RestrictedFunctionsUnitTest.inc index c4e195fd45..d570897176 100644 --- a/WordPress/Tests/DB/RestrictedFunctionsUnitTest.inc +++ b/WordPress/Tests/DB/RestrictedFunctionsUnitTest.inc @@ -99,7 +99,7 @@ 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. -namespace\Sub\mysql_connect(); +MyNamespace\mysqli_init(); +\MyNamespace\mysqlnd_qc_clear_cache(); +namespace\maxdb_close(); // The sniff should start flagging this once it can resolve relative namespaces. +namespace\Sub\mysqli_fetch(); diff --git a/WordPress/Tests/DateTime/RestrictedFunctionsUnitTest.inc b/WordPress/Tests/DateTime/RestrictedFunctionsUnitTest.inc index d2c9e1f160..e9c010e8a8 100644 --- a/WordPress/Tests/DateTime/RestrictedFunctionsUnitTest.inc +++ b/WordPress/Tests/DateTime/RestrictedFunctionsUnitTest.inc @@ -13,7 +13,7 @@ $post_data['post_title'] = sprintf( __( 'Draft created on %1$s at %2$s' ), gmdat */ \date_default_timezone_set( 'Foo/Bar' ); \DATE_default_timezone_SET( 'Foo/Bar' ); -MyNamespace\date_default_timezone_set( 'Foo/Bar' ); +MyNamespace\date( 'Y-m-d' ); \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. +namespace\date( 'Y-m-d' ); // The sniff should start flagging this once it can resolve relative namespaces. namespace\Sub\date_default_timezone_set( 'Foo/Bar' ); diff --git a/WordPress/Tests/PHP/DevelopmentFunctionsUnitTest.inc b/WordPress/Tests/PHP/DevelopmentFunctionsUnitTest.inc index daa215fe1d..963e06888a 100644 --- a/WordPress/Tests/PHP/DevelopmentFunctionsUnitTest.inc +++ b/WordPress/Tests/PHP/DevelopmentFunctionsUnitTest.inc @@ -40,7 +40,7 @@ $wrapper ->var_dump(); // OK, not the native PHP 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. -namespace\Sub\var_dump( $value ); +MyNamespace\phpinfo(); +\MyNamespace\print_r( $value ); +namespace\error_reporting(); // The sniff should start flagging this once it can resolve relative namespaces. +namespace\Sub\debug_backtrace(); diff --git a/WordPress/Tests/PHP/DiscouragedPHPFunctionsUnitTest.inc b/WordPress/Tests/PHP/DiscouragedPHPFunctionsUnitTest.inc index 636c384e60..d79d88abd6 100644 --- a/WordPress/Tests/PHP/DiscouragedPHPFunctionsUnitTest.inc +++ b/WordPress/Tests/PHP/DiscouragedPHPFunctionsUnitTest.inc @@ -45,7 +45,7 @@ class Serialize {} /* * Safeguard correct handling of all types of namespaced function calls. */ -MyNamespace\serialize( $value ); -\MyNamespace\serialize( $value ); -namespace\serialize( $value ); // The sniff should start flagging this once it can resolve relative namespaces. -namespace\Sub\serialize( $value ); +MyNamespace\urlencode( $value ); +\MyNamespace\putenv( $value ); +namespace\exec( $command ); // The sniff should start flagging this once it can resolve relative namespaces. +namespace\Sub\base64_decode( $value ); diff --git a/WordPress/Tests/PHP/POSIXFunctionsUnitTest.inc b/WordPress/Tests/PHP/POSIXFunctionsUnitTest.inc index a50f77a6fa..7d34f92fe9 100644 --- a/WordPress/Tests/PHP/POSIXFunctionsUnitTest.inc +++ b/WordPress/Tests/PHP/POSIXFunctionsUnitTest.inc @@ -29,7 +29,7 @@ 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. -namespace\Sub\split( ':', $date ); +MyNamespace\ereg( 'pattern', $string ); +\MyNamespace\ereg_replace( 'pattern', 'replacement', $string ); +namespace\spliti( ':', $date ); // The sniff should start flagging this once it can resolve relative namespaces. +namespace\Sub\sql_regcase( 'string' ); diff --git a/WordPress/Tests/WP/DeprecatedFunctionsUnitTest.2.inc b/WordPress/Tests/WP/DeprecatedFunctionsUnitTest.2.inc index fbdb4650a3..87418bf766 100644 --- a/WordPress/Tests/WP/DeprecatedFunctionsUnitTest.2.inc +++ b/WordPress/Tests/WP/DeprecatedFunctionsUnitTest.2.inc @@ -5,7 +5,7 @@ */ \the_category_ID(); \THE_category_id(); -MyNamespace\the_category_ID(); -\MyNamespace\the_category_ID(); -namespace\the_category_ID(); // The sniff should start flagging this once it can resolve relative namespaces. -namespace\Sub\the_category_ID(); +MyNamespace\permalink_link(); +\MyNamespace\get_postdata(); +namespace\create_user(); // The sniff should start flagging this once it can resolve relative namespaces. +namespace\Sub\user_can_edit_post(); diff --git a/WordPress/Tests/WP/DiscouragedFunctionsUnitTest.1.inc b/WordPress/Tests/WP/DiscouragedFunctionsUnitTest.1.inc index 6a2194a64e..067a7907a5 100644 --- a/WordPress/Tests/WP/DiscouragedFunctionsUnitTest.1.inc +++ b/WordPress/Tests/WP/DiscouragedFunctionsUnitTest.1.inc @@ -68,7 +68,7 @@ call_user_func( query_posts(...), $param ); // Warning. * Safeguard correct handling of all types of namespaced function calls. */ \query_POSTS(); // Warning. -MyNamespace\query_posts(); // OK, not the global function. +MyNamespace\wp_reset_query(); // OK, not the global function. \MyNamespace\query_posts(); // OK, not the global function. -namespace\query_posts(); // OK, not the global function. +namespace\wp_reset_query(); // OK, not the global function. namespace\Sub\query_posts(); // OK, not the global function. From 3acb1319c21bacb0bae2323fe667ea1e345f6c1d Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 1 Dec 2025 10:53:01 +0000 Subject: [PATCH 015/108] GH Actions: Bump the action-runners group with 2 updates Bumps the action-runners group with 2 updates: [shivammathur/setup-php](https://github.com/shivammathur/setup-php) and [crate-ci/typos](https://github.com/crate-ci/typos). Updates `shivammathur/setup-php` from 2.35.5 to 2.36.0 - [Release notes](https://github.com/shivammathur/setup-php/releases) - [Commits](https://github.com/shivammathur/setup-php/compare/bf6b4fbd49ca58e4608c9c89fba0b8d90bd2a39f...44454db4f0199b8b9685a5d763dc37cbf79108e1) Updates `crate-ci/typos` from 1.39.2 to 1.40.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/626c4bedb751ce0b7f03262ca97ddda9a076ae1c...2d0ce569feab1f8752f1dde43cc2f2aa53236e06) --- updated-dependencies: - dependency-name: shivammathur/setup-php dependency-version: 2.36.0 dependency-type: direct:production update-type: version-update:semver-minor dependency-group: action-runners - dependency-name: crate-ci/typos dependency-version: 1.40.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 | 8 ++++---- .github/workflows/quicktest.yml | 2 +- .github/workflows/unit-tests.yml | 2 +- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/.github/workflows/basic-qa.yml b/.github/workflows/basic-qa.yml index 10a1ec6263..6b073d23d7 100644 --- a/.github/workflows/basic-qa.yml +++ b/.github/workflows/basic-qa.yml @@ -31,7 +31,7 @@ jobs: persist-credentials: false - name: Setup PHP - uses: shivammathur/setup-php@bf6b4fbd49ca58e4608c9c89fba0b8d90bd2a39f # 2.35.5 + uses: shivammathur/setup-php@44454db4f0199b8b9685a5d763dc37cbf79108e1 # 2.36.0 with: php-version: 'latest' coverage: none @@ -162,7 +162,7 @@ jobs: persist-credentials: false - name: Set up PHP - uses: shivammathur/setup-php@bf6b4fbd49ca58e4608c9c89fba0b8d90bd2a39f # 2.35.5 + uses: shivammathur/setup-php@44454db4f0199b8b9685a5d763dc37cbf79108e1 # 2.36.0 with: php-version: ${{ matrix.php }} # Allow for PHP deprecation notices. @@ -245,7 +245,7 @@ jobs: persist-credentials: false - name: Install PHP - uses: shivammathur/setup-php@bf6b4fbd49ca58e4608c9c89fba0b8d90bd2a39f # 2.35.5 + uses: shivammathur/setup-php@44454db4f0199b8b9685a5d763dc37cbf79108e1 # 2.36.0 with: php-version: 'latest' coverage: none @@ -275,4 +275,4 @@ jobs: persist-credentials: false - name: "Search for misspellings" - uses: "crate-ci/typos@626c4bedb751ce0b7f03262ca97ddda9a076ae1c" # v1.39.2 + uses: "crate-ci/typos@2d0ce569feab1f8752f1dde43cc2f2aa53236e06" # v1.40.0 diff --git a/.github/workflows/quicktest.yml b/.github/workflows/quicktest.yml index 5ee925db9e..bf16702d7e 100644 --- a/.github/workflows/quicktest.yml +++ b/.github/workflows/quicktest.yml @@ -35,7 +35,7 @@ jobs: persist-credentials: false - name: Set up PHP - uses: shivammathur/setup-php@bf6b4fbd49ca58e4608c9c89fba0b8d90bd2a39f # 2.35.5 + uses: shivammathur/setup-php@44454db4f0199b8b9685a5d763dc37cbf79108e1 # 2.36.0 with: php-version: ${{ matrix.php }} # With stable PHPCS dependencies, allow for PHP deprecation notices. diff --git a/.github/workflows/unit-tests.yml b/.github/workflows/unit-tests.yml index 2bcae652cc..ae91294a87 100644 --- a/.github/workflows/unit-tests.yml +++ b/.github/workflows/unit-tests.yml @@ -90,7 +90,7 @@ jobs: fi - name: Set up PHP - uses: shivammathur/setup-php@bf6b4fbd49ca58e4608c9c89fba0b8d90bd2a39f # 2.35.5 + uses: shivammathur/setup-php@44454db4f0199b8b9685a5d763dc37cbf79108e1 # 2.36.0 with: php-version: ${{ matrix.php }} ini-values: ${{ steps.set_ini.outputs.PHP_INI }} From 513f9b38149316e1addcd7473eb4b05e3426faa4 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 8 Dec 2025 09:06:32 +0000 Subject: [PATCH 016/108] GH Actions: Bump actions/checkout in the action-runners group Bumps the action-runners group with 1 update: [actions/checkout](https://github.com/actions/checkout). Updates `actions/checkout` from 6.0.0 to 6.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/1af3b93b6815bc44a9784bd300feb67ff0d1eeb3...8e8c483db84b4bee98b60c0593521ed34d9990e8) --- updated-dependencies: - dependency-name: actions/checkout dependency-version: 6.0.1 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: action-runners ... 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 6b073d23d7..81f0477c29 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@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0 + uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1 with: persist-credentials: false @@ -117,7 +117,7 @@ jobs: steps: - name: Checkout code - uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0 + uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1 with: persist-credentials: false @@ -157,7 +157,7 @@ jobs: steps: - name: Checkout repository - uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0 + uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1 with: persist-credentials: false @@ -240,7 +240,7 @@ jobs: steps: - name: Checkout code - uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0 + uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1 with: persist-credentials: false @@ -270,7 +270,7 @@ jobs: steps: - name: "Checkout" - uses: "actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3" # v6.0.0 + uses: "actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8" # v6.0.1 with: persist-credentials: false diff --git a/.github/workflows/quicktest.yml b/.github/workflows/quicktest.yml index bf16702d7e..462ced3768 100644 --- a/.github/workflows/quicktest.yml +++ b/.github/workflows/quicktest.yml @@ -30,7 +30,7 @@ jobs: steps: - name: Checkout repository - uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0 + uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1 with: persist-credentials: false diff --git a/.github/workflows/unit-tests.yml b/.github/workflows/unit-tests.yml index ae91294a87..4502ac7042 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@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0 + uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1 with: persist-credentials: false From ac8c504cd44010d7681c107544449a1a9c155dbf Mon Sep 17 00:00:00 2001 From: jrfnl Date: Mon, 8 Dec 2025 15:19:35 +0100 Subject: [PATCH 017/108] README: fix a few badges The `poser.pugx.org` site isn't working half the time and broken badges do not look good. --- README.md | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 5ebe6c660c..febabd8ad4 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ From 56ac2fceedef18cf72b2748a1b3ff602f057c9d7 Mon Sep 17 00:00:00 2001 From: jrfnl Date: Mon, 8 Dec 2025 15:21:25 +0100 Subject: [PATCH 018/108] Dependabot/gh-actions: move to bi-weekly schedule :point_right: Important: this is for **version** updates only, not for security updates, which are handled separately and don't depend on this configuration. --- PR 2621 updated the GitHub Actions workflows used in this repo to use "pinned" versions for external action runners to improve workflow security. The net result of this, is that Dependabot now sends PRs to all repos I (co-)maintain on a weekly basis for most repos. As the default day for the "weekly" interval is _Monday_ and most repos don't change this, it means that Dependabot has a huge queue on Mondays and that PRs come in bit by bit throughout the day and even spill over into Tuesday. This constant stream of low level/easy PRs to merge is disruptive and time consuming, especially as I can't just go through them all in one go. As these updates are rarely time-sensitive, it should be fine to receive them less frequently. This commit tries to make it so by changing the Dependabot schedule for GitHub Actions to once every two weeks and late in the day when the queue should be mostly empty (as long as it's not a Monday), which should mean that if I apply this same change to all repos I am involved with, all these Dependabot PRs should come in around the same time. --- .github/dependabot.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/dependabot.yml b/.github/dependabot.yml index 2b9891a7f0..b9a37be052 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -8,8 +8,8 @@ updates: - package-ecosystem: "github-actions" directory: "/" schedule: - interval: "weekly" - time: "09:00" + interval: "cron" + cronjob: "10 22 5,20 * *" # At 22:10, every 5th and 20th day of the month. open-pull-requests-limit: 5 commit-message: prefix: "GH Actions:" From f131da83f82f92b5e4d76a29195a9f8913f01bd0 Mon Sep 17 00:00:00 2001 From: jrfnl Date: Tue, 9 Dec 2025 14:40:57 +0100 Subject: [PATCH 019/108] AbstractClassRestrictionsSniff: fix inconsequential typo The sniff looks for whitespace or a close curly at the end of a class declaration statement, but those don't end with a close curly, but with an open curly. As it would be rare for anyone not to have whitespace before the open curly (which is also enforced by WPCS), this bug will probably never have had any consequences in real life, as the `findNext()` would stop at the whitespace anyway. Having said that, I see quite a lot more wrong with the code in this abstract, but will leave that for the future abstract in PHPCSUtils to fix as spending lots of time on it here is not worth our time. --- WordPress/AbstractClassRestrictionsSniff.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/WordPress/AbstractClassRestrictionsSniff.php b/WordPress/AbstractClassRestrictionsSniff.php index e0f1c85802..d380522b3a 100644 --- a/WordPress/AbstractClassRestrictionsSniff.php +++ b/WordPress/AbstractClassRestrictionsSniff.php @@ -134,7 +134,7 @@ public function is_targetted_token( $stackPtr ) { $nameEnd = ( $this->phpcsFile->findNext( array( \T_OPEN_PARENTHESIS, \T_WHITESPACE, \T_SEMICOLON, \T_CLOSE_PARENTHESIS, \T_CLOSE_TAG ), ( $stackPtr + 2 ) ) - 1 ); } else { - $nameEnd = ( $this->phpcsFile->findNext( array( \T_CLOSE_CURLY_BRACKET, \T_WHITESPACE ), ( $stackPtr + 2 ) ) - 1 ); + $nameEnd = ( $this->phpcsFile->findNext( array( \T_OPEN_CURLY_BRACKET, \T_WHITESPACE ), ( $stackPtr + 2 ) ) - 1 ); } if ( isset( $this->tokens[ $stackPtr + 2 ] ) && false !== $nameEnd ) { From 64d3e627c16942b954ca1a850df67e1f9f143e11 Mon Sep 17 00:00:00 2001 From: Rodrigo Primo Date: Thu, 6 Nov 2025 11:07:29 -0300 Subject: [PATCH 020/108] WP/DeprecatedClasses: rename test case file More tests will be added in a separate file in a subsequent commit. --- ...st.inc => DeprecatedClassesUnitTest.1.inc} | 0 .../Tests/WP/DeprecatedClassesUnitTest.php | 21 ++++++++++++------- 2 files changed, 14 insertions(+), 7 deletions(-) rename WordPress/Tests/WP/{DeprecatedClassesUnitTest.inc => DeprecatedClassesUnitTest.1.inc} (100%) diff --git a/WordPress/Tests/WP/DeprecatedClassesUnitTest.inc b/WordPress/Tests/WP/DeprecatedClassesUnitTest.1.inc similarity index 100% rename from WordPress/Tests/WP/DeprecatedClassesUnitTest.inc rename to WordPress/Tests/WP/DeprecatedClassesUnitTest.1.inc diff --git a/WordPress/Tests/WP/DeprecatedClassesUnitTest.php b/WordPress/Tests/WP/DeprecatedClassesUnitTest.php index 682f144ebe..32d3af6557 100644 --- a/WordPress/Tests/WP/DeprecatedClassesUnitTest.php +++ b/WordPress/Tests/WP/DeprecatedClassesUnitTest.php @@ -24,17 +24,24 @@ final class DeprecatedClassesUnitTest 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 = 9; - $end_line = 28; - $errors = array_fill( $start_line, ( ( $end_line - $start_line ) + 1 ), 1 ); + public function getErrorList( $testFile = '' ) { + switch ( $testFile ) { + case 'DeprecatedClassesUnitTest.1.inc': + $start_line = 9; + $end_line = 28; + $errors = array_fill( $start_line, ( ( $end_line - $start_line ) + 1 ), 1 ); - // Unset the lines related to version comments. - unset( $errors[16], $errors[18], $errors[21], $errors[26] ); + // Unset the lines related to version comments. + unset( $errors[16], $errors[18], $errors[21], $errors[26] ); - return $errors; + return $errors; + default: + return array(); + } } /** From 6d2d1e4b4d4f2e7d41250942b7d17c7779e0162f Mon Sep 17 00:00:00 2001 From: Rodrigo Primo Date: Thu, 6 Nov 2025 11:30:44 -0300 Subject: [PATCH 021/108] WP/DeprecatedClasses: add tests for namespaced names I opted to add the tests in a separate file as for DeprecatedClassesUnitTest.1.inc the error lines are generated dynamically. --- .../Tests/WP/DeprecatedClassesUnitTest.2.inc | 23 +++++++++++++++++++ .../Tests/WP/DeprecatedClassesUnitTest.php | 11 +++++++++ 2 files changed, 34 insertions(+) create mode 100644 WordPress/Tests/WP/DeprecatedClassesUnitTest.2.inc diff --git a/WordPress/Tests/WP/DeprecatedClassesUnitTest.2.inc b/WordPress/Tests/WP/DeprecatedClassesUnitTest.2.inc new file mode 100644 index 0000000000..6b710f9d2f --- /dev/null +++ b/WordPress/Tests/WP/DeprecatedClassesUnitTest.2.inc @@ -0,0 +1,23 @@ + 1, + 13 => 1, + 14 => 1, + 18 => 1, + 19 => 1, + 23 => 1, + ); + default: return array(); } From 3ed84e252cdcc62276fdc428ee40efa1eefd3a69 Mon Sep 17 00:00:00 2001 From: Rodrigo Primo Date: Thu, 6 Nov 2025 12:10:59 -0300 Subject: [PATCH 022/108] WP/ClassNameCase: add tests for namespaced names This commit also adds two non-namespaces tests for interfaces as those were missing in the file. --- WordPress/Tests/WP/ClassNameCaseUnitTest.inc | 26 ++++++++++++++++++++ WordPress/Tests/WP/ClassNameCaseUnitTest.php | 7 ++++++ 2 files changed, 33 insertions(+) diff --git a/WordPress/Tests/WP/ClassNameCaseUnitTest.inc b/WordPress/Tests/WP/ClassNameCaseUnitTest.inc index 1c540dc656..70af2b1484 100644 --- a/WordPress/Tests/WP/ClassNameCaseUnitTest.inc +++ b/WordPress/Tests/WP/ClassNameCaseUnitTest.inc @@ -65,3 +65,29 @@ class NotYetDetected { public function paramTypeDeclaration( wp_role $role ) {} public function returnTypeDeclaration() : WP_TERM {} } + +class ImplementsInterfaceCorrectCase implements SimplePie_Cache_Base {} +class ImplementsInterfaceIncorrectCase implements simplepie_cache_base {} + +/* + * Safeguard correct handling of namespaced class references (the namespace types not handled below are already handled + * in other tests above). + */ +$obj = new MyNamespace\atomEntry(); +$obj = new \MyNamespace\core_upgrader(); +$obj = new namespace\Sub\file_upload_upgrader(); +$obj = new namespace\pop3(); // Warning. +class MyClass1 extends MyNamespace\twentytwenty_walker_page {} +class MyClass2 extends \MyNamespace\TWENTY_ELEVEN_EPHEMERA_WIDGET {} +class MyClass3 extends namespace\Sub\twenty_Twenty_One_SVG_icons {} +class MyClass4 extends namespace\twentynineteen_SVG_icons {} // Warning. +class MyClass5 implements \WPORG\REQUESTS\AUTH {} // Warning. +class MyClass6 implements \MyNamespace\SIMPLEPIE\Cache\namefilter {} +class MyClass7 implements MyNamespace\requests_auth {} +class MyClass8 implements namespace\Sub\WpOrg\REQUESTS\proxy {} +class MyClass9 implements namespace\simplepie\CACHE\base {} // Warning. +\avifinfo\Box::prepare_query(); // Warning. +MyNamespace\Avifinfo\CHAN_PROP::prepare_query(); +\MyNamespace\Avifinfo\features::prepare_query(); +namespace\Sub\AVIFINFO\parser::prepare_query(); +namespace\AVIFINFO\TILE::prepare_query(); // Warning. diff --git a/WordPress/Tests/WP/ClassNameCaseUnitTest.php b/WordPress/Tests/WP/ClassNameCaseUnitTest.php index 7869ea7f6f..62f9f6b179 100644 --- a/WordPress/Tests/WP/ClassNameCaseUnitTest.php +++ b/WordPress/Tests/WP/ClassNameCaseUnitTest.php @@ -45,6 +45,13 @@ public function getWarningList() { 47 => 1, 48 => 1, 49 => 1, + 70 => 1, + 79 => 1, + 83 => 1, + 84 => 1, + 88 => 1, + 89 => 1, + 93 => 1, ); } } From a6b8b329b3b9bfacdf5dd06dcc5e53f3934866c4 Mon Sep 17 00:00:00 2001 From: Rodrigo Primo Date: Wed, 12 Nov 2025 15:30:05 -0300 Subject: [PATCH 023/108] DB/RestrictedClasses: add tests for namespaced names --- .../Tests/DB/RestrictedClassesUnitTest.1.inc | 23 ++++++++++++++++++- .../Tests/DB/RestrictedClassesUnitTest.php | 4 ++++ 2 files changed, 26 insertions(+), 1 deletion(-) diff --git a/WordPress/Tests/DB/RestrictedClassesUnitTest.1.inc b/WordPress/Tests/DB/RestrictedClassesUnitTest.1.inc index 4449a0395b..d41ff86379 100644 --- a/WordPress/Tests/DB/RestrictedClassesUnitTest.1.inc +++ b/WordPress/Tests/DB/RestrictedClassesUnitTest.1.inc @@ -30,7 +30,7 @@ class MyMysqli extends mysqli {} class YourMysqli extends \mysqli {} class OurMysqli implements mysqli {} -class TheirMysqli implements \mysqli {} +class TheirMysqli implements \MYSQLI {} $db5 = new PDO(); $db6 = ( new PDO() )->exec(); @@ -115,3 +115,24 @@ $anon = new readonly class { $anon = new readonly class() extends PDOStatement {}; // Error. $anon = new #[MyAttribute] readonly class {}; + +/* + * Safeguard correct handling of namespaced class references (the namespace types not handled below are already handled + * in other tests above). + */ +$obj = new MyNamespace\PDO(); +$obj = new \MyNamespace\PDOStatement(); +$obj = new namespace\Sub\mysqli(); +$obj = new namespace\PDO(); // Error. +class MyClass1 extends MyNamespace\mysqli {} +class MyClass2 extends \MyNamespace\PDO {} +class MyClass3 extends namespace\Sub\PDOStatement {} +class MyClass4 extends namespace\mysqli {} // Error. +class MyClass5 implements MyNamespace\mysqli {} +class MyClass6 implements \MyNamespace\PDO {} +class MyClass7 implements namespace\Sub\PDOStatement {} +class MyClass8 implements namespace\mysqli {} // Error. +MyNamespace\mysqli::do_something(); +\MyNamespace\PDO::do_something(); +namespace\Sub\PDOStatement::do_something(); +namespace\MYSQLI::do_something(); // Error. diff --git a/WordPress/Tests/DB/RestrictedClassesUnitTest.php b/WordPress/Tests/DB/RestrictedClassesUnitTest.php index a07ace04d8..a9bb96546e 100644 --- a/WordPress/Tests/DB/RestrictedClassesUnitTest.php +++ b/WordPress/Tests/DB/RestrictedClassesUnitTest.php @@ -102,6 +102,10 @@ public function getErrorList( $testFile = '' ) { 103 => 1, 106 => 1, 115 => 1, + 126 => 1, + 130 => 1, + 134 => 1, + 138 => 1, ); case 'RestrictedClassesUnitTest.2.inc': From 1905ce07a548275a1acba31c52e19cb17c1a1d19 Mon Sep 17 00:00:00 2001 From: Rodrigo Primo Date: Thu, 16 Oct 2025 13:33:43 -0300 Subject: [PATCH 024/108] CodeAnalysis/EscapedNotTranslated: add tests for namespaced names --- .../CodeAnalysis/EscapedNotTranslatedUnitTest.inc | 13 +++++++++++-- .../CodeAnalysis/EscapedNotTranslatedUnitTest.php | 7 ++++--- 2 files changed, 15 insertions(+), 5 deletions(-) diff --git a/WordPress/Tests/CodeAnalysis/EscapedNotTranslatedUnitTest.inc b/WordPress/Tests/CodeAnalysis/EscapedNotTranslatedUnitTest.inc index c451ccc91b..63b8d03ccd 100644 --- a/WordPress/Tests/CodeAnalysis/EscapedNotTranslatedUnitTest.inc +++ b/WordPress/Tests/CodeAnalysis/EscapedNotTranslatedUnitTest.inc @@ -4,8 +4,17 @@ esc_html( 'text' ); esc_html( $var ); esc_html( 'text', 'domain' ); // Warning. -esc_html( $foo, $bar ); // Warning. -esc_attr( +\ESC_HTML( $foo, $bar ); // Warning. +esc_ATTR( 'text', // Some comment. MY_DOMAIN // More comment. ); // Warning. + +/* + * Safeguard correct handling of all types of namespaced function calls. + */ +\esc_attr( 'text', 'domain' ); // Warning. +MyNamespace\esc_html( 'text', 'domain' ); +\MyNamespace\esc_attr( 'text', 'domain' ); +namespace\esc_html( 'text', 'domain' ); // The sniff should start flagging this once it can resolve relative namespaces. +namespace\Sub\esc_attr( 'text', 'domain' ); diff --git a/WordPress/Tests/CodeAnalysis/EscapedNotTranslatedUnitTest.php b/WordPress/Tests/CodeAnalysis/EscapedNotTranslatedUnitTest.php index 4218e90dc9..eee562f2d6 100644 --- a/WordPress/Tests/CodeAnalysis/EscapedNotTranslatedUnitTest.php +++ b/WordPress/Tests/CodeAnalysis/EscapedNotTranslatedUnitTest.php @@ -36,9 +36,10 @@ public function getErrorList() { */ public function getWarningList() { return array( - 6 => 1, - 7 => 1, - 8 => 1, + 6 => 1, + 7 => 1, + 8 => 1, + 16 => 1, ); } } From fdf91539bc154a516a152942f038b13c8e87a063 Mon Sep 17 00:00:00 2001 From: Rodrigo Primo Date: Thu, 16 Oct 2025 13:42:26 -0300 Subject: [PATCH 025/108] DateTime/CurrentTimeTimestamp: add tests for namespaced names --- .../Tests/DateTime/CurrentTimeTimestampUnitTest.inc | 11 ++++++++++- .../DateTime/CurrentTimeTimestampUnitTest.inc.fixed | 11 ++++++++++- .../Tests/DateTime/CurrentTimeTimestampUnitTest.php | 1 + 3 files changed, 21 insertions(+), 2 deletions(-) diff --git a/WordPress/Tests/DateTime/CurrentTimeTimestampUnitTest.inc b/WordPress/Tests/DateTime/CurrentTimeTimestampUnitTest.inc index 07634e769a..95e92f2bff 100644 --- a/WordPress/Tests/DateTime/CurrentTimeTimestampUnitTest.inc +++ b/WordPress/Tests/DateTime/CurrentTimeTimestampUnitTest.inc @@ -20,7 +20,7 @@ current_time( // Error. ); current_time( 'timestamp', $gmt ); // Warning. -current_time( 'timestamp', false ); // Warning. +\Current_Time( 'timestamp', false ); // Warning. current_time( 'U', 0 ); // Warning. current_time( 'U' ); // Warning. @@ -30,3 +30,12 @@ current_time( gmt: true, type: 'mysql', ); // OK. current_time( type: 'Y-m-d' ); // OK. current_time( gmt: true, type: 'timestamp' ); // Error. current_time( gmt: 0, type : 'U' ); // Warning. + +/* + * Safeguard correct handling of all types of namespaced function calls. + */ +\current_time( 'timestamp', true ); // Error. +MyNamespace\current_time( 'timestamp', true ); +\MyNamespace\current_time( 'timestamp', true ); +namespace\current_time( 'timestamp', true ); // The sniff should start flagging this once it can resolve relative namespaces. +namespace\Sub\current_time( 'timestamp', true ); diff --git a/WordPress/Tests/DateTime/CurrentTimeTimestampUnitTest.inc.fixed b/WordPress/Tests/DateTime/CurrentTimeTimestampUnitTest.inc.fixed index 5b2fa7e28a..080c332946 100644 --- a/WordPress/Tests/DateTime/CurrentTimeTimestampUnitTest.inc.fixed +++ b/WordPress/Tests/DateTime/CurrentTimeTimestampUnitTest.inc.fixed @@ -17,7 +17,7 @@ current_time( // Error. ); current_time( 'timestamp', $gmt ); // Warning. -current_time( 'timestamp', false ); // Warning. +\Current_Time( 'timestamp', false ); // Warning. current_time( 'U', 0 ); // Warning. current_time( 'U' ); // Warning. @@ -27,3 +27,12 @@ current_time( gmt: true, type: 'mysql', ); // OK. current_time( type: 'Y-m-d' ); // OK. time(); // Error. current_time( gmt: 0, type : 'U' ); // Warning. + +/* + * Safeguard correct handling of all types of namespaced function calls. + */ +\time(); // Error. +MyNamespace\current_time( 'timestamp', true ); +\MyNamespace\current_time( 'timestamp', true ); +namespace\current_time( 'timestamp', true ); // The sniff should start flagging this once it can resolve relative namespaces. +namespace\Sub\current_time( 'timestamp', true ); diff --git a/WordPress/Tests/DateTime/CurrentTimeTimestampUnitTest.php b/WordPress/Tests/DateTime/CurrentTimeTimestampUnitTest.php index c667af8234..4525e58d79 100644 --- a/WordPress/Tests/DateTime/CurrentTimeTimestampUnitTest.php +++ b/WordPress/Tests/DateTime/CurrentTimeTimestampUnitTest.php @@ -31,6 +31,7 @@ public function getErrorList() { 11 => 1, 17 => 1, 31 => 1, + 37 => 1, ); } From 44bd8d19d966111edb57036824adb01d96e4f267 Mon Sep 17 00:00:00 2001 From: Rodrigo Primo Date: Thu, 16 Oct 2025 13:51:05 -0300 Subject: [PATCH 026/108] NamingConventions/ValidPostTypeSlug: add tests for namespaced names --- .../ValidPostTypeSlugUnitTest.1.inc | 13 +++++++++++-- .../NamingConventions/ValidPostTypeSlugUnitTest.php | 1 + 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/WordPress/Tests/NamingConventions/ValidPostTypeSlugUnitTest.1.inc b/WordPress/Tests/NamingConventions/ValidPostTypeSlugUnitTest.1.inc index 5c0ed5729a..bf6450c790 100644 --- a/WordPress/Tests/NamingConventions/ValidPostTypeSlugUnitTest.1.inc +++ b/WordPress/Tests/NamingConventions/ValidPostTypeSlugUnitTest.1.inc @@ -5,7 +5,7 @@ register_post_type( 'my_own_post_type', array() ); // OK. register_post_type( 'my-own-post-type-too-long', array() ); // Bad. register_post_type( 'author', array() ); // Bad. Reserved slug name. register_post_type( 'My-Own-Post-Type', array() ); // Bad. Invalid chars: uppercase. -register_post_type( 'my/own/post/type', array() ); // Bad. Invalid chars: "/". +register_POST_TYPE( 'my/own/post/type', array() ); // Bad. Invalid chars: "/". register_post_type( <<get_post_type_id() ); // Non string literal. Warning register_post_type( null, array() ); // Non string literal. Warning with severity: 3 register_post_type( 1000, array() ); // Non string literal. Warning with severity: 3 -register_post_type( 'wp_', array() ); // Bad. Reserved prefix. +\REGISTER_post_TYPE( 'wp_', array() ); // Bad. Reserved prefix. register_post_type( 'wp_post_type', array() ); // Bad. Reserved prefix. register_post_type( '', array() ); // Bad. Empty post type slug. @@ -68,3 +68,12 @@ register_post_type( // Post type name. $name,// Non string literal. Warning with severity: 3 ); + +/* + * Safeguard correct handling of all types of namespaced function calls. + */ +\register_post_type( 'my-own-post-type-too-long', array() ); // Bad. +MyNamespace\register_post_type( 'my-own-post-type-too-long', array() ); // Ok. +\MyNamespace\register_post_type( 'my-own-post-type-too-long', array() ); // Ok. +namespace\register_post_type( 'my-own-post-type-too-long', array() ); // The sniff should start flagging this once it can resolve relative namespaces. +namespace\Sub\register_post_type( 'my-own-post-type-too-long', array() ); // Ok. diff --git a/WordPress/Tests/NamingConventions/ValidPostTypeSlugUnitTest.php b/WordPress/Tests/NamingConventions/ValidPostTypeSlugUnitTest.php index 821b73ef24..cb2d41c998 100644 --- a/WordPress/Tests/NamingConventions/ValidPostTypeSlugUnitTest.php +++ b/WordPress/Tests/NamingConventions/ValidPostTypeSlugUnitTest.php @@ -57,6 +57,7 @@ public function getErrorList( $testFile = '' ) { 52 => 1, 62 => 1, 64 => 1, + 75 => 1, ); case 'ValidPostTypeSlugUnitTest.2.inc': From 16b7b2ab17e1f3ec928c2ec77bdd00d5707e920f Mon Sep 17 00:00:00 2001 From: Rodrigo Primo Date: Thu, 16 Oct 2025 13:51:30 -0300 Subject: [PATCH 027/108] PHP/IniSet: add tests for namespaced names --- WordPress/Tests/PHP/IniSetUnitTest.inc | 13 +++++++++++-- WordPress/Tests/PHP/IniSetUnitTest.php | 1 + 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/WordPress/Tests/PHP/IniSetUnitTest.inc b/WordPress/Tests/PHP/IniSetUnitTest.inc index c5ef7295d1..96a310cb19 100644 --- a/WordPress/Tests/PHP/IniSetUnitTest.inc +++ b/WordPress/Tests/PHP/IniSetUnitTest.inc @@ -14,8 +14,8 @@ ini_set('short_open_tag', 'On'); // Ok. ini_set('short_open_tag', 'on'); // Ok. ini_set('bcmath.scale', 0); // Error. -ini_set( 'bcmath.scale' ,0 ); // Error. -ini_set('display_errors', 0); // Error. +\ini_SET( 'bcmath.scale' ,0 ); // Error. +INI_set('display_errors', 0); // Error. ini_set('error_reporting', 0); // Error. ini_set('filter.default', 'full_special_chars'); // Error. ini_set('filter.default_flags', 0); // Error. @@ -58,3 +58,12 @@ ini_set( // Set the number of decimals. 0 ); // Error. + +/* + * Safeguard correct handling of all types of namespaced function calls. + */ +\ini_set( 'bcmath.scale', 0 ); // Error. +MyNamespace\ini_alter( 'bcmath.scale', 0 ); // Ok. +\MyNamespace\ini_set( 'bcmath.scale', 0 ); // Ok. +namespace\ini_alter( 'bcmath.scale', 0 ); // The sniff should start flagging this once it can resolve relative namespaces. +namespace\Sub\ini_set( 'bcmath.scale', 0 ); // Ok. diff --git a/WordPress/Tests/PHP/IniSetUnitTest.php b/WordPress/Tests/PHP/IniSetUnitTest.php index fede4955b2..1dd5ca4ab7 100644 --- a/WordPress/Tests/PHP/IniSetUnitTest.php +++ b/WordPress/Tests/PHP/IniSetUnitTest.php @@ -49,6 +49,7 @@ public function getErrorList() { 42 => 1, 51 => 1, 55 => 1, + 65 => 1, ); } From 93225ec0ad8b8d227db0e5732b0ba6035e3e100e Mon Sep 17 00:00:00 2001 From: Rodrigo Primo Date: Thu, 16 Oct 2025 14:13:37 -0300 Subject: [PATCH 028/108] Security/PluginMenuSlug: add tests for namespaced names --- WordPress/Tests/Security/PluginMenuSlugUnitTest.inc | 13 +++++++++++-- WordPress/Tests/Security/PluginMenuSlugUnitTest.php | 1 + 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/WordPress/Tests/Security/PluginMenuSlugUnitTest.inc b/WordPress/Tests/Security/PluginMenuSlugUnitTest.inc index 2c77ee621e..3f4e34f948 100644 --- a/WordPress/Tests/Security/PluginMenuSlugUnitTest.inc +++ b/WordPress/Tests/Security/PluginMenuSlugUnitTest.inc @@ -2,11 +2,11 @@ add_menu_page( $page_title, $menu_title, $capability, __FILE__, $function, $icon_url, $position ); // Bad. -add_dashboard_page( $page_title, $menu_title, $capability, __file__, $function); // Bad. +\ADD_DASHBOARD_PAGE( $page_title, $menu_title, $capability, __file__, $function); // Bad. add_submenu_page( $parent_slug, $page_title, $menu_title, $capability, 'awesome-submenu-page', $function ); // Ok. -add_submenu_page( __FILE__ . 'parent', $page_title, $menu_title, $capability, __FILE__, $function ); // Bad x 2. +Add_Submenu_Page( __FILE__ . 'parent', $page_title, $menu_title, $capability, __FILE__, $function ); // Bad x 2. // These are all ok: not calling the WP core function. $my_class->add_dashboard_page( $page_title, $menu_title, $capability, __FILE__, $function); // Ok. @@ -20,3 +20,12 @@ add_submenu_page( parent_slug: __FILE__, // Bad. capability: $capability, ); + +/* + * Safeguard correct handling of all types of namespaced function calls. + */ +\add_menu_page( $page_title, $menu_title, $capability, __FILE__, $function, $icon_url, $position ); // Bad. +MyNamespace\add_submenu_page( $parent_slug, $page_title, $menu_title, $capability, __FILE__, $function ); // Ok. +\MyNamespace\add_dashboard_page( $page_title, $menu_title, $capability, __FILE__, $function ); // Ok. +namespace\add_menu_page( $page_title, $menu_title, $capability, __FILE__, $function, $icon_url, $position ); // The sniff should start flagging this once it can resolve relative namespaces. +namespace\Sub\add_submenu_page( $parent_slug, $page_title, $menu_title, $capability, __FILE__, $function ); // Ok. diff --git a/WordPress/Tests/Security/PluginMenuSlugUnitTest.php b/WordPress/Tests/Security/PluginMenuSlugUnitTest.php index 6741d048a1..cee8c0e1b6 100644 --- a/WordPress/Tests/Security/PluginMenuSlugUnitTest.php +++ b/WordPress/Tests/Security/PluginMenuSlugUnitTest.php @@ -42,6 +42,7 @@ public function getWarningList() { 5 => 1, 9 => 2, 20 => 1, + 27 => 1, ); } } From 57a83a40e327a5b2650bda288932184302754794 Mon Sep 17 00:00:00 2001 From: Rodrigo Primo Date: Thu, 16 Oct 2025 14:14:13 -0300 Subject: [PATCH 029/108] PHP/PregQuoteDelimiter: add tests for namespaced names --- WordPress/Tests/PHP/PregQuoteDelimiterUnitTest.inc | 13 +++++++++++-- WordPress/Tests/PHP/PregQuoteDelimiterUnitTest.php | 1 + 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/WordPress/Tests/PHP/PregQuoteDelimiterUnitTest.inc b/WordPress/Tests/PHP/PregQuoteDelimiterUnitTest.inc index 1942b2b07f..06611613af 100644 --- a/WordPress/Tests/PHP/PregQuoteDelimiterUnitTest.inc +++ b/WordPress/Tests/PHP/PregQuoteDelimiterUnitTest.inc @@ -4,12 +4,21 @@ preg_quote($keywords, '/'); // OK. preg_quote( $keywords, '`' ); // OK. preg_quote($keywords); // Warning. -$textbody = preg_replace ( "/" . preg_quote($word) . "/", // Warning +$textbody = preg_replace ( "/" . \PREG_quote($word) . "/", // Warning "" . $word . "", $textbody ); // Safeguard support for PHP 8.0+ named parameters. preg_quote(delimiter: '#', str: $keywords); // OK. preg_quote(str: $keywords); // Warning. -preg_quote(str: $keywords, delimitter: '#'); // Warning (typo in param name). +Preg_QUOTE(str: $keywords, delimitter: '#'); // Warning (typo in param name). preg_quote(delimiter: '#'); // OK. Invalid function call, but that's not the concern of this sniff. + +/* + * Safeguard correct handling of all types of namespaced function calls. + */ +\preg_quote($keywords); // Warning. +MyNamespace\preg_quote($keywords); // Ok. +\MyNamespace\preg_quote($keywords); // Ok. +namespace\preg_quote($keywords); // The sniff should start flagging this once it can resolve relative namespaces. +namespace\Sub\preg_quote($keywords); // Ok. diff --git a/WordPress/Tests/PHP/PregQuoteDelimiterUnitTest.php b/WordPress/Tests/PHP/PregQuoteDelimiterUnitTest.php index 63d4e0eb9f..4c6a254fae 100644 --- a/WordPress/Tests/PHP/PregQuoteDelimiterUnitTest.php +++ b/WordPress/Tests/PHP/PregQuoteDelimiterUnitTest.php @@ -40,6 +40,7 @@ public function getWarningList() { 7 => 1, 13 => 1, 14 => 1, + 20 => 1, ); } } From 5570af3a170b070892e046578ba2a01bf1de820d Mon Sep 17 00:00:00 2001 From: Rodrigo Primo Date: Thu, 16 Oct 2025 14:14:47 -0300 Subject: [PATCH 030/108] PHP/StrictInArray: add tests for namespaced names --- WordPress/Tests/PHP/StrictInArrayUnitTest.inc | 11 ++++++++++- WordPress/Tests/PHP/StrictInArrayUnitTest.php | 1 + 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/WordPress/Tests/PHP/StrictInArrayUnitTest.inc b/WordPress/Tests/PHP/StrictInArrayUnitTest.inc index fd1e194225..15ce708653 100644 --- a/WordPress/Tests/PHP/StrictInArrayUnitTest.inc +++ b/WordPress/Tests/PHP/StrictInArrayUnitTest.inc @@ -3,7 +3,7 @@ in_array( 1, array( '1', 1, true ), true ); // Ok. in_array( 1, array( '1', 1, true ) ); // Warning. -in_array( 1, array( '1', 1, true ), false ); // Warning. +\In_Array( 1, array( '1', 1, true ), false ); // Warning. IN_ARRAY( 1, array( '1', 1, true ), false ); // Warning. Foo::in_array( 1, array( '1', 1, true ) ); // Ok. @@ -55,3 +55,12 @@ array_search( $haystack, true // Use strict typing. ); // Ok. + +/* + * Safeguard correct handling of all types of namespaced function calls. + */ +\in_array( 1, array( '1', 2 ) ); // Bad. +MyNamespace\array_search( 1, array( '1', 2 ) ); // Ok. +\MyNamespace\array_keys( array( '1', 2 ) ); // Ok. +namespace\in_array( 1, array( '1', 2 ) ); // The sniff should start flagging this once it can resolve relative namespaces. +namespace\Sub\array_search( 1, array( '1', 2 ) ); // Ok. diff --git a/WordPress/Tests/PHP/StrictInArrayUnitTest.php b/WordPress/Tests/PHP/StrictInArrayUnitTest.php index 41aa9d37c4..d7104d7d9b 100644 --- a/WordPress/Tests/PHP/StrictInArrayUnitTest.php +++ b/WordPress/Tests/PHP/StrictInArrayUnitTest.php @@ -52,6 +52,7 @@ public function getWarningList() { 44 => 1, 48 => 1, 49 => 1, + 62 => 1, ); } } From b09073a8ab8bf903d060770478ac615bf5e2668d Mon Sep 17 00:00:00 2001 From: Rodrigo Primo Date: Thu, 16 Oct 2025 14:18:36 -0300 Subject: [PATCH 031/108] WP/Capabilities: move syntax error test to its own file --- WordPress/Tests/WP/CapabilitiesUnitTest.1.inc | 4 ---- WordPress/Tests/WP/CapabilitiesUnitTest.5.inc | 8 ++++++++ 2 files changed, 8 insertions(+), 4 deletions(-) create mode 100644 WordPress/Tests/WP/CapabilitiesUnitTest.5.inc diff --git a/WordPress/Tests/WP/CapabilitiesUnitTest.1.inc b/WordPress/Tests/WP/CapabilitiesUnitTest.1.inc index ab1fdb9c41..5752f4b54e 100644 --- a/WordPress/Tests/WP/CapabilitiesUnitTest.1.inc +++ b/WordPress/Tests/WP/CapabilitiesUnitTest.1.inc @@ -112,7 +112,3 @@ add_menu_page( [] ); // Should bow out because the parameter is not found. $obj->current_user_can( 'foo_bar' ); // Ok. We're not checking for method calls. My\NamespaceS\add_posts_page( 'page_title', 'menu_title', 'administrator', 'menu_slug', 'function' ); // Ok. We're not checking namespaced functions. - -// Parse error, should be handled correctly by bowing out. -// This must be the last test in the file! -add_posts_page( 'page_title', diff --git a/WordPress/Tests/WP/CapabilitiesUnitTest.5.inc b/WordPress/Tests/WP/CapabilitiesUnitTest.5.inc new file mode 100644 index 0000000000..d5f8d0d393 --- /dev/null +++ b/WordPress/Tests/WP/CapabilitiesUnitTest.5.inc @@ -0,0 +1,8 @@ + Date: Thu, 16 Oct 2025 17:58:19 -0300 Subject: [PATCH 032/108] WP/Capabilities: add tests for namespaced names --- WordPress/Tests/WP/CapabilitiesUnitTest.1.inc | 14 +++++++++++--- WordPress/Tests/WP/CapabilitiesUnitTest.php | 1 + 2 files changed, 12 insertions(+), 3 deletions(-) diff --git a/WordPress/Tests/WP/CapabilitiesUnitTest.1.inc b/WordPress/Tests/WP/CapabilitiesUnitTest.1.inc index 5752f4b54e..3cd45f9c9c 100644 --- a/WordPress/Tests/WP/CapabilitiesUnitTest.1.inc +++ b/WordPress/Tests/WP/CapabilitiesUnitTest.1.inc @@ -63,8 +63,8 @@ add_menu_page( $pagetitle, 'menu_title', 'foo_bar', 'handle', 'function', 'icon_ * Roles found instead of capabilities. */ add_posts_page( 'page_title', 'menu_title', 'administrator', 'menu_slug', 'function' ); // Error. -add_media_page( 'page_title', 'menu_title', 'editor', 'menu_slug', 'function' ); // Error. -add_pages_page( 'page_title', 'menu_title', 'author', 'menu_slug', 'function' ); // Error. +\aDd_MeDiA_pAgE( 'page_title', 'menu_title', 'editor', 'menu_slug', 'function' ); // Error. +ADD_PAGES_PAGE( 'page_title', 'menu_title', 'author', 'menu_slug', 'function' ); // Error. add_comments_page( 'page_title', 'menu_title', 'contributor', 'menu_slug', 'function' ); // Error. add_theme_page( 'page_title', $menu_title, 'subscriber', 'menu_slug', 'function' ); // Error. add_plugins_page( 'page_title', 'menu_title', 'super_admin', 'menu_slug', 'function' ); // Error. @@ -111,4 +111,12 @@ add_menu_page( $p, $t, /* deliberately empty */, $slug, ); add_menu_page( [] ); // Should bow out because the parameter is not found. $obj->current_user_can( 'foo_bar' ); // Ok. We're not checking for method calls. -My\NamespaceS\add_posts_page( 'page_title', 'menu_title', 'administrator', 'menu_slug', 'function' ); // Ok. We're not checking namespaced functions. + +/* + * Safeguard correct handling of all types of namespaced function calls. + */ +\add_posts_page( 'page_title', 'menu_title', 'administrator', 'menu_slug', 'function' ); // Bad. +My\NamespaceS\current_user_can( 'administrator' ); // Ok. +\MyNamespace\add_comments_page( 'page_title', 'menu_title', 'administrator', 'menu_slug', 'function' ); // Ok. +namespace\author_can( $post, 'administrator' ); // The sniff should start flagging this once it can resolve relative namespaces. +namespace\Sub\add_posts_page( 'page_title', 'menu_title', 'administrator', 'menu_slug', 'function' ); // Ok. diff --git a/WordPress/Tests/WP/CapabilitiesUnitTest.php b/WordPress/Tests/WP/CapabilitiesUnitTest.php index 42113c2a24..1b4e34dd05 100644 --- a/WordPress/Tests/WP/CapabilitiesUnitTest.php +++ b/WordPress/Tests/WP/CapabilitiesUnitTest.php @@ -73,6 +73,7 @@ public function getErrorList( $testFile = '' ) { 78 => 1, 85 => 1, 106 => 1, + 118 => 1, ); case 'CapabilitiesUnitTest.3.inc': From 6b7601d977a0b195676d0588101d12ec78d1c824 Mon Sep 17 00:00:00 2001 From: Rodrigo Primo Date: Tue, 9 Dec 2025 14:43:04 -0300 Subject: [PATCH 033/108] Apply changes from code review Co-authored-by: Juliette <663378+jrfnl@users.noreply.github.com> --- .../Tests/Security/EscapeOutputUnitTest.1.inc | 39 ++++++++++++++++++- .../Tests/Security/EscapeOutputUnitTest.php | 17 +++++--- 2 files changed, 48 insertions(+), 8 deletions(-) diff --git a/WordPress/Tests/Security/EscapeOutputUnitTest.1.inc b/WordPress/Tests/Security/EscapeOutputUnitTest.1.inc index afb3e51700..772d949a60 100644 --- a/WordPress/Tests/Security/EscapeOutputUnitTest.1.inc +++ b/WordPress/Tests/Security/EscapeOutputUnitTest.1.inc @@ -661,7 +661,7 @@ exit( status: esc_html( $foo ) ); // Ok. die( status: esc_html( $foo ) ); // Ok. exit( status: $foo ); // Bad. -\die( status: $foo ); // Bad. +\Die( status: $foo ); // Bad. /* * Issue https://github.com/WordPress/WordPress-Coding-Standards/issues/2552 @@ -763,6 +763,41 @@ _deprecated_file( MyClass::basename( __FILE__ ), '1.3.0' ); // Bad. _deprecated_file( BASENAME, __FILE__ ); // Bad. _deprecated_file( MyNamespace\basename( __FILE__ ), '1.3.0' ); // Bad. _deprecated_file( \MyNamespace\basename( __FILE__ ), '1.3.0' ); // Bad. -_deprecated_file( namespace\basename( __FILE__ ), '1.3.0' ); // Bad. We might want to update the regex so that the sniff stop flagging this once it can resolve relative namespaces. +_deprecated_file( namespace\basename( __FILE__ ), '1.3.0' ); // Bad. We might want to update the regex so that the sniff stops flagging this once it can resolve relative namespaces. _deprecated_file( namespace\Sub\basename( __FILE__ ), '1.3.0' ); // Bad. _deprecated_file( basename(...), '1.3.0' ); // Bad. + +/* + * Safeguard correct handling of FQN true/false/null constants. + */ +echo \true, \False, \NULL; // Ok. + +/* + * Safeguard correct handling of namespaced constants that mirror the name of "safe" global PHP constants. + */ +echo MyNamespace\PHP_EOL; // Bad. +echo \MyNamespace\PHP_VERSION_ID; // Bad. +echo namespace\PHP_EXTRA_VERSION; // Bad. The sniff should stop flagging this once it can resolve relative namespaces. +echo namespace\Sub\PHP_VERSION; // Bad. + +/* + * Safeguard correct handling of FQN functions with multiple PHP short echo tags. + */ +?> + + + +', \array_map( 'esc_html', $items ) ); // Ok. +echo implode( '
', MyNamespace\array_map( 'esc_html', $items ) ); // Bad x 2. +echo implode( '
', \MyNamespace\map_deep( $items, 'esc_html' ) ); // Bad. +echo implode( '
', namespace\array_map( 'esc_html', $items ) ); // Bad x 2. The sniff should stop flagging this once it can resolve relative namespaces. +echo implode( '
', namespace\Sub\map_deep( $items, 'esc_html' ) ); // Bad. diff --git a/WordPress/Tests/Security/EscapeOutputUnitTest.php b/WordPress/Tests/Security/EscapeOutputUnitTest.php index 39d0c46a5a..b6a8946584 100644 --- a/WordPress/Tests/Security/EscapeOutputUnitTest.php +++ b/WordPress/Tests/Security/EscapeOutputUnitTest.php @@ -10,7 +10,6 @@ namespace WordPressCS\WordPress\Tests\Security; use PHP_CodeSniffer\Tests\Standards\AbstractSniffUnitTest; -use PHPCSUtils\BackCompat\Helper; /** * Unit test class for the EscapeOutput sniff. @@ -38,8 +37,6 @@ final class EscapeOutputUnitTest extends AbstractSniffUnitTest { public function getErrorList( $testFile = '' ) { switch ( $testFile ) { case 'EscapeOutputUnitTest.1.inc': - $phpcs_version = Helper::getVersion(); - return array( 17 => 1, 19 => 1, @@ -163,9 +160,7 @@ public function getErrorList( $testFile = '' ) { 655 => 1, 657 => 1, 663 => 1, - // PHPCS 3.13.3 changed the tokenization of FQN exit/die it impacts directly how this test case - // behaves (see https://github.com/PHPCSStandards/PHP_CodeSniffer/issues/1201). - 664 => version_compare( $phpcs_version, '3.13.3', '>=' ) ? 1 : 0, + 664 => 1, 672 => 1, 673 => 1, 678 => 1, @@ -200,6 +195,16 @@ public function getErrorList( $testFile = '' ) { 766 => 1, 767 => 1, 768 => 1, + 778 => 1, + 779 => 1, + 780 => 1, + 781 => 1, + 787 => 1, + 788 => 1, + 800 => 2, + 801 => 1, + 802 => 2, + 803 => 1, ); case 'EscapeOutputUnitTest.6.inc': From 0638f0b80b0f0ae9529ab7190c4ed0e6f132c486 Mon Sep 17 00:00:00 2001 From: Rodrigo Primo Date: Wed, 10 Dec 2025 11:07:18 -0300 Subject: [PATCH 034/108] Security/EscapeOutput: fix false positive for get_search_query() with FQN/mixed-case true The sniff was incorrectly flagging `get_search_query()` calls as unsafe when the `$escaped` parameter was passed as fully qualified true or as true using a non-standard case. The comparison `'true' !== $escaped_param['clean']` failed because the parameter value wasn't normalized. This commit fixes this by stripping any leading backslash and converting to lowercase before comparison. --- WordPress/Sniffs/Security/EscapeOutputSniff.php | 2 +- WordPress/Tests/Security/EscapeOutputUnitTest.1.inc | 10 ++++++++++ WordPress/Tests/Security/EscapeOutputUnitTest.php | 3 +++ 3 files changed, 14 insertions(+), 1 deletion(-) diff --git a/WordPress/Sniffs/Security/EscapeOutputSniff.php b/WordPress/Sniffs/Security/EscapeOutputSniff.php index e0714e36c4..8a964cc020 100644 --- a/WordPress/Sniffs/Security/EscapeOutputSniff.php +++ b/WordPress/Sniffs/Security/EscapeOutputSniff.php @@ -741,7 +741,7 @@ protected function check_code_is_escaped( $start, $end, $code = 'OutputNotEscape // Special case get_search_query() which is unsafe if $escaped = false. if ( 'get_search_query' === strtolower( $functionName ) ) { $escaped_param = PassedParameters::getParameter( $this->phpcsFile, $ptr, 1, 'escaped' ); - if ( false !== $escaped_param && 'true' !== $escaped_param['clean'] ) { + if ( false !== $escaped_param && 'true' !== strtolower( ltrim( $escaped_param['clean'], '\\' ) ) ) { $this->phpcsFile->addError( 'Output from get_search_query() is unsafe due to $escaped parameter being set to "false".', $ptr, diff --git a/WordPress/Tests/Security/EscapeOutputUnitTest.1.inc b/WordPress/Tests/Security/EscapeOutputUnitTest.1.inc index 772d949a60..5946578951 100644 --- a/WordPress/Tests/Security/EscapeOutputUnitTest.1.inc +++ b/WordPress/Tests/Security/EscapeOutputUnitTest.1.inc @@ -801,3 +801,13 @@ echo implode( '
', MyNamespace\array_map( 'esc_html', $items ) ); // Bad x 2. echo implode( '
', \MyNamespace\map_deep( $items, 'esc_html' ) ); // Bad. echo implode( '
', namespace\array_map( 'esc_html', $items ) ); // Bad x 2. The sniff should stop flagging this once it can resolve relative namespaces. echo implode( '
', namespace\Sub\map_deep( $items, 'esc_html' ) ); // Bad. + +/* + * Safeguard correct handling of get_search_query() with FQN and non-standard case booleans for the $escaped parameter. + */ +echo \get_search_query( TRUE ); // Ok. +echo \get_search_query( \true ); // Ok. +echo \get_search_query( \True ); // Ok. +echo \get_search_query( FaLsE ); // Bad. +echo \get_search_query( \false ); // Bad. +echo \get_search_query( \FALSE ); // Bad. diff --git a/WordPress/Tests/Security/EscapeOutputUnitTest.php b/WordPress/Tests/Security/EscapeOutputUnitTest.php index b6a8946584..7111a1ff13 100644 --- a/WordPress/Tests/Security/EscapeOutputUnitTest.php +++ b/WordPress/Tests/Security/EscapeOutputUnitTest.php @@ -205,6 +205,9 @@ public function getErrorList( $testFile = '' ) { 801 => 1, 802 => 2, 803 => 1, + 811 => 1, + 812 => 1, + 813 => 1, ); case 'EscapeOutputUnitTest.6.inc': From 93bf823dda70189a003f3b7ad9f385a9fcec837d Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 15 Dec 2025 09:05:56 +0000 Subject: [PATCH 035/108] GH Actions: Bump codecov/codecov-action in the action-runners group Bumps the action-runners group with 1 update: [codecov/codecov-action](https://github.com/codecov/codecov-action). Updates `codecov/codecov-action` from 5.5.1 to 5.5.2 - [Release notes](https://github.com/codecov/codecov-action/releases) - [Changelog](https://github.com/codecov/codecov-action/blob/main/CHANGELOG.md) - [Commits](https://github.com/codecov/codecov-action/compare/5a1091511ad55cbe89839c7260b706298ca349f7...671740ac38dd9b0130fbe1cec585b89eea48d3de) --- updated-dependencies: - dependency-name: codecov/codecov-action dependency-version: 5.5.2 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: action-runners ... Signed-off-by: dependabot[bot] --- .github/workflows/quicktest.yml | 2 +- .github/workflows/unit-tests.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/quicktest.yml b/.github/workflows/quicktest.yml index 462ced3768..9f3458fa43 100644 --- a/.github/workflows/quicktest.yml +++ b/.github/workflows/quicktest.yml @@ -75,7 +75,7 @@ jobs: - name: Send coverage report to Codecov if: ${{ success() && github.event.repository.fork == false && github.ref_name == 'develop' }} - uses: codecov/codecov-action@5a1091511ad55cbe89839c7260b706298ca349f7 # v5.5.1 + uses: codecov/codecov-action@671740ac38dd9b0130fbe1cec585b89eea48d3de # v5.5.2 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 4502ac7042..b09e24bdf3 100644 --- a/.github/workflows/unit-tests.yml +++ b/.github/workflows/unit-tests.yml @@ -137,7 +137,7 @@ jobs: - name: Send coverage report to Codecov if: ${{ success() && matrix.coverage == true && github.event.repository.fork == false }} - uses: codecov/codecov-action@5a1091511ad55cbe89839c7260b706298ca349f7 # v5.5.1 + uses: codecov/codecov-action@671740ac38dd9b0130fbe1cec585b89eea48d3de # v5.5.2 with: files: ./build/logs/clover.xml fail_ci_if_error: true From 4086bb079023e2cadff145a97b312ba70a09a77d Mon Sep 17 00:00:00 2001 From: Rodrigo Primo Date: Fri, 15 Aug 2025 15:21:55 -0300 Subject: [PATCH 036/108] ConstantsHelper::is_use_of_global_constant(): do not treat `use const` alias as global constant usage This method was incorrectly identifying a constant alias as a global constant. This change aligns this method with how the sibling method in PHPCompatibility behaves (https://github.com/PHPCompatibility/PHPCompatibility/blob/6e10469b0f3827862b37df2ac2b7ec4580ce888f/PHPCompatibility/Helpers/MiscHelper.php#L45). --- WordPress/Helpers/ConstantsHelper.php | 1 + WordPress/Tests/WP/DiscouragedConstantsUnitTest.inc | 2 +- WordPress/Tests/WP/DiscouragedConstantsUnitTest.php | 1 - 3 files changed, 2 insertions(+), 2 deletions(-) diff --git a/WordPress/Helpers/ConstantsHelper.php b/WordPress/Helpers/ConstantsHelper.php index 6decbb4010..320c6312f8 100644 --- a/WordPress/Helpers/ConstantsHelper.php +++ b/WordPress/Helpers/ConstantsHelper.php @@ -79,6 +79,7 @@ public static function is_use_of_global_constant( File $phpcsFile, $stackPtr ) { \T_INSTANCEOF => true, \T_INSTEADOF => true, \T_GOTO => true, + \T_AS => true, ); $tokens_to_ignore += Tokens::$ooScopeTokens; $tokens_to_ignore += Collections::objectOperators(); diff --git a/WordPress/Tests/WP/DiscouragedConstantsUnitTest.inc b/WordPress/Tests/WP/DiscouragedConstantsUnitTest.inc index 50302d54fc..f7a4a1d48f 100644 --- a/WordPress/Tests/WP/DiscouragedConstantsUnitTest.inc +++ b/WordPress/Tests/WP/DiscouragedConstantsUnitTest.inc @@ -61,7 +61,7 @@ echo BACKGROUND_COLOR; echo BACKGROUND_IMAGE; use const STYLESHEETPATH as SSP; -use const ABC as STYLESHEETPATH; +use const ABC as STYLESHEETPATH; // This is ok, as `STYLESHEETPATH` is not a global constant here. switch( STYLESHEETPATH ) { case STYLESHEETPATH: diff --git a/WordPress/Tests/WP/DiscouragedConstantsUnitTest.php b/WordPress/Tests/WP/DiscouragedConstantsUnitTest.php index 138d0eb4ef..9e820865ca 100644 --- a/WordPress/Tests/WP/DiscouragedConstantsUnitTest.php +++ b/WordPress/Tests/WP/DiscouragedConstantsUnitTest.php @@ -49,7 +49,6 @@ public function getWarningList() { 60 => 1, 61 => 1, 63 => 1, - 64 => 1, 66 => 1, 67 => 1, 71 => 1, From 1e334662bf22a983875a6c2e822d99e73d184a8b Mon Sep 17 00:00:00 2001 From: Rodrigo Primo Date: Thu, 6 Nov 2025 10:39:29 -0300 Subject: [PATCH 037/108] WP/CapitalPDangit: add tests for namespaced names --- WordPress/Tests/WP/CapitalPDangitUnitTest.1.inc | 9 +++++++++ WordPress/Tests/WP/CapitalPDangitUnitTest.1.inc.fixed | 9 +++++++++ WordPress/Tests/WP/CapitalPDangitUnitTest.php | 4 ++++ 3 files changed, 22 insertions(+) diff --git a/WordPress/Tests/WP/CapitalPDangitUnitTest.1.inc b/WordPress/Tests/WP/CapitalPDangitUnitTest.1.inc index 391148fb56..fd95c66be2 100644 --- a/WordPress/Tests/WP/CapitalPDangitUnitTest.1.inc +++ b/WordPress/Tests/WP/CapitalPDangitUnitTest.1.inc @@ -244,3 +244,12 @@ class TypeClassConstants { // Ensures no false positives on incorrect casing in a class constant type name. public const (\Fully\Qualified\MyClass&wordPRESS)|string ANOTHER_WORDPRESS = 'wordpress'; } + +/* + * Safeguard correct handling of all types of namespaced calls to the define() function. + */ +\DEFINE( 'WORDPRESS_SOMETHING', 'wordpress' ); // OK. +MyNamespace\define( 'WORDPRESS_SOMETHING', 'wordpress' ); // Bad. +\MyNamespace\Define( 'WORDPRESS_SOMETHING', 'wordpress' ); // Bad. +namespace\Sub\define( 'WORDPRESS_SOMETHING', 'wordpress' ); // Bad. +namespace\define( 'WORDPRESS_SOMETHING', 'wordpress' ); // The sniff should stop flagging this once it can resolve relative namespaces. diff --git a/WordPress/Tests/WP/CapitalPDangitUnitTest.1.inc.fixed b/WordPress/Tests/WP/CapitalPDangitUnitTest.1.inc.fixed index 5630f0d415..d43a7af60b 100644 --- a/WordPress/Tests/WP/CapitalPDangitUnitTest.1.inc.fixed +++ b/WordPress/Tests/WP/CapitalPDangitUnitTest.1.inc.fixed @@ -244,3 +244,12 @@ class TypeClassConstants { // Ensures no false positives on incorrect casing in a class constant type name. public const (\Fully\Qualified\MyClass&wordPRESS)|string ANOTHER_WORDPRESS = 'wordpress'; } + +/* + * Safeguard correct handling of all types of namespaced calls to the define() function. + */ +\DEFINE( 'WORDPRESS_SOMETHING', 'wordpress' ); // OK. +MyNamespace\define( 'WORDPRESS_SOMETHING', 'WordPress' ); // Bad. +\MyNamespace\Define( 'WORDPRESS_SOMETHING', 'WordPress' ); // Bad. +namespace\Sub\define( 'WORDPRESS_SOMETHING', 'WordPress' ); // Bad. +namespace\define( 'WORDPRESS_SOMETHING', 'WordPress' ); // The sniff should stop flagging this once it can resolve relative namespaces. diff --git a/WordPress/Tests/WP/CapitalPDangitUnitTest.php b/WordPress/Tests/WP/CapitalPDangitUnitTest.php index ea1cfcf65e..ff545fcc65 100644 --- a/WordPress/Tests/WP/CapitalPDangitUnitTest.php +++ b/WordPress/Tests/WP/CapitalPDangitUnitTest.php @@ -69,6 +69,10 @@ public function getWarningList( $testFile = '' ) { 204 => 1, 205 => 1, 224 => 1, + 252 => 1, + 253 => 1, + 254 => 1, + 255 => 1, ); case 'CapitalPDangitUnitTest.2.inc': From fae2dc0baeb909784f3917d4da741279679c55d7 Mon Sep 17 00:00:00 2001 From: Xristopher Anderton Date: Tue, 17 Sep 2024 10:53:29 -0700 Subject: [PATCH 038/108] PHP/PregQuoteDelimiter: add XML documentation Co-authored-by: Juliette <663378+jrfnl@users.noreply.github.com> --- .../Docs/PHP/PregQuoteDelimiterStandard.xml | 35 +++++++++++++++++++ 1 file changed, 35 insertions(+) create mode 100644 WordPress/Docs/PHP/PregQuoteDelimiterStandard.xml diff --git a/WordPress/Docs/PHP/PregQuoteDelimiterStandard.xml b/WordPress/Docs/PHP/PregQuoteDelimiterStandard.xml new file mode 100644 index 0000000000..1b91c32fc7 --- /dev/null +++ b/WordPress/Docs/PHP/PregQuoteDelimiterStandard.xml @@ -0,0 +1,35 @@ + + + + + + + + '#' ); +preg_match( + '#^' . $quoted_input . '#i', + $post_content, + $matches +); + ]]> + + + ); +preg_match( + '#^' . $quoted_input . '#i', + $post_content, + $matches +); + ]]> + + + From 86ea20d5ebb52886a16f7d2a17607889f0a7f60b Mon Sep 17 00:00:00 2001 From: Paul Wong-Gibbs Date: Thu, 13 Jun 2024 11:40:14 +0200 Subject: [PATCH 039/108] DB/RestrictedFunctions: add XML documentation --- .../Docs/DB/RestrictedFunctionsStandard.xml | 53 +++++++++++++++++++ 1 file changed, 53 insertions(+) create mode 100644 WordPress/Docs/DB/RestrictedFunctionsStandard.xml diff --git a/WordPress/Docs/DB/RestrictedFunctionsStandard.xml b/WordPress/Docs/DB/RestrictedFunctionsStandard.xml new file mode 100644 index 0000000000..75defe7fba --- /dev/null +++ b/WordPress/Docs/DB/RestrictedFunctionsStandard.xml @@ -0,0 +1,53 @@ + + + + + + + + get_posts(); + ]]> + + + mysqli_query( + $mysql, + "SELECT * FROM wp_posts LIMIT 5" +); + ]]> + + + + + wp_insert_post( + array( 'post_title' => 'Title' ) +); + +// or... + +global $wpdb; +$wpdb->insert( + $wpdb->posts, + array( 'post_title' => 'Title' ), + array( '%s' ) +); + ]]> + + + mysqli_query( + $mysql, + "INSERT INTO wp_posts (post_title) + VALUES ('Title')" +); + ]]> + + + From a7e514ac621d38a5b55838a5f077fc640c9301c8 Mon Sep 17 00:00:00 2001 From: Rodrigo Primo Date: Thu, 25 Dec 2025 09:46:57 -0300 Subject: [PATCH 040/108] WP/DiscouragedConstants: update sniff docblock to mention constants (re-)declaration check Also fixes casing of "CONSTANTS" to "constants". --- WordPress/Sniffs/WP/DiscouragedConstantsSniff.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/WordPress/Sniffs/WP/DiscouragedConstantsSniff.php b/WordPress/Sniffs/WP/DiscouragedConstantsSniff.php index 7db5a37854..bd3486205a 100644 --- a/WordPress/Sniffs/WP/DiscouragedConstantsSniff.php +++ b/WordPress/Sniffs/WP/DiscouragedConstantsSniff.php @@ -17,7 +17,7 @@ use WordPressCS\WordPress\Helpers\ConstantsHelper; /** - * Warns against usage of discouraged WP CONSTANTS and recommends alternatives. + * Warns against usage and (re-)declaration of discouraged WP constants and recommends alternatives. * * @since 0.14.0 */ From 8679889abb24bed762e7240029a6142c39429c80 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 5 Jan 2026 22:26:41 +0000 Subject: [PATCH 041/108] 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.40.0 to 1.41.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/2d0ce569feab1f8752f1dde43cc2f2aa53236e06...5c19779cb52ea50e151f5a10333ccd269227b5ae) --- updated-dependencies: - dependency-name: crate-ci/typos dependency-version: 1.41.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 81f0477c29..538d8a34e1 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@2d0ce569feab1f8752f1dde43cc2f2aa53236e06" # v1.40.0 + uses: "crate-ci/typos@5c19779cb52ea50e151f5a10333ccd269227b5ae" # v1.41.0 From 9c8a85e29f5f5d2490f50d1b660f5040feb611e6 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 20 Jan 2026 22:13:54 +0000 Subject: [PATCH 042/108] 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.41.0 to 1.42.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/5c19779cb52ea50e151f5a10333ccd269227b5ae...65120634e79d8374d1aa2f27e54baa0c364fff5a) --- updated-dependencies: - dependency-name: crate-ci/typos dependency-version: 1.42.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 538d8a34e1..7fbabac4e1 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@5c19779cb52ea50e151f5a10333ccd269227b5ae" # v1.41.0 + uses: "crate-ci/typos@65120634e79d8374d1aa2f27e54baa0c364fff5a" # v1.42.1 From 773710034640eca5675fb690ce8083882818422e Mon Sep 17 00:00:00 2001 From: Jason Kenison Date: Tue, 27 Jan 2026 23:16:43 -0800 Subject: [PATCH 043/108] Add documentation for sniff WordPress.Security.PluginMenuSlug (#2592) Describes check for __FILE__ in plugin menu slugs. --- .../Docs/Security/PluginMenuSlugStandard.xml | 53 +++++++++++++++++++ 1 file changed, 53 insertions(+) create mode 100644 WordPress/Docs/Security/PluginMenuSlugStandard.xml diff --git a/WordPress/Docs/Security/PluginMenuSlugStandard.xml b/WordPress/Docs/Security/PluginMenuSlugStandard.xml new file mode 100644 index 0000000000..df6b52e375 --- /dev/null +++ b/WordPress/Docs/Security/PluginMenuSlugStandard.xml @@ -0,0 +1,53 @@ + + + + + + + + 'my-plugin-main', + 'my_plugin_main_page' +); + +add_submenu_page( + 'my_plugin_main_page', + 'My Plugin Subpage', + 'Subpage', + 'manage_options', + 'my-plugin-subpage', + 'my_plugin_subpage' +); + ]]> + + + __FILE__, + 'my_plugin_main_page' +); + +add_submenu_page( + __FILE__ . 'my_plugin_main_page', + 'My Plugin Subpage', + 'Subpage', + 'manage_options', + 'my-plugin-subpage', + 'my_plugin_subpage' +); + ]]> + + + From fa02bc4cdd5c76433844721d37dc2cf22db7c91f Mon Sep 17 00:00:00 2001 From: Rodrigo Primo Date: Fri, 30 Jan 2026 06:10:21 -0300 Subject: [PATCH 044/108] WP/GlobalVariablesOverride: add XML documentation (#2679) * Add GlobalVariableOverride standard doc --------- Co-authored-by: Paulo Trentin Co-authored-by: Juliette <663378+jrfnl@users.noreply.github.com> --- .../WP/GlobalVariablesOverrideStandard.xml | 41 +++++++++++++++++++ 1 file changed, 41 insertions(+) create mode 100644 WordPress/Docs/WP/GlobalVariablesOverrideStandard.xml diff --git a/WordPress/Docs/WP/GlobalVariablesOverrideStandard.xml b/WordPress/Docs/WP/GlobalVariablesOverrideStandard.xml new file mode 100644 index 0000000000..18df55e13a --- /dev/null +++ b/WordPress/Docs/WP/GlobalVariablesOverrideStandard.xml @@ -0,0 +1,41 @@ + + + + + + + + $prefix_query = new WP_Query( $args ); + +$GLOBALS['prefix_data'] = 'some data'; + +foreach ( $selected_posts as $prefix_post ) { + // Do something. +} + ]]> + + + global $wp_query; + $wp_query = new WP_Query( $args ); + + $GLOBALS['post'] = get_post( 1 ); +} + +foreach ( $selected_posts as $post ) { + // Do something. +} + ]]> + + + From a3f1eeda91ddeba97941d84caf60493a07730614 Mon Sep 17 00:00:00 2001 From: Rodrigo Primo Date: Mon, 2 Feb 2026 05:57:25 -0300 Subject: [PATCH 045/108] WP/DiscouragedConstants: add XML documentation (#2680) * Adding documentation to WordPress.WP.DiscouragedConstants --------- Co-authored-by: paulopmt1 Co-authored-by: RafaelFunchal --- .../Docs/WP/DiscouragedConstantsStandard.xml | 46 +++++++++++++++++++ 1 file changed, 46 insertions(+) create mode 100644 WordPress/Docs/WP/DiscouragedConstantsStandard.xml diff --git a/WordPress/Docs/WP/DiscouragedConstantsStandard.xml b/WordPress/Docs/WP/DiscouragedConstantsStandard.xml new file mode 100644 index 0000000000..583d62d767 --- /dev/null +++ b/WordPress/Docs/WP/DiscouragedConstantsStandard.xml @@ -0,0 +1,46 @@ + + + + + + + + get_stylesheet_directory(); + ]]> + + + STYLESHEETPATH; + ]]> + + + + + + + + add_theme_support( + 'custom-header', + array( 'width' => 200 ) +); + ]]> + + + 'HEADER_IMAGE_WIDTH', + 200 +); + ]]> + + + From 9508e0d5e9042d3828893708843e87277faa77fb Mon Sep 17 00:00:00 2001 From: Nic-Sevic <47717887+Nic-Sevic@users.noreply.github.com> Date: Tue, 17 Sep 2024 11:56:14 -0700 Subject: [PATCH 046/108] Add: documentation for AssignmentInTernaryCondition sniff MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Nic Co-authored-by: Juliette <663378+jrfnl@users.noreply.github.com> Co-authored-by: Denis Žoljom --- .../AssignmentInTernaryConditionStandard.xml | 25 +++++++++++++++++++ 1 file changed, 25 insertions(+) create mode 100644 WordPress/Docs/CodeAnalysis/AssignmentInTernaryConditionStandard.xml diff --git a/WordPress/Docs/CodeAnalysis/AssignmentInTernaryConditionStandard.xml b/WordPress/Docs/CodeAnalysis/AssignmentInTernaryConditionStandard.xml new file mode 100644 index 0000000000..5cb2579dba --- /dev/null +++ b/WordPress/Docs/CodeAnalysis/AssignmentInTernaryConditionStandard.xml @@ -0,0 +1,25 @@ + + + + + + + + === 'a' ) ? 'b' : 'c'; + ]]> + + + = 'a' ) ? 'b' : 'c'; + ]]> + + + From eefd218f96c8644eed2869408871922cdada33a1 Mon Sep 17 00:00:00 2001 From: Rafael Funchal Date: Tue, 17 Sep 2024 11:58:29 -0700 Subject: [PATCH 047/108] Adding documentation for WordPress.Arrays.ArrayDeclarationSpacing Co-authored-by: RafaelFunchal Co-authored-by: mattgaldino Co-authored-by: Rodrigo Primo Co-authored-by: Juliette <663378+jrfnl@users.noreply.github.com> --- .../ArrayDeclarationSpacingStandard.xml | 58 +++++++++++++++++++ 1 file changed, 58 insertions(+) create mode 100644 WordPress/Docs/Arrays/ArrayDeclarationSpacingStandard.xml diff --git a/WordPress/Docs/Arrays/ArrayDeclarationSpacingStandard.xml b/WordPress/Docs/Arrays/ArrayDeclarationSpacingStandard.xml new file mode 100644 index 0000000000..9b61acc2aa --- /dev/null +++ b/WordPress/Docs/Arrays/ArrayDeclarationSpacingStandard.xml @@ -0,0 +1,58 @@ + + + + + + + + 'cat' => 1, + 'paged' => 2, +); + ]]> + + + 'cat' => 1, 'paged' => 2 ); + ]]> + + + + + + + + 'post', + 'page', +); + +$args = array( + 'cat' => 1, + 'paged' => 2, +); + ]]> + + + 'post', 'page', +); + + +$args = array( + 'cat' => 1, 'paged' => 2, +); + ]]> + + + From 547b7ab3affb295cbe12fda348d0ef7fb745fc39 Mon Sep 17 00:00:00 2001 From: Paul Wong-Gibbs Date: Thu, 13 Jun 2024 12:17:00 +0200 Subject: [PATCH 048/108] Add documentation for WordPress.DB.RestrictedClasses Co-authored-by: Paul Wong-Gibbs Co-authored-by: Rodrigo Primo Co-authored-by: Juliette <663378+jrfnl@users.noreply.github.com> --- .../Docs/DB/RestrictedClassesStandard.xml | 66 +++++++++++++++++++ 1 file changed, 66 insertions(+) create mode 100644 WordPress/Docs/DB/RestrictedClassesStandard.xml diff --git a/WordPress/Docs/DB/RestrictedClassesStandard.xml b/WordPress/Docs/DB/RestrictedClassesStandard.xml new file mode 100644 index 0000000000..36094d6b9c --- /dev/null +++ b/WordPress/Docs/DB/RestrictedClassesStandard.xml @@ -0,0 +1,66 @@ + + + + + + + + get_posts(); + ]]> + + + new mysqli( + 'localhost', + $user, + $pass, + $db +); + +$results = $mysqli->query( + "SELECT * FROM wp_posts LIMIT 5" +); + ]]> + + + + + wp_insert_post( + array( 'post_title' => 'Title' ) +); + +// or... + +global $wpdb; +$wpdb->insert( + $wpdb->posts, + array( 'post_title' => 'Title' ), + array( '%s' ) +); + ]]> + + + new PDO( + $dsn, + $user, + $pass +); + +$stmt = $pdo->prepare( + "INSERT INTO wp_posts (post_title) + VALUES (?)" +); + +$stmt->execute( array( 'Title' ) ); + ]]> + + + From 3ee819c5ba95fa9d012ac9b54b4bcc587d1bbbd5 Mon Sep 17 00:00:00 2001 From: Rodrigo Primo Date: Wed, 4 Feb 2026 04:02:19 -0300 Subject: [PATCH 049/108] PHP/DevelopmentFunctions: add XML documentation (#2690) * Add documentation for WordPress.PHP.DevelopmentFunctions --------- Co-authored-by: gogdzl --- WordPress/Docs/PHP/DevelopmentFunctionsStandard.xml | 11 +++++++++++ 1 file changed, 11 insertions(+) create mode 100644 WordPress/Docs/PHP/DevelopmentFunctionsStandard.xml diff --git a/WordPress/Docs/PHP/DevelopmentFunctionsStandard.xml b/WordPress/Docs/PHP/DevelopmentFunctionsStandard.xml new file mode 100644 index 0000000000..625d86c435 --- /dev/null +++ b/WordPress/Docs/PHP/DevelopmentFunctionsStandard.xml @@ -0,0 +1,11 @@ + + + + + + From c026fb2191d360750ab72dc3f5a919ff2758aa6d Mon Sep 17 00:00:00 2001 From: Rodrigo Primo Date: Wed, 4 Feb 2026 13:19:45 -0300 Subject: [PATCH 050/108] Arrays/ArrayDeclarationSpacing: replace "associative" with "explicit keys" (#2688) Updates one error message and docblocks to use "arrays with explicit keys" instead of "associative arrays" to align with the PHP handbook terminology. The sniff has always checked for arrays with explicit keys (whether string or numeric), not just associative arrays with string keys. This change aligns the wording with the actual behavior. The public property `allow_single_item_single_line_associative_arrays` and the error code `AssociativeArrayFound` are intentionally left unchanged to avoid breaking changes for users who reference them in their ruleset configurations. Ref: wpcs-docs 156, wpcs-docs 157 --- .../Sniffs/Arrays/ArrayDeclarationSpacingSniff.php | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/WordPress/Sniffs/Arrays/ArrayDeclarationSpacingSniff.php b/WordPress/Sniffs/Arrays/ArrayDeclarationSpacingSniff.php index bd0f75acf1..ae44ca523b 100644 --- a/WordPress/Sniffs/Arrays/ArrayDeclarationSpacingSniff.php +++ b/WordPress/Sniffs/Arrays/ArrayDeclarationSpacingSniff.php @@ -19,21 +19,21 @@ /** * Enforces WordPress array spacing format. * - * - Checks that associative arrays are multi-line. + * - Checks that arrays with explicit keys are multi-line. * - Checks that each array item in a multi-line array starts on a new line. * * @link https://developer.wordpress.org/coding-standards/wordpress-coding-standards/php/#indentation * * @since 0.11.0 - The WordPress specific additional checks have now been split off * from the `WordPress.Arrays.ArrayDeclaration` sniff into this sniff. - * - Added sniffing & fixing for associative arrays. + * - Added sniffing & fixing for arrays with explicit keys. * @since 0.12.0 Decoupled this sniff from the upstream sniff completely. * This sniff now extends the WordPressCS native `Sniff` class instead. * @since 0.13.0 Added the last remaining checks from the `WordPress.Arrays.ArrayDeclaration` * sniff which were not covered elsewhere. * The `WordPress.Arrays.ArrayDeclaration` sniff has now been deprecated. * @since 0.13.0 Class name changed: this class is now namespaced. - * @since 0.14.0 Single item associative arrays are now by default exempt from the + * @since 0.14.0 Single item arrays with explicit keys are now by default exempt from the * "must be multi-line" rule. This behavior can be changed using the * `allow_single_item_single_line_associative_arrays` property. * @since 3.0.0 Removed various whitespace related checks and fixers in favor of the PHPCSExtra @@ -42,7 +42,7 @@ final class ArrayDeclarationSpacingSniff extends Sniff { /** - * Whether or not to allow single item associative arrays to be single line. + * Whether or not to allow single item arrays with explicit keys to be single line. * * @since 0.14.0 * @@ -102,7 +102,7 @@ public function process_token( $stackPtr ) { } /** - * Check that associative arrays are always multi-line. + * Check that arrays with explicit keys are always multi-line. * * @since 0.13.0 The actual checks contained in this method used to * be in the `process()` method. @@ -137,9 +137,9 @@ protected function process_single_line_array( $stackPtr, $opener, $closer ) { if ( false === $array_has_keys ) { return; } - $error = 'When an array uses associative keys, each value should start on %s.'; + $error = 'When an array is declared with explicit keys, each value should start on %s.'; if ( true === $this->allow_single_item_single_line_associative_arrays ) { - $error = 'When a multi-item array uses associative keys, each value should start on %s.'; + $error = 'When a multi-item array is declared with explicit keys, each value should start on %s.'; } /* From e3c8568d80b730861ed409e88fcfb0782b96bf6a Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 5 Feb 2026 22:13:36 +0000 Subject: [PATCH 051/108] 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 6.0.1 to 6.0.2 - [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/8e8c483db84b4bee98b60c0593521ed34d9990e8...de0fac2e4500dabe0009e67214ff5f5447ce83dd) Updates `crate-ci/typos` from 1.42.1 to 1.43.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/65120634e79d8374d1aa2f27e54baa0c364fff5a...ad3053d3adbcce7f2e3c60fd4ddfc239787d1eff) --- updated-dependencies: - dependency-name: actions/checkout dependency-version: 6.0.2 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: action-runners - dependency-name: crate-ci/typos dependency-version: 1.43.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 | 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 7fbabac4e1..f7575f4c4c 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@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1 + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 with: persist-credentials: false @@ -117,7 +117,7 @@ jobs: steps: - name: Checkout code - uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1 + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 with: persist-credentials: false @@ -157,7 +157,7 @@ jobs: steps: - name: Checkout repository - uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1 + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 with: persist-credentials: false @@ -240,7 +240,7 @@ jobs: steps: - name: Checkout code - uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1 + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 with: persist-credentials: false @@ -270,9 +270,9 @@ jobs: steps: - name: "Checkout" - uses: "actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8" # v6.0.1 + uses: "actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd" # v6.0.2 with: persist-credentials: false - name: "Search for misspellings" - uses: "crate-ci/typos@65120634e79d8374d1aa2f27e54baa0c364fff5a" # v1.42.1 + uses: "crate-ci/typos@ad3053d3adbcce7f2e3c60fd4ddfc239787d1eff" # v1.43.2 diff --git a/.github/workflows/quicktest.yml b/.github/workflows/quicktest.yml index 9f3458fa43..90de6af732 100644 --- a/.github/workflows/quicktest.yml +++ b/.github/workflows/quicktest.yml @@ -30,7 +30,7 @@ jobs: steps: - name: Checkout repository - uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1 + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 with: persist-credentials: false diff --git a/.github/workflows/unit-tests.yml b/.github/workflows/unit-tests.yml index b09e24bdf3..6d9c44dee5 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@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1 + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 with: persist-credentials: false From 03a96eebf88e21db4eeef7131095509592445f70 Mon Sep 17 00:00:00 2001 From: Rodrigo Primo Date: Fri, 6 Feb 2026 11:35:29 -0300 Subject: [PATCH 052/108] Arrays/ArrayDeclarationSpacing: move parse error test to its own file --- .../Tests/Arrays/ArrayDeclarationSpacingUnitTest.1.inc | 4 ---- .../Arrays/ArrayDeclarationSpacingUnitTest.1.inc.fixed | 4 ---- .../Tests/Arrays/ArrayDeclarationSpacingUnitTest.3.inc | 8 ++++++++ 3 files changed, 8 insertions(+), 8 deletions(-) create mode 100644 WordPress/Tests/Arrays/ArrayDeclarationSpacingUnitTest.3.inc diff --git a/WordPress/Tests/Arrays/ArrayDeclarationSpacingUnitTest.1.inc b/WordPress/Tests/Arrays/ArrayDeclarationSpacingUnitTest.1.inc index fd47c0a3a9..a40f8fcd78 100644 --- a/WordPress/Tests/Arrays/ArrayDeclarationSpacingUnitTest.1.inc +++ b/WordPress/Tests/Arrays/ArrayDeclarationSpacingUnitTest.1.inc @@ -81,7 +81,3 @@ $bad = array( // Don't confuse list arrows with array arrows. $okay = array( $item1, list( 'key1' => $a, 'key2' => $b ) = $array, $item3 ); - -// Live coding/parse error. -// This must be the last test in the file! -$ignore = array( $item1, 'key' => 'value', diff --git a/WordPress/Tests/Arrays/ArrayDeclarationSpacingUnitTest.1.inc.fixed b/WordPress/Tests/Arrays/ArrayDeclarationSpacingUnitTest.1.inc.fixed index c0bddcc551..072fee9908 100644 --- a/WordPress/Tests/Arrays/ArrayDeclarationSpacingUnitTest.1.inc.fixed +++ b/WordPress/Tests/Arrays/ArrayDeclarationSpacingUnitTest.1.inc.fixed @@ -134,7 +134,3 @@ $bad = array( // Don't confuse list arrows with array arrows. $okay = array( $item1, list( 'key1' => $a, 'key2' => $b ) = $array, $item3 ); - -// Live coding/parse error. -// This must be the last test in the file! -$ignore = array( $item1, 'key' => 'value', diff --git a/WordPress/Tests/Arrays/ArrayDeclarationSpacingUnitTest.3.inc b/WordPress/Tests/Arrays/ArrayDeclarationSpacingUnitTest.3.inc new file mode 100644 index 0000000000..184b1da687 --- /dev/null +++ b/WordPress/Tests/Arrays/ArrayDeclarationSpacingUnitTest.3.inc @@ -0,0 +1,8 @@ + 'value', From 735d3988ab1472fd8f8ccbae6e401814cac98559 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 20 Feb 2026 22:13:41 +0000 Subject: [PATCH 053/108] 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.43.2 to 1.43.5 - [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/ad3053d3adbcce7f2e3c60fd4ddfc239787d1eff...57b11c6b7e54c402ccd9cda953f1072ec4f78e33) --- updated-dependencies: - dependency-name: crate-ci/typos dependency-version: 1.43.5 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 f7575f4c4c..e4a0367ee7 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@ad3053d3adbcce7f2e3c60fd4ddfc239787d1eff" # v1.43.2 + uses: "crate-ci/typos@57b11c6b7e54c402ccd9cda953f1072ec4f78e33" # v1.43.5 From 021af8da046c216da95f1be1b09533e94000e262 Mon Sep 17 00:00:00 2001 From: jrfnl Date: Mon, 23 Feb 2026 15:35:31 +0100 Subject: [PATCH 054/108] NoSilencedErrors: remove tolerance for `parse_url()` The `parse_url()` function was in the list of functions allowed to use error silencing due to it throwing an `E_WARNING` in certain circumstances in PHP < 5.3.3. I believe by now, we should no longer need to take PHP < 5.3.3 into account, so this exception should no longer be permitted. --- WordPress/Sniffs/PHP/NoSilencedErrorsSniff.php | 1 - 1 file changed, 1 deletion(-) diff --git a/WordPress/Sniffs/PHP/NoSilencedErrorsSniff.php b/WordPress/Sniffs/PHP/NoSilencedErrorsSniff.php index 400da4a6dd..06cc8879be 100644 --- a/WordPress/Sniffs/PHP/NoSilencedErrorsSniff.php +++ b/WordPress/Sniffs/PHP/NoSilencedErrorsSniff.php @@ -142,7 +142,6 @@ final class NoSilencedErrorsSniff extends Sniff { // Miscellaneous other functions. 'imagecreatefromstring' => true, 'imagecreatefromwebp' => true, - 'parse_url' => true, // Pre-PHP 5.3.3 an E_WARNING was thrown when URL parsing failed. 'unserialize' => true, ); From 6a2ec07c2c4f196dca33da3f4119019afa445e63 Mon Sep 17 00:00:00 2001 From: jrfnl Date: Mon, 23 Feb 2026 15:44:00 +0100 Subject: [PATCH 055/108] PHP/RestrictedPHPFunctions: rephrase error message Follow up on the conversation about this phrasing in https://github.com/WordPress/WordPress-Coding-Standards/pull/2491#discussion_r1775744625 and https://github.com/WordPress/WordPress-Coding-Standards/pull/2693#discussion_r2841053023 Also related to: https://github.com/WordPress/wpcs-docs/pull/158 --- WordPress/Sniffs/PHP/RestrictedPHPFunctionsSniff.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/WordPress/Sniffs/PHP/RestrictedPHPFunctionsSniff.php b/WordPress/Sniffs/PHP/RestrictedPHPFunctionsSniff.php index f3102e33d5..f4c47c85e7 100644 --- a/WordPress/Sniffs/PHP/RestrictedPHPFunctionsSniff.php +++ b/WordPress/Sniffs/PHP/RestrictedPHPFunctionsSniff.php @@ -35,7 +35,7 @@ public function getGroups() { return array( 'create_function' => array( 'type' => 'error', - 'message' => '%s() is deprecated as of PHP 7.2 and removed in PHP 8.0. Please use declared named or anonymous functions instead.', + 'message' => '%s() internally performs an eval(), which makes this a very dangerous function. For this reason, it was deprecated as of PHP 7.2 and removed in PHP 8.0. Please use anonymous functions, or declare a named function instead.', 'functions' => array( 'create_function', ), From 2229662b6a1a1351775bafb9607862bfc6190965 Mon Sep 17 00:00:00 2001 From: Rodrigo Primo Date: Fri, 6 Feb 2026 11:42:02 -0300 Subject: [PATCH 056/108] Arrays/ArrayDeclarationSpacing: add new property and soft-deprecate old one Add `allow_single_item_single_line_explicit_key_arrays` property to replace `allow_single_item_single_line_associative_arrays`, aligning the property name with the "explicit keys" terminology from PR 2688. The old property is soft-deprecated (docblock only) and continues to work via a backward compatibility layer: if the new property has not been changed from its default and the old property has with a valid value, the old property's value is used. Closes: 2691 Co-authored-by: Juliette <663378+jrfnl@users.noreply.github.com> --- .../Arrays/ArrayDeclarationSpacingSniff.php | 27 +++++++++++-- .../ArrayDeclarationSpacingUnitTest.1.inc | 13 ++++++ ...rrayDeclarationSpacingUnitTest.1.inc.fixed | 18 +++++++++ .../ArrayDeclarationSpacingUnitTest.2.inc | 7 ++++ ...rrayDeclarationSpacingUnitTest.2.inc.fixed | 12 ++++++ .../ArrayDeclarationSpacingUnitTest.php | 40 ++++++++++--------- 6 files changed, 96 insertions(+), 21 deletions(-) diff --git a/WordPress/Sniffs/Arrays/ArrayDeclarationSpacingSniff.php b/WordPress/Sniffs/Arrays/ArrayDeclarationSpacingSniff.php index ae44ca523b..2e8b794e05 100644 --- a/WordPress/Sniffs/Arrays/ArrayDeclarationSpacingSniff.php +++ b/WordPress/Sniffs/Arrays/ArrayDeclarationSpacingSniff.php @@ -38,13 +38,25 @@ * `allow_single_item_single_line_associative_arrays` property. * @since 3.0.0 Removed various whitespace related checks and fixers in favor of the PHPCSExtra * `NormalizedArrays.Arrays.ArrayBraceSpacing` sniff. + * @since 3.4.0 The `allow_single_item_single_line_associative_arrays` property has been + * deprecated in favor of the new `allow_single_item_single_line_explicit_key_arrays` property. */ final class ArrayDeclarationSpacingSniff extends Sniff { + /** + * Whether to allow single item arrays with explicit keys to be single line. + * + * @since 3.4.0 + * + * @var bool Defaults to true. + */ + public $allow_single_item_single_line_explicit_key_arrays = true; + /** * Whether or not to allow single item arrays with explicit keys to be single line. * * @since 0.14.0 + * @deprecated 3.4.0 Use $allow_single_item_single_line_explicit_key_arrays instead. * * @var bool Defaults to true. */ @@ -114,10 +126,19 @@ public function process_token( $stackPtr ) { * @return void */ protected function process_single_line_array( $stackPtr, $opener, $closer ) { + // For now, if the new property has not been changed from its default value and the deprecated property has, use + // the deprecated property's value. + $allow_single_item = $this->allow_single_item_single_line_explicit_key_arrays; + if ( true === $allow_single_item + && false === $this->allow_single_item_single_line_associative_arrays + ) { + $allow_single_item = false; + } + $array_items = PassedParameters::getParameters( $this->phpcsFile, $stackPtr ); - if ( ( false === $this->allow_single_item_single_line_associative_arrays + if ( ( false === $allow_single_item && empty( $array_items ) ) - || ( true === $this->allow_single_item_single_line_associative_arrays + || ( true === $allow_single_item && \count( $array_items ) === 1 ) ) { return; @@ -138,7 +159,7 @@ protected function process_single_line_array( $stackPtr, $opener, $closer ) { return; } $error = 'When an array is declared with explicit keys, each value should start on %s.'; - if ( true === $this->allow_single_item_single_line_associative_arrays ) { + if ( true === $allow_single_item ) { $error = 'When a multi-item array is declared with explicit keys, each value should start on %s.'; } diff --git a/WordPress/Tests/Arrays/ArrayDeclarationSpacingUnitTest.1.inc b/WordPress/Tests/Arrays/ArrayDeclarationSpacingUnitTest.1.inc index a40f8fcd78..5bd00f8acf 100644 --- a/WordPress/Tests/Arrays/ArrayDeclarationSpacingUnitTest.1.inc +++ b/WordPress/Tests/Arrays/ArrayDeclarationSpacingUnitTest.1.inc @@ -81,3 +81,16 @@ $bad = array( // Don't confuse list arrows with array arrows. $okay = array( $item1, list( 'key1' => $a, 'key2' => $b ) = $array, $item3 ); + +// phpcs:set WordPress.Arrays.ArrayDeclarationSpacing allow_single_item_single_line_explicit_key_arrays false + +$bad = array( 'key' => 'value' ); // Bad. +$bad = array( 'key1' => 'value1', 'key2' => 'value2' ); // Bad. + +// phpcs:set WordPress.Arrays.ArrayDeclarationSpacing allow_single_item_single_line_explicit_key_arrays true + +// phpcs:set WordPress.Arrays.ArrayDeclarationSpacing allow_single_item_single_line_associative_arrays null + +$ok = array( 'key' => 'value' ); // OK, invalid value for deprecated property should be ignored. + +// phpcs:set WordPress.Arrays.ArrayDeclarationSpacing allow_single_item_single_line_associative_arrays true diff --git a/WordPress/Tests/Arrays/ArrayDeclarationSpacingUnitTest.1.inc.fixed b/WordPress/Tests/Arrays/ArrayDeclarationSpacingUnitTest.1.inc.fixed index 072fee9908..267427ae3b 100644 --- a/WordPress/Tests/Arrays/ArrayDeclarationSpacingUnitTest.1.inc.fixed +++ b/WordPress/Tests/Arrays/ArrayDeclarationSpacingUnitTest.1.inc.fixed @@ -134,3 +134,21 @@ $bad = array( // Don't confuse list arrows with array arrows. $okay = array( $item1, list( 'key1' => $a, 'key2' => $b ) = $array, $item3 ); + +// phpcs:set WordPress.Arrays.ArrayDeclarationSpacing allow_single_item_single_line_explicit_key_arrays false + +$bad = array( +'key' => 'value' +); // Bad. +$bad = array( +'key1' => 'value1', +'key2' => 'value2' +); // Bad. + +// phpcs:set WordPress.Arrays.ArrayDeclarationSpacing allow_single_item_single_line_explicit_key_arrays true + +// phpcs:set WordPress.Arrays.ArrayDeclarationSpacing allow_single_item_single_line_associative_arrays null + +$ok = array( 'key' => 'value' ); // OK, invalid value for deprecated property should be ignored. + +// phpcs:set WordPress.Arrays.ArrayDeclarationSpacing allow_single_item_single_line_associative_arrays true diff --git a/WordPress/Tests/Arrays/ArrayDeclarationSpacingUnitTest.2.inc b/WordPress/Tests/Arrays/ArrayDeclarationSpacingUnitTest.2.inc index 34ea62060f..da24a06279 100644 --- a/WordPress/Tests/Arrays/ArrayDeclarationSpacingUnitTest.2.inc +++ b/WordPress/Tests/Arrays/ArrayDeclarationSpacingUnitTest.2.inc @@ -107,3 +107,10 @@ $bad = [ // Don't confuse list arrows with array arrows. $okay = [ $item1, [ 'key1' => $a, 'key2' => $b ] = $array, $item3 ]; + +// phpcs:set WordPress.Arrays.ArrayDeclarationSpacing allow_single_item_single_line_explicit_key_arrays false + +$bad = [ 'key' => 'value' ]; // Bad. +$bad = [ 'key1' => 'value1', 'key2' => 'value2' ]; // Bad. + +// phpcs:set WordPress.Arrays.ArrayDeclarationSpacing allow_single_item_single_line_explicit_key_arrays true diff --git a/WordPress/Tests/Arrays/ArrayDeclarationSpacingUnitTest.2.inc.fixed b/WordPress/Tests/Arrays/ArrayDeclarationSpacingUnitTest.2.inc.fixed index c4b03f73cc..3480020aa9 100644 --- a/WordPress/Tests/Arrays/ArrayDeclarationSpacingUnitTest.2.inc.fixed +++ b/WordPress/Tests/Arrays/ArrayDeclarationSpacingUnitTest.2.inc.fixed @@ -163,3 +163,15 @@ $bad = [ // Don't confuse list arrows with array arrows. $okay = [ $item1, [ 'key1' => $a, 'key2' => $b ] = $array, $item3 ]; + +// phpcs:set WordPress.Arrays.ArrayDeclarationSpacing allow_single_item_single_line_explicit_key_arrays false + +$bad = [ +'key' => 'value' +]; // Bad. +$bad = [ +'key1' => 'value1', +'key2' => 'value2' +]; // Bad. + +// phpcs:set WordPress.Arrays.ArrayDeclarationSpacing allow_single_item_single_line_explicit_key_arrays true diff --git a/WordPress/Tests/Arrays/ArrayDeclarationSpacingUnitTest.php b/WordPress/Tests/Arrays/ArrayDeclarationSpacingUnitTest.php index 9a289959e6..6a46292970 100644 --- a/WordPress/Tests/Arrays/ArrayDeclarationSpacingUnitTest.php +++ b/WordPress/Tests/Arrays/ArrayDeclarationSpacingUnitTest.php @@ -51,29 +51,33 @@ public function getErrorList( $testFile = '' ) { 62 => 1, 63 => 1, 75 => 1, + 87 => 1, + 88 => 1, ); // Short arrays. case 'ArrayDeclarationSpacingUnitTest.2.inc': return array( - 9 => 4, - 13 => 2, - 15 => 1, - 19 => 1, - 22 => 1, - 25 => 1, - 44 => 1, - 45 => 1, - 48 => 1, - 49 => 1, - 52 => 2, - 54 => 1, - 57 => 1, - 58 => 1, - 62 => 1, - 63 => 1, - 75 => 1, - 97 => 1, + 9 => 4, + 13 => 2, + 15 => 1, + 19 => 1, + 22 => 1, + 25 => 1, + 44 => 1, + 45 => 1, + 48 => 1, + 49 => 1, + 52 => 2, + 54 => 1, + 57 => 1, + 58 => 1, + 62 => 1, + 63 => 1, + 75 => 1, + 97 => 1, + 113 => 1, + 114 => 1, ); default: From b4ca43ced75f95177a93c732584fe1b834f2b93d Mon Sep 17 00:00:00 2001 From: Rodrigo Primo Date: Tue, 24 Feb 2026 13:10:53 -0300 Subject: [PATCH 057/108] WP/AlternativeFunctions: add XML documentation (#2687) Co-authored-by: pamprn09 Co-authored-by: bhubbard Co-authored-by: Pamela Ribeiro --- .../Docs/WP/AlternativeFunctionsStandard.xml | 25 +++++++++++++++++++ 1 file changed, 25 insertions(+) create mode 100644 WordPress/Docs/WP/AlternativeFunctionsStandard.xml diff --git a/WordPress/Docs/WP/AlternativeFunctionsStandard.xml b/WordPress/Docs/WP/AlternativeFunctionsStandard.xml new file mode 100644 index 0000000000..bf2f5f3a95 --- /dev/null +++ b/WordPress/Docs/WP/AlternativeFunctionsStandard.xml @@ -0,0 +1,25 @@ + + + + + + + + wp_rand( 1, 100 ); + ]]> + + + mt_rand( 1, 100 ); + ]]> + + + From 1f0b1a7a9050e03f5d1717996be6d9ef10368cec Mon Sep 17 00:00:00 2001 From: Rodrigo Primo Date: Wed, 25 Feb 2026 10:03:19 -0300 Subject: [PATCH 058/108] ContextHelper::is_in_function_call(): add basic tests (#2626) * ContextHelper::is_in_function_call(): add basic tests * Since there were no previous tests for utility methods, it was also necessary to modify the test structure to enable running utility tests. They are different from the sniff tests as they extend `UtilityMethodTestCase` and don't need to run via `./vendor/squizlabs/php_codesniffer/tests/AllTests.php`. * Refactor runIsInFunctionCallTest() to receive a PARAMETER_MAP entry directly * Pass the resolved parameter values and expected match boolean to the helper method instead of a string key. This removes the need to look up the values inside the helper. Without the `$expectedKey`, I ended up removing the custom assertion message. That shouldn't be a problem as the default PHPUnit output already includes the information that was added in the custom assertion message. --------- Co-authored-by: Juliette <663378+jrfnl@users.noreply.github.com> --- .../IsInFunctionCallUnitTest.inc | 78 ++++ .../IsInFunctionCallUnitTest.php | 436 ++++++++++++++++++ .../Security/NonceVerificationUnitTest.1.inc | 2 +- .../Security/NonceVerificationUnitTest.php | 1 - 4 files changed, 515 insertions(+), 2 deletions(-) create mode 100644 WordPress/Tests/Helpers/ContextHelper/IsInFunctionCallUnitTest.inc create mode 100644 WordPress/Tests/Helpers/ContextHelper/IsInFunctionCallUnitTest.php diff --git a/WordPress/Tests/Helpers/ContextHelper/IsInFunctionCallUnitTest.inc b/WordPress/Tests/Helpers/ContextHelper/IsInFunctionCallUnitTest.inc new file mode 100644 index 0000000000..8a20dade8a --- /dev/null +++ b/WordPress/Tests/Helpers/ContextHelper/IsInFunctionCallUnitTest.inc @@ -0,0 +1,78 @@ +valid_function1( /* testObjectMethodInsideCall */ array() ); +/* testNullsafeObjectMethod */ +$obj?->valid_function1( /* testNullsafeObjectMethodInsideCall */ [ 1, 2, 3 ] ); + +/* + * The below should only be recognized as inside a function call to one of the valid functions when `$allow_nested` + * is `true`. + */ + +/* testNestedOuter */ +valid_function1( another_function( /* testNestedOuterInsideCall */ 'param' ) ); +/* testNestedMultipleLevels */ +valid_function1( middle_function( inner_function( /* testNestedMultipleLevelsInsideCall */ 999 ) ) ); + +/* + * The below should only be recognized as inside a function call to one of the valid functions when both + * `$global_function` is `false` and `$allow_nested` is `true`. + */ + +MyNamespace\/* testNestedBothNamespacedOuter */ valid_function1( + MyNamespace\other_function( + /* testNestedBothNamespacedOuterInsideCall */ 'value' . $var + ) +); + +/* + * Safeguard to ensure parentheses in other parameters within the same function call don't confuse the method. + */ +/* testOtherParamsWithParentheses */ +valid_function1( + array( 'key1' => 'value1' ), + /* testOtherParamsWithParenthesesInsideCall */ $var, + function() { return 'closure value'; } +); diff --git a/WordPress/Tests/Helpers/ContextHelper/IsInFunctionCallUnitTest.php b/WordPress/Tests/Helpers/ContextHelper/IsInFunctionCallUnitTest.php new file mode 100644 index 0000000000..be9a4d10e6 --- /dev/null +++ b/WordPress/Tests/Helpers/ContextHelper/IsInFunctionCallUnitTest.php @@ -0,0 +1,436 @@ +> + */ + private const PARAMETER_MAP = array( + self::GLOBAL_ONLY => array( + 'global_function' => true, + 'allow_nested' => false, + ), + self::GLOBAL_NESTED => array( + 'global_function' => true, + 'allow_nested' => true, + ), + self::NON_GLOBAL_ONLY => array( + 'global_function' => false, + 'allow_nested' => false, + ), + self::NON_GLOBAL_NESTED => array( + 'global_function' => false, + 'allow_nested' => true, + ), + ); + + /** + * Expected results: when a test case uses this constant, `is_in_function_call()` should return `false` regardless + * of the value of the parameters `$global_function` and `$allow_nested`. + * + * @var array + */ + private const EXPECT_NO_MATCH = array( + self::GLOBAL_ONLY => false, + self::GLOBAL_NESTED => false, + self::NON_GLOBAL_ONLY => false, + self::NON_GLOBAL_NESTED => false, + ); + + /** + * Expected results: when a test case uses this constant, `is_in_function_call()` should return the function name + * pointer regardless of the value of the parameters `$global_function` and `$allow_nested`. + * + * @var array + */ + private const EXPECT_ALWAYS_MATCH = array( + self::GLOBAL_ONLY => true, + self::GLOBAL_NESTED => true, + self::NON_GLOBAL_ONLY => true, + self::NON_GLOBAL_NESTED => true, + ); + + /** + * Expected results: when a test case uses this constant, `is_in_function_call()` should return the function name + * pointer when `$global_function` is `false`, and `false` when `$global_function` is `true`. + * + * @var array + */ + private const EXPECT_NON_GLOBAL_ONLY = array( + self::GLOBAL_ONLY => false, + self::GLOBAL_NESTED => false, + self::NON_GLOBAL_ONLY => true, + self::NON_GLOBAL_NESTED => true, + ); + + /** + * Expected results: when a test case uses this constant, `is_in_function_call()` should return the function name + * pointer when `$allow_nested` is `true`, and `false` when `$allow_nested` is `false`. + * + * @var array + */ + private const EXPECT_NESTED_ONLY = array( + self::GLOBAL_ONLY => false, + self::GLOBAL_NESTED => true, + self::NON_GLOBAL_ONLY => false, + self::NON_GLOBAL_NESTED => true, + ); + + /** + * Expected results: when a test case uses this constant, `is_in_function_call()` should return the function name + * pointer when both `$global_function` is `false` and `$allow_nested` is `true`, and `false` otherwise. + * + * @var array + */ + private const EXPECT_NON_GLOBAL_NESTED_ONLY = array( + self::GLOBAL_ONLY => false, + self::GLOBAL_NESTED => false, + self::NON_GLOBAL_ONLY => false, + self::NON_GLOBAL_NESTED => true, + ); + + /** + * Test is_in_function_call() when $valid_functions is an empty array. + * + * @return void + */ + public function testIsInFunctionCallShouldReturnFalseWhenEmptyValidFunctions() { + $insideFunctionPtr = $this->getTargetToken( '/* testLowercaseNameInsideCall */', \T_VARIABLE ); + $result = ContextHelper::is_in_function_call( + self::$phpcsFile, + $insideFunctionPtr, + array() + ); + + $this->assertFalse( $result ); + } + + /** + * Test to document that is_in_function_call() does not match when $valid_functions keys are not lowercase. + * + * @return void + */ + public function testIsInFunctionCallShouldReturnFalseWhenValidFunctionsKeysAreNotLowercase() { + $insideFunctionPtr = $this->getTargetToken( '/* testLowercaseNameInsideCall */', \T_VARIABLE ); + $result = ContextHelper::is_in_function_call( + self::$phpcsFile, + $insideFunctionPtr, + array( + 'Valid_Function1' => true, + ) + ); + + $this->assertFalse( $result ); + } + + /** + * Test is_in_function_call() with specific parameters. + * + * @dataProvider dataIsInFunctionCallWithDefaultParams + * @dataProvider dataIsInFunctionCallWithGlobalFalse + * @dataProvider dataIsInFunctionCallWithNestedTrue + * @dataProvider dataIsInFunctionCallWithGlobalFalseNestedTrue + * + * @param string $marker The comment which prefaces the target token. + * @param int|string $tokenType The token type to search for. + * @param bool $shouldMatch Whether `is_in_function_call()` should find a match. + * @param string|null $expectedMarker The comment which prefaces the expected function name + * in the test file (if a match is expected). + * @param array $params The is_in_function_call() parameter values. + * + * @return void + */ + public function testIsInFunctionCall( $marker, $tokenType, $shouldMatch, $expectedMarker, $params ) { + $insideFunctionPtr = $this->getTargetToken( $marker, $tokenType ); + $result = ContextHelper::is_in_function_call( + self::$phpcsFile, + $insideFunctionPtr, + array( + 'valid_function1' => true, + 'valid_function2' => true, + ), + $params['global_function'], + $params['allow_nested'] + ); + + $expected = false; + if ( true === $shouldMatch ) { + $expected = $this->getTargetToken( $expectedMarker, \T_STRING ); + } + + $this->assertSame( $expected, $result ); + } + + /** + * Data provider. + * + * @see testIsInFunctionCall() + * + * @return array|null>> + */ + public static function dataIsInFunctionCallWithDefaultParams() { + $data = self::dataIsInFunctionCall(); + $newData = array(); + + // Update 'shouldMatch' and 'params' to only contain the values relevant for this test. + foreach ( $data as $key => $dataset ) { + $key = self::GLOBAL_ONLY . ' | ' . $key; + $newData[ $key ] = $dataset; + $newData[ $key ]['shouldMatch'] = $dataset['shouldMatch'][ self::GLOBAL_ONLY ]; + $newData[ $key ]['params'] = self::PARAMETER_MAP[ self::GLOBAL_ONLY ]; + } + + return $newData; + } + + /** + * Data provider. + * + * @see testIsInFunctionCall() + * + * @return array|null>> + */ + public static function dataIsInFunctionCallWithGlobalFalse() { + $data = self::dataIsInFunctionCall(); + $newData = array(); + + // Update 'shouldMatch' and 'params' to only contain the values relevant for this test. + foreach ( $data as $key => $dataset ) { + $key = self::NON_GLOBAL_ONLY . ' | ' . $key; + $newData[ $key ] = $dataset; + $newData[ $key ]['shouldMatch'] = $dataset['shouldMatch'][ self::NON_GLOBAL_ONLY ]; + $newData[ $key ]['params'] = self::PARAMETER_MAP[ self::NON_GLOBAL_ONLY ]; + } + + return $newData; + } + + /** + * Data provider. + * + * @see testIsInFunctionCall() + * + * @return array|null>> + */ + public static function dataIsInFunctionCallWithNestedTrue() { + $data = self::dataIsInFunctionCall(); + $newData = array(); + + // Update 'shouldMatch' and 'params' to only contain the values relevant for this test. + foreach ( $data as $key => $dataset ) { + $key = self::GLOBAL_NESTED . ' | ' . $key; + $newData[ $key ] = $dataset; + $newData[ $key ]['shouldMatch'] = $dataset['shouldMatch'][ self::GLOBAL_NESTED ]; + $newData[ $key ]['params'] = self::PARAMETER_MAP[ self::GLOBAL_NESTED ]; + } + + return $newData; + } + + /** + * Data provider. + * + * @see testIsInFunctionCall() + * + * @return array|null>> + */ + public static function dataIsInFunctionCallWithGlobalFalseNestedTrue() { + $data = self::dataIsInFunctionCall(); + $newData = array(); + + // Update 'shouldMatch' and 'params' to only contain the values relevant for this test. + foreach ( $data as $key => $dataset ) { + $key = self::NON_GLOBAL_NESTED . ' | ' . $key; + $newData[ $key ] = $dataset; + $newData[ $key ]['shouldMatch'] = $dataset['shouldMatch'][ self::NON_GLOBAL_NESTED ]; + $newData[ $key ]['params'] = self::PARAMETER_MAP[ self::NON_GLOBAL_NESTED ]; + } + + return $newData; + } + + /** + * Base data provider. Wrapper data providers adapt this data for their specific parameter combination. + * + * @return array>> + */ + public static function dataIsInFunctionCall() { + $data = array( + // Cases that should never match (regardless of parameters). + 'plain_assignment' => array( + 'marker' => '/* testPlainAssignment */', + 'tokenType' => \T_CONSTANT_ENCAPSED_STRING, + 'shouldMatch' => self::EXPECT_NO_MATCH, + ), + 'different_function' => array( + 'marker' => '/* testDifferentFunction */', + 'tokenType' => \T_LNUMBER, + 'shouldMatch' => self::EXPECT_NO_MATCH, + ), + 'inside_closure' => array( + 'marker' => '/* testInsideClosure */', + 'tokenType' => \T_VARIABLE, + 'shouldMatch' => self::EXPECT_NO_MATCH, + ), + 'variable_function' => array( + 'marker' => '/* testVariableFunction */', + 'tokenType' => \T_VARIABLE, + 'shouldMatch' => self::EXPECT_NO_MATCH, + ), + 'if_condition' => array( + 'marker' => '/* testIfCondition */', + 'tokenType' => \T_TRUE, + 'shouldMatch' => self::EXPECT_NO_MATCH, + ), + + // Cases that should always match (regardless of parameters). + 'lowercase_name' => array( + 'marker' => '/* testLowercaseNameInsideCall */', + 'tokenType' => \T_VARIABLE, + 'shouldMatch' => self::EXPECT_ALWAYS_MATCH, + 'expectedMarker' => '/* testLowercaseName */', + ), + 'uppercase_name' => array( + 'marker' => '/* testUppercaseNameInsideCall */', + 'tokenType' => \T_CONSTANT_ENCAPSED_STRING, + 'shouldMatch' => self::EXPECT_ALWAYS_MATCH, + 'expectedMarker' => '/* testUppercaseName */', + ), + 'fully_qualified' => array( + 'marker' => '/* testFullyQualifiedInsideCall */', + 'tokenType' => \T_LNUMBER, + 'shouldMatch' => self::EXPECT_ALWAYS_MATCH, + 'expectedMarker' => '/* testFullyQualified */', + ), + 'nested_inner' => array( + 'marker' => '/* testNestedInnerInsideCall */', + 'tokenType' => \T_TRUE, + 'shouldMatch' => self::EXPECT_ALWAYS_MATCH, + 'expectedMarker' => '/* testNestedInner */', + ), + + // Cases that match only when `$global_function` is `false`. + 'namespaced_function' => array( + 'marker' => '/* testNamespacedFunctionInsideCall */', + 'tokenType' => \T_STRING, + 'shouldMatch' => self::EXPECT_NON_GLOBAL_ONLY, + 'expectedMarker' => '/* testNamespacedFunction */', + ), + 'fully_qualified_namespaced_function' => array( + 'marker' => '/* testFullyQualifiedNamespacedFunctionInsideCall */', + 'tokenType' => \T_NULL, + 'shouldMatch' => self::EXPECT_NON_GLOBAL_ONLY, + 'expectedMarker' => '/* testFullyQualifiedNamespacedFunction */', + ), + 'namespace_relative_function' => array( + 'marker' => '/* testNamespaceRelativeFunctionInsideCall */', + 'tokenType' => \T_DNUMBER, + 'shouldMatch' => self::EXPECT_NON_GLOBAL_ONLY, + 'expectedMarker' => '/* testNamespaceRelativeFunction */', + ), + 'static_method' => array( + 'marker' => '/* testStaticMethodInsideCall */', + 'tokenType' => \T_CONSTANT_ENCAPSED_STRING, + 'shouldMatch' => self::EXPECT_NON_GLOBAL_ONLY, + 'expectedMarker' => '/* testStaticMethod */', + ), + 'object_method' => array( + 'marker' => '/* testObjectMethodInsideCall */', + 'tokenType' => \T_ARRAY, + 'shouldMatch' => self::EXPECT_NON_GLOBAL_ONLY, + 'expectedMarker' => '/* testObjectMethod */', + ), + 'nullsafe_object_method' => array( + 'marker' => '/* testNullsafeObjectMethodInsideCall */', + 'tokenType' => \T_OPEN_SHORT_ARRAY, + 'shouldMatch' => self::EXPECT_NON_GLOBAL_ONLY, + 'expectedMarker' => '/* testNullsafeObjectMethod */', + ), + + // Cases that match only when `$allow_nested` is `true`. + 'nested_outer' => array( + 'marker' => '/* testNestedOuterInsideCall */', + 'tokenType' => \T_CONSTANT_ENCAPSED_STRING, + 'shouldMatch' => self::EXPECT_NESTED_ONLY, + 'expectedMarker' => '/* testNestedOuter */', + ), + 'nested_multiple_levels' => array( + 'marker' => '/* testNestedMultipleLevelsInsideCall */', + 'tokenType' => \T_LNUMBER, + 'shouldMatch' => self::EXPECT_NESTED_ONLY, + 'expectedMarker' => '/* testNestedMultipleLevels */', + ), + 'nested_both_namespaced_outer' => array( + 'marker' => '/* testNestedBothNamespacedOuterInsideCall */', + 'tokenType' => \T_STRING_CONCAT, + 'shouldMatch' => self::EXPECT_NON_GLOBAL_NESTED_ONLY, + 'expectedMarker' => '/* testNestedBothNamespacedOuter */', + ), + + // Safeguard: parentheses in other parameters should not confuse the method. + 'other_params_with_parentheses' => array( + 'marker' => '/* testOtherParamsWithParenthesesInsideCall */', + 'tokenType' => \T_VARIABLE, + 'shouldMatch' => self::EXPECT_ALWAYS_MATCH, + 'expectedMarker' => '/* testOtherParamsWithParentheses */', + ), + ); + + foreach ( $data as $key => $dataset ) { + if ( isset( $dataset['expectedMarker'] ) === false ) { + $data[ $key ]['expectedMarker'] = null; + } + } + + return $data; + } +} diff --git a/WordPress/Tests/Security/NonceVerificationUnitTest.1.inc b/WordPress/Tests/Security/NonceVerificationUnitTest.1.inc index fc688e09de..605caeb8c0 100644 --- a/WordPress/Tests/Security/NonceVerificationUnitTest.1.inc +++ b/WordPress/Tests/Security/NonceVerificationUnitTest.1.inc @@ -291,7 +291,7 @@ function function_containing_nested_closure() { }; } -// Tests specifically for the ContextHelper::is_in_function_call(). + function disallow_custom_unslash_before_noncecheck_via_method() { $var = MyClass::stripslashes_from_strings_only( $_POST['foo'] ); // Bad. wp_verify_nonce( $var ); diff --git a/WordPress/Tests/Security/NonceVerificationUnitTest.php b/WordPress/Tests/Security/NonceVerificationUnitTest.php index ea76b5a4b0..7920859d6d 100644 --- a/WordPress/Tests/Security/NonceVerificationUnitTest.php +++ b/WordPress/Tests/Security/NonceVerificationUnitTest.php @@ -18,7 +18,6 @@ * @since 0.13.0 Class name changed: this class is now namespaced. * @since 1.0.0 This sniff has been moved from the `CSRF` category to the `Security` category. * - * @covers \WordPressCS\WordPress\Helpers\ContextHelper::is_in_function_call * @covers \WordPressCS\WordPress\Helpers\ContextHelper::is_in_type_test * @covers \WordPressCS\WordPress\Helpers\ContextHelper::is_in_isset_or_empty * @covers \WordPressCS\WordPress\Helpers\ContextHelper::is_in_array_comparison From c580c6c606a58606efa4bb1541d665f7cd5fd5c4 Mon Sep 17 00:00:00 2001 From: Rodrigo Primo Date: Wed, 25 Feb 2026 10:04:17 -0300 Subject: [PATCH 059/108] PHP/NoSilencedErrors: add XML documentation (#2694) * Add documentation for WordPress.PHP.NoSilencedErrors --------- Co-authored-by: gogdzl Co-authored-by: Juliette <663378+jrfnl@users.noreply.github.com> --- .../Docs/PHP/NoSilencedErrorsStandard.xml | 29 +++++++++++++++++++ 1 file changed, 29 insertions(+) create mode 100644 WordPress/Docs/PHP/NoSilencedErrorsStandard.xml diff --git a/WordPress/Docs/PHP/NoSilencedErrorsStandard.xml b/WordPress/Docs/PHP/NoSilencedErrorsStandard.xml new file mode 100644 index 0000000000..9db8f6e942 --- /dev/null +++ b/WordPress/Docs/PHP/NoSilencedErrorsStandard.xml @@ -0,0 +1,29 @@ + + + + + + + + strtr( $str, $replace_pairs ); + ]]> + + + @strtr( $str, $replace_pairs ); + ]]> + + + From 2de7e5d9e675178886aad2e18b1ec4acee5d2268 Mon Sep 17 00:00:00 2001 From: Rodrigo Primo Date: Wed, 25 Feb 2026 11:55:02 -0300 Subject: [PATCH 060/108] ContextHelper::is_in_function_call(): handle $valid_functions keys case-insensitively The method already lowercased the token content before matching, but required callers to pass $valid_functions keys in lowercase. This normalizes the keys internally using array_change_key_case(), so callers no longer need to worry about passing lowercase function names. --- WordPress/Helpers/ContextHelper.php | 7 ++-- .../IsInFunctionCallUnitTest.php | 34 ++++++++++++++++--- 2 files changed, 35 insertions(+), 6 deletions(-) diff --git a/WordPress/Helpers/ContextHelper.php b/WordPress/Helpers/ContextHelper.php index b90006fde0..1da3286715 100644 --- a/WordPress/Helpers/ContextHelper.php +++ b/WordPress/Helpers/ContextHelper.php @@ -199,8 +199,9 @@ public static function is_token_namespaced( File $phpcsFile, $stackPtr ) { * @param \PHP_CodeSniffer\Files\File $phpcsFile The file being scanned. * @param int $stackPtr The index of the token in the stack. * @param array $valid_functions List of valid function names. - * Note: The keys to this array should be the function names - * in lowercase. Values are irrelevant. + * Note: The keys to this array should be the function names. + * Values are irrelevant. The matching of function names found in + * the code against the keys in this array is done case-insensitively. * @param bool $global_function Optional. Whether to make sure that the function call is * to a global function. If `false`, calls to methods, be it static * `Class::method()` or via an object `$obj->method()`, and @@ -217,6 +218,8 @@ public static function is_token_namespaced( File $phpcsFile, $stackPtr ) { * @return int|bool Stack pointer to the function call T_STRING token or false otherwise. */ public static function is_in_function_call( File $phpcsFile, $stackPtr, array $valid_functions, $global_function = true, $allow_nested = false ) { + $valid_functions = array_change_key_case( $valid_functions, \CASE_LOWER ); + $tokens = $phpcsFile->getTokens(); if ( ! isset( $tokens[ $stackPtr ]['nested_parenthesis'] ) ) { return false; diff --git a/WordPress/Tests/Helpers/ContextHelper/IsInFunctionCallUnitTest.php b/WordPress/Tests/Helpers/ContextHelper/IsInFunctionCallUnitTest.php index be9a4d10e6..c80188631b 100644 --- a/WordPress/Tests/Helpers/ContextHelper/IsInFunctionCallUnitTest.php +++ b/WordPress/Tests/Helpers/ContextHelper/IsInFunctionCallUnitTest.php @@ -155,21 +155,47 @@ public function testIsInFunctionCallShouldReturnFalseWhenEmptyValidFunctions() { } /** - * Test to document that is_in_function_call() does not match when $valid_functions keys are not lowercase. + * Test that is_in_function_call() matches regardless of the case of $valid_functions keys. + * + * @dataProvider dataIsInFunctionCallShouldMatchRegardlessOfValidFunctionsKeyCase + * + * @param string $functionName The function name to use as a key in $valid_functions. * * @return void */ - public function testIsInFunctionCallShouldReturnFalseWhenValidFunctionsKeysAreNotLowercase() { + public function testIsInFunctionCallShouldMatchRegardlessOfValidFunctionsKeyCase( $functionName ) { $insideFunctionPtr = $this->getTargetToken( '/* testLowercaseNameInsideCall */', \T_VARIABLE ); + $expected = $this->getTargetToken( '/* testLowercaseName */', \T_STRING ); $result = ContextHelper::is_in_function_call( self::$phpcsFile, $insideFunctionPtr, array( - 'Valid_Function1' => true, + $functionName => true, ) ); - $this->assertFalse( $result ); + $this->assertSame( $expected, $result ); + } + + /** + * Data provider. + * + * @see testIsInFunctionCallShouldMatchRegardlessOfValidFunctionsKeyCase() + * + * @return array> + */ + public static function dataIsInFunctionCallShouldMatchRegardlessOfValidFunctionsKeyCase() { + return array( + 'lowercase key' => array( + 'functionName' => 'valid_function1', + ), + 'uppercase key' => array( + 'functionName' => 'VALID_FUNCTION1', + ), + 'mixed case key' => array( + 'functionName' => 'Valid_Function1', + ), + ); } /** From 6c040eabdd4beb07c094a93523033331b36a9294 Mon Sep 17 00:00:00 2001 From: Rodrigo Primo Date: Wed, 4 Mar 2026 22:58:31 -0300 Subject: [PATCH 061/108] PHP/RestrictedPHPFunctions: add XML documentation (#2693) * Add documentation for WordPress.PHP.RestrictedPHPFunctions * Rework XML documentation for WordPress.PHP.RestrictedPHPFunctions Some of these changes were suggested during the review of PR 2491, and others were decided while working on the new PR: - Make the standard description generic instead of mentioning create_function() specifically, following the pattern used by other docs like DeprecatedFunctionsStandard.xml. - Use "must not" instead of "should not" since the sniff produces an error. - Simplify the code examples by removing the add_action() wrapper. - Add tags to the valid code example. * Explain why in the standard description Following the suggestion in PR 2687, this commit improves the standard description to explain why these functions must not be used. The phrasing is kept generic instead of mentioning create_function() specifically, since the sniff name suggests it could be extended with more functions in the future. Co-authored-by: gogdzl --- .../PHP/RestrictedPHPFunctionsStandard.xml | 34 +++++++++++++++++++ 1 file changed, 34 insertions(+) create mode 100644 WordPress/Docs/PHP/RestrictedPHPFunctionsStandard.xml diff --git a/WordPress/Docs/PHP/RestrictedPHPFunctionsStandard.xml b/WordPress/Docs/PHP/RestrictedPHPFunctionsStandard.xml new file mode 100644 index 0000000000..bebbd86b19 --- /dev/null +++ b/WordPress/Docs/PHP/RestrictedPHPFunctionsStandard.xml @@ -0,0 +1,34 @@ + + + + + + + + function () { + return foo( 'bar' ); + } +); + ]]> + + + create_function( + '', + 'return foo( "bar" );' + ) +); + ]]> + + + From 747be3e3d6ac7228121ec3a2e77a28ee9ba84a98 Mon Sep 17 00:00:00 2001 From: Rodrigo Primo Date: Thu, 5 Mar 2026 04:17:32 -0300 Subject: [PATCH 062/108] DB/DirectDatabaseQuery: add XML documentation (#2697) * docs: add documentation for WordPress.DB.DirectDatabaseQuery - Rewrite standard descriptions to explain why each rule exists. - Add tags to highlight key parts in code examples. - Use realistic code examples. - Replace second caching example with a write + cache invalidation pattern. - Wrap caching examples in functions, as the sniff always generates a NoCaching warning if the caching code is not inside a function. - Remove dbDelta() recommendation from SchemaChange section. I believe the original intent of the rule is to discourage schema changes and not suggest dbDelta() is used. - Remove SchemaChange code comparison (no valid alternative). --------- Co-authored-by: Jay McPartland Co-authored-by: Juliette <663378+jrfnl@users.noreply.github.com> --- .../Docs/DB/DirectDatabaseQueryStandard.xml | 124 ++++++++++++++++++ 1 file changed, 124 insertions(+) create mode 100644 WordPress/Docs/DB/DirectDatabaseQueryStandard.xml diff --git a/WordPress/Docs/DB/DirectDatabaseQueryStandard.xml b/WordPress/Docs/DB/DirectDatabaseQueryStandard.xml new file mode 100644 index 0000000000..d727c064e8 --- /dev/null +++ b/WordPress/Docs/DB/DirectDatabaseQueryStandard.xml @@ -0,0 +1,124 @@ + + + + + + + + WP_Query( + array( + 'post_type' => 'page', + ) +); + ]]> + + + $wpdb->get_results( + $wpdb->prepare( + "SELECT * FROM %i + WHERE post_type = %s", + $wpdb->posts, + 'page' + ) +); + ]]> + + + + + + + + wp_cache_get( $key ); + + if ( false !== $cached ) { + return $cached; + } + + $results = $wpdb->get_col( + "SELECT ID FROM $wpdb->posts + WHERE post_status = 'draft'" + ); + + wp_cache_set( $key, $results ); + + return $results; +} + ]]> + + + get_col( + "SELECT ID FROM $wpdb->posts + WHERE post_status = 'draft'" + ); + + return $results; +} + ]]> + + + + + update( + $wpdb->posts, + array( 'post_title' => $title ), + array( 'ID' => $post_id ) + ); + + clean_post_cache( $post_id ); +} + ]]> + + + update( + $wpdb->posts, + array( 'post_title' => $title ), + array( 'ID' => $post_id ) + ); +} + ]]> + + + + + + + + + + + query( + "ALTER TABLE {$wpdb->posts} + ADD COLUMN rating int" +); + ]]> + + + From 1dbd8ad908be0e53c99d002129ca0c32cc57e287 Mon Sep 17 00:00:00 2001 From: Rodrigo Primo Date: Thu, 5 Mar 2026 10:55:03 -0300 Subject: [PATCH 063/108] Merge pull request #2699 from rodrigoprimo/docs-slow-db-query DB/SlowDBQuery: add XML documentation --- WordPress/Docs/DB/SlowDBQueryStandard.xml | 33 +++++++++++++++++++++++ 1 file changed, 33 insertions(+) create mode 100644 WordPress/Docs/DB/SlowDBQueryStandard.xml diff --git a/WordPress/Docs/DB/SlowDBQueryStandard.xml b/WordPress/Docs/DB/SlowDBQueryStandard.xml new file mode 100644 index 0000000000..230c7fafb6 --- /dev/null +++ b/WordPress/Docs/DB/SlowDBQueryStandard.xml @@ -0,0 +1,33 @@ + + + + + + + + 'post', +) ); + + +$args = 'post_type=post&orderby=date'; + ]]> + + + meta_key' => 'color', + 'meta_value' => 'blue', +) ); + +$args = 'post_type=post&meta_key=featured'; + ]]> + + + From 16c0a751a83dab779576e89a4ac75f59d5ebbcb4 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 5 Mar 2026 22:14:12 +0000 Subject: [PATCH 064/108] 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.43.5 to 1.44.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/57b11c6b7e54c402ccd9cda953f1072ec4f78e33...631208b7aac2daa8b707f55e7331f9112b0e062d) --- updated-dependencies: - dependency-name: crate-ci/typos dependency-version: 1.44.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 e4a0367ee7..f934355a39 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@57b11c6b7e54c402ccd9cda953f1072ec4f78e33" # v1.43.5 + uses: "crate-ci/typos@631208b7aac2daa8b707f55e7331f9112b0e062d" # v1.44.0 From e0ebae2dba5fedac3460704a370122cb80051c61 Mon Sep 17 00:00:00 2001 From: Rodrigo Primo Date: Thu, 19 Mar 2026 10:51:22 -0300 Subject: [PATCH 065/108] WP/EnqueuedResourceParameters: add tests for namespaced names (#2675) I'm adding two different tests for fully qualified global function calls to cover all the global functions that are referenced directly in the `EnqueuedResourceParametersSniff::process_parameters` method. --- .../WP/EnqueuedResourceParametersUnitTest.1.inc | 12 +++++++++++- .../Tests/WP/EnqueuedResourceParametersUnitTest.php | 2 ++ 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/WordPress/Tests/WP/EnqueuedResourceParametersUnitTest.1.inc b/WordPress/Tests/WP/EnqueuedResourceParametersUnitTest.1.inc index 03157513e4..8592a34121 100644 --- a/WordPress/Tests/WP/EnqueuedResourceParametersUnitTest.1.inc +++ b/WordPress/Tests/WP/EnqueuedResourceParametersUnitTest.1.inc @@ -42,7 +42,7 @@ wp_register_style( 'script-name', 'https://example.com/someScript.js', false, '1 wp_register_style( 'script-name', 'https://example.com/someScript.js' ); // Warning - missing $ver. wp_enqueue_style( 'script-name', 'https://example.com/someScript.js', false, '1.0.0'); // OK. -wp_enqueue_style( 'script-name', 'https://example.com/someScript.js' ); // Warning - missing $ver. +WP_ENQUEUE_style( 'script-name', 'https://example.com/someScript.js' ); // Warning - missing $ver. wp_register_script( 'someScript-js' ); // OK. wp_enqueue_script( 'someScript-js' ); // OK. @@ -108,3 +108,13 @@ wp_register_script( 'someScript-js', 'https://example.com/someScript.js' , array 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. + +/* + * Safeguard correct handling of all types of namespaced function calls. + */ +\wp_enqueue_script( 'script-name', 'https://example.com/someScript.js', false, '1.1.0' ); // Warning - missing $in_footer. +\wp_REGISTER_script( 'someScript-js', 'https://example.com/someScript.js' , array( 'jquery' ), '1.1.0' ); // Warning - missing $in_footer. +MyNamespace\wp_register_style( 'style-name', 'https://example.com/style.css' ); // Ok. +\MyNamespace\wp_enqueue_style( 'style-name', 'https://example.com/style.css' ); // Ok. +namespace\wp_register_script( 'someScript-js', 'https://example.com/someScript.js' , array( 'jquery' ), '1.1.0' ); // The sniff should start flagging this once it can resolve relative namespaces (once it does, it should be "Warning - missing $in_footer"). +namespace\Sub\wp_enqueue_style( 'style-name', 'https://example.com/style.css' ); // Ok. diff --git a/WordPress/Tests/WP/EnqueuedResourceParametersUnitTest.php b/WordPress/Tests/WP/EnqueuedResourceParametersUnitTest.php index eaa719c19b..a1dd90b4f5 100644 --- a/WordPress/Tests/WP/EnqueuedResourceParametersUnitTest.php +++ b/WordPress/Tests/WP/EnqueuedResourceParametersUnitTest.php @@ -82,6 +82,8 @@ public function getWarningList( $testFile = '' ) { 100 => 1, 107 => 1, 108 => 1, + 115 => 1, + 116 => 1, ); default: From 5a9ae23627cfa43f4a01115d1307aee0395efbb8 Mon Sep 17 00:00:00 2001 From: Rodrigo Primo Date: Thu, 19 Mar 2026 13:32:09 -0300 Subject: [PATCH 066/108] Apply suggestion from PR review --- WordPress/Tests/WP/DeprecatedFunctionsUnitTest.1.inc | 1 - WordPress/Tests/WP/DeprecatedFunctionsUnitTest.2.inc | 5 +++++ WordPress/Tests/WP/DeprecatedFunctionsUnitTest.php | 7 ++++--- 3 files changed, 9 insertions(+), 4 deletions(-) diff --git a/WordPress/Tests/WP/DeprecatedFunctionsUnitTest.1.inc b/WordPress/Tests/WP/DeprecatedFunctionsUnitTest.1.inc index 291eefdc78..57a44658ef 100644 --- a/WordPress/Tests/WP/DeprecatedFunctionsUnitTest.1.inc +++ b/WordPress/Tests/WP/DeprecatedFunctionsUnitTest.1.inc @@ -444,4 +444,3 @@ wp_add_editor_classic_theme_styles(); /* ============ WP 6.9 ============ */ seems_utf8(); wp_print_auto_sizes_contain_css_fix(); -wp_PRINT_auto_SIZES_contain_CSS_fix(); diff --git a/WordPress/Tests/WP/DeprecatedFunctionsUnitTest.2.inc b/WordPress/Tests/WP/DeprecatedFunctionsUnitTest.2.inc index 87418bf766..654c7d4ff4 100644 --- a/WordPress/Tests/WP/DeprecatedFunctionsUnitTest.2.inc +++ b/WordPress/Tests/WP/DeprecatedFunctionsUnitTest.2.inc @@ -9,3 +9,8 @@ MyNamespace\permalink_link(); \MyNamespace\get_postdata(); namespace\create_user(); // The sniff should start flagging this once it can resolve relative namespaces. namespace\Sub\user_can_edit_post(); + +/* + * Safeguard correct handling of non-standard case function call. + */ +wp_ADMIN_bar_HEADER(); diff --git a/WordPress/Tests/WP/DeprecatedFunctionsUnitTest.php b/WordPress/Tests/WP/DeprecatedFunctionsUnitTest.php index 2d75be123c..4e36fa091b 100644 --- a/WordPress/Tests/WP/DeprecatedFunctionsUnitTest.php +++ b/WordPress/Tests/WP/DeprecatedFunctionsUnitTest.php @@ -92,8 +92,9 @@ public function getErrorList( $testFile = '' ) { case 'DeprecatedFunctionsUnitTest.2.inc': return array( - 6 => 1, - 7 => 1, + 6 => 1, + 7 => 1, + 16 => 1, ); default: @@ -112,7 +113,7 @@ public function getWarningList( $testFile = '' ) { switch ( $testFile ) { case 'DeprecatedFunctionsUnitTest.1.inc': $start_line = 430; - $end_line = 447; + $end_line = 446; $warnings = array_fill( $start_line, ( ( $end_line - $start_line ) + 1 ), 1 ); // Unset the lines related to version comments. From 70223650506053b6ad76b558c5b367c04ca490a6 Mon Sep 17 00:00:00 2001 From: Rodrigo Primo Date: Wed, 5 Nov 2025 14:16:36 -0300 Subject: [PATCH 067/108] Security/ValidatedSanitizedInput: add tests for namespaced names --- .../ValidatedSanitizedInputUnitTest.1.inc | 124 ++++++++++++++++++ .../ValidatedSanitizedInputUnitTest.php | 29 ++++ 2 files changed, 153 insertions(+) diff --git a/WordPress/Tests/Security/ValidatedSanitizedInputUnitTest.1.inc b/WordPress/Tests/Security/ValidatedSanitizedInputUnitTest.1.inc index cc4edc147a..e19f439248 100644 --- a/WordPress/Tests/Security/ValidatedSanitizedInputUnitTest.1.inc +++ b/WordPress/Tests/Security/ValidatedSanitizedInputUnitTest.1.inc @@ -500,3 +500,127 @@ function test_in_match_condition_is_regarded_as_comparison() { }; } } + +/* + * Safeguard correct handling of qualified and relative namespaced calls to array key exists functions. + * Non-namespaced and fully qualified calls are already covered above. + */ +function test_namespaced_array_key_exists() { + if ( MyNamespace\array_key_exists( 'key_exists1', $_POST ) ) { + $id = (int) $_POST['key_exists1']; // Bad. + } + if ( namespace\key_exists( 'key_exists2', $_POST ) ) { + $id = (int) $_POST['key_exists2']; // Bad. Note: This should NOT be flagged in the future once the sniff is able to resolve relative namespaces. + } + if ( namespace\Sub\array_key_exists( 'key_exists3', $_POST ) ) { + $id = (int) $_POST['key_exists3']; // Bad. + } +} + +/* + * Safeguard correct handling of all types of namespaced calls to type test functions. + */ +function test_namespaced_type_test_functions() { + if ( isset( $_POST['type_test1'] ) && \is_int( $_POST['type_test1'] ) ) {} // OK. + if ( isset( $_POST['type_test2'] ) && MyNamespace\is_string( $_POST['type_test2'] ) ) {} // Bad. + if ( isset( $_POST['type_test3'] ) && \MyNamespace\is_array( $_POST['type_test3'] ) ) {} // Bad. + if ( isset( $_POST['type_test4'] ) && namespace\is_numeric( $_POST['type_test4'] ) ) {} // Bad. Note: This should NOT be flagged in the future once the sniff is able to resolve relative namespaces. + if ( isset( $_POST['type_test5'] ) && namespace\Sub\is_bool( $_POST['type_test5'] ) ) {} // Bad. +} + +/* + * Safeguard correct handling of all types of namespaced calls to array comparison functions. + */ +function test_namespaced_array_comparison_functions() { + if ( isset( $_POST['array_cmp1'] ) && \in_array( $_POST['array_cmp1'], $my_array, true ) ) {} // OK. + if ( isset( $_POST['array_cmp2'] ) && MyNamespace\array_search( $_POST['array_cmp2'], $my_array, true ) ) {} // Bad. + if ( isset( $_POST['array_cmp3'] ) && \MyNamespace\array_keys( $my_array, $_POST['array_cmp3'] ) ) {} // Bad. + if ( isset( $_POST['array_cmp4'] ) && namespace\in_array( $_POST['array_cmp4'], $my_array, true ) ) {} // Bad. Note: This should NOT be flagged in the future once the sniff is able to resolve relative namespaces. + if ( isset( $_POST['array_cmp5'] ) && namespace\Sub\array_search( $_POST['array_cmp5'], $my_array, true ) ) {} // Bad. +} + +/* + * Safeguard correct handling of all types of namespaced calls to unslashing functions. + * + * Note: The "Bad" test cases below are false negatives. They should trigger 2 errors (MissingUnslash + + * InputNotSanitized), not 1 (MissingUnslash). This problem only affects PHPCS 3.x and does not happen in PHPCS 4.x. It + * will be addressed in https://github.com/WordPress/WordPress-Coding-Standards/issues/2665. + */ +function test_namespaced_unslashing_functions() { + if ( isset( $_POST['unslash1'] ) ) { + $text = sanitize_text_field( \wp_unslash( $_POST['unslash1'] ) ); // OK. + } + if ( isset( $_POST['unslash2'] ) ) { + $text = sanitize_text_field( MyNamespace\stripslashes_deep( $_POST['unslash2'] ) ); // Bad. + } + if ( isset( $_POST['unslash3'] ) ) { + $text = sanitize_text_field( \MyNamespace\stripslashes_from_strings_only( $_POST['unslash3'] ) ); // Bad. + } + if ( isset( $_POST['unslash4'] ) ) { + $text = sanitize_text_field( namespace\wp_unslash( $_POST['unslash4'] ) ); // Bad. Note: This should NOT be flagged in the future once the sniff is able to resolve relative namespaces. + } + if ( isset( $_POST['unslash5'] ) ) { + $text = sanitize_text_field( namespace\Sub\stripslashes_deep( $_POST['unslash5'] ) ); // Bad. + } +} + +/* + * Safeguard correct handling of all types of namespaced calls to array walking functions. + */ +function test_namespaced_array_walking_functions() { + if ( isset( $_POST['array_walk1'] ) ) { + $data = \array_map( 'sanitize_text_field', \wp_unslash( $_POST['array_walk1'] ) ); // OK. + } + if ( isset( $_POST['array_walk2'] ) ) { + $data = MyNamespace\map_deep( wp_unslash( $_POST['array_walk2'] ), 'sanitize_text_field' ); // Bad. + } + if ( isset( $_POST['array_walk3'] ) ) { + $data = \MyNamespace\array_map( 'sanitize_text_field', \wp_unslash( $_POST['array_walk3'] ) ); // Bad. + } + if ( isset( $_POST['array_walk4'] ) ) { + $data = namespace\map_deep( wp_unslash( $_POST['array_walk4'] ), 'sanitize_text_field' ); // Bad. Note: This should NOT be flagged in the future once the sniff is able to resolve relative namespaces. + } + if ( isset( $_POST['array_walk5'] ) ) { + $data = namespace\Sub\array_map( 'sanitize_text_field', \wp_unslash( $_POST['array_walk5'] ) ); // Bad. + } +} + +/* + * Safeguard correct handling of fully qualified and relative namespaced calls to sanitizing functions. + * Qualified calls are already covered above. + */ +function test_namespaced_sanitizing_functions() { + if ( isset( $_POST['sanitize1'] ) ) { + $text = \sanitize_text_field( wp_unslash( $_POST['sanitize1'] ) ); // OK. + } + if ( isset( $_POST['sanitize2'] ) ) { + $email = \MyNamespace\sanitize_email( wp_unslash( $_POST['sanitize2'] ) ); // Bad. + } + if ( isset( $_POST['sanitize3'] ) ) { + $url = namespace\sanitize_url( wp_unslash( $_POST['sanitize3'] ) ); // Bad. Note: This should NOT be flagged in the future once the sniff is able to resolve relative namespaces. + } + if ( isset( $_POST['sanitize4'] ) ) { + $title = namespace\Sub\sanitize_title( wp_unslash( $_POST['sanitize4'] ) ); // Bad. + } +} + +/* + * Safeguard correct handling of all types of namespaced calls to unslashing + sanitizing functions. + */ +function test_namespaced_unslashing_sanitizing_functions() { + if ( isset( $_POST['unslash_sanitize1'] ) ) { + $id = \absint( $_POST['unslash_sanitize1'] ); // OK. + } + if ( isset( $_POST['unslash_sanitize2'] ) ) { + $is_active = MyNamespace\boolval( $_POST['unslash_sanitize2'] ); // Bad. + } + if ( isset( $_POST['unslash_sanitize3'] ) ) { + $id = \MyNamespace\intval( $_POST['unslash_sanitize3'] ); // Bad. + } + if ( isset( $_POST['unslash_sanitize4'] ) ) { + $price = namespace\floatval( $_POST['unslash_sanitize4'] ); // Bad. Note: This should NOT be flagged in the future once the sniff is able to resolve relative namespaces. + } + if ( isset( $_POST['unslash_sanitize5'] ) ) { + $key = namespace\Sub\sanitize_key( $_POST['unslash_sanitize5'] ); // Bad. + } +} diff --git a/WordPress/Tests/Security/ValidatedSanitizedInputUnitTest.php b/WordPress/Tests/Security/ValidatedSanitizedInputUnitTest.php index 065162c2a8..a5428b1560 100644 --- a/WordPress/Tests/Security/ValidatedSanitizedInputUnitTest.php +++ b/WordPress/Tests/Security/ValidatedSanitizedInputUnitTest.php @@ -114,6 +114,35 @@ public function getErrorList( $testFile = '' ) { 497 => 1, 498 => 1, 499 => 3, + 510 => 1, + 513 => 1, + 516 => 1, + 525 => 2, + 526 => 2, + 527 => 2, + 528 => 2, + 536 => 2, + 537 => 2, + 538 => 2, + 539 => 2, + + // The error counts below differ depending on whether running PHPCS 3.x or PHPCS 4.x. See the comment in the test case file. + 554 => 1, + 557 => 1, + 560 => 1, + 563 => 1, + + 575 => 1, + 578 => 1, + 581 => 1, + 584 => 1, + 597 => 1, + 600 => 1, + 603 => 1, + 615 => 2, + 618 => 2, + 621 => 2, + 624 => 2, ); case 'ValidatedSanitizedInputUnitTest.2.inc': From a36706e4ccadcc428f6cf98daf102fec3c7ccad9 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 20 Mar 2026 22:13:34 +0000 Subject: [PATCH 068/108] GH Actions: Bump the action-runners group with 2 updates Bumps the action-runners group with 2 updates: [shivammathur/setup-php](https://github.com/shivammathur/setup-php) and [codecov/codecov-action](https://github.com/codecov/codecov-action). Updates `shivammathur/setup-php` from 2.36.0 to 2.37.0 - [Release notes](https://github.com/shivammathur/setup-php/releases) - [Commits](https://github.com/shivammathur/setup-php/compare/44454db4f0199b8b9685a5d763dc37cbf79108e1...accd6127cb78bee3e8082180cb391013d204ef9f) Updates `codecov/codecov-action` from 5.5.2 to 5.5.3 - [Release notes](https://github.com/codecov/codecov-action/releases) - [Changelog](https://github.com/codecov/codecov-action/blob/main/CHANGELOG.md) - [Commits](https://github.com/codecov/codecov-action/compare/671740ac38dd9b0130fbe1cec585b89eea48d3de...1af58845a975a7985b0beb0cbe6fbbb71a41dbad) --- updated-dependencies: - dependency-name: shivammathur/setup-php dependency-version: 2.37.0 dependency-type: direct:production update-type: version-update:semver-minor dependency-group: action-runners - dependency-name: codecov/codecov-action dependency-version: 5.5.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 | 6 +++--- .github/workflows/quicktest.yml | 4 ++-- .github/workflows/unit-tests.yml | 4 ++-- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/.github/workflows/basic-qa.yml b/.github/workflows/basic-qa.yml index f934355a39..b201396fcd 100644 --- a/.github/workflows/basic-qa.yml +++ b/.github/workflows/basic-qa.yml @@ -31,7 +31,7 @@ jobs: persist-credentials: false - name: Setup PHP - uses: shivammathur/setup-php@44454db4f0199b8b9685a5d763dc37cbf79108e1 # 2.36.0 + uses: shivammathur/setup-php@accd6127cb78bee3e8082180cb391013d204ef9f # 2.37.0 with: php-version: 'latest' coverage: none @@ -162,7 +162,7 @@ jobs: persist-credentials: false - name: Set up PHP - uses: shivammathur/setup-php@44454db4f0199b8b9685a5d763dc37cbf79108e1 # 2.36.0 + uses: shivammathur/setup-php@accd6127cb78bee3e8082180cb391013d204ef9f # 2.37.0 with: php-version: ${{ matrix.php }} # Allow for PHP deprecation notices. @@ -245,7 +245,7 @@ jobs: persist-credentials: false - name: Install PHP - uses: shivammathur/setup-php@44454db4f0199b8b9685a5d763dc37cbf79108e1 # 2.36.0 + uses: shivammathur/setup-php@accd6127cb78bee3e8082180cb391013d204ef9f # 2.37.0 with: php-version: 'latest' coverage: none diff --git a/.github/workflows/quicktest.yml b/.github/workflows/quicktest.yml index 90de6af732..9a3129e84a 100644 --- a/.github/workflows/quicktest.yml +++ b/.github/workflows/quicktest.yml @@ -35,7 +35,7 @@ jobs: persist-credentials: false - name: Set up PHP - uses: shivammathur/setup-php@44454db4f0199b8b9685a5d763dc37cbf79108e1 # 2.36.0 + uses: shivammathur/setup-php@accd6127cb78bee3e8082180cb391013d204ef9f # 2.37.0 with: php-version: ${{ matrix.php }} # With stable PHPCS dependencies, allow for PHP deprecation notices. @@ -75,7 +75,7 @@ jobs: - name: Send coverage report to Codecov if: ${{ success() && github.event.repository.fork == false && github.ref_name == 'develop' }} - uses: codecov/codecov-action@671740ac38dd9b0130fbe1cec585b89eea48d3de # v5.5.2 + uses: codecov/codecov-action@1af58845a975a7985b0beb0cbe6fbbb71a41dbad # v5.5.3 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 6d9c44dee5..d672827c44 100644 --- a/.github/workflows/unit-tests.yml +++ b/.github/workflows/unit-tests.yml @@ -90,7 +90,7 @@ jobs: fi - name: Set up PHP - uses: shivammathur/setup-php@44454db4f0199b8b9685a5d763dc37cbf79108e1 # 2.36.0 + uses: shivammathur/setup-php@accd6127cb78bee3e8082180cb391013d204ef9f # 2.37.0 with: php-version: ${{ matrix.php }} ini-values: ${{ steps.set_ini.outputs.PHP_INI }} @@ -137,7 +137,7 @@ jobs: - name: Send coverage report to Codecov if: ${{ success() && matrix.coverage == true && github.event.repository.fork == false }} - uses: codecov/codecov-action@671740ac38dd9b0130fbe1cec585b89eea48d3de # v5.5.2 + uses: codecov/codecov-action@1af58845a975a7985b0beb0cbe6fbbb71a41dbad # v5.5.3 with: files: ./build/logs/clover.xml fail_ci_if_error: true From 4c23d00f88e9e0e3004f6845b709599e71a07454 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 20 Mar 2026 22:13:41 +0000 Subject: [PATCH 069/108] GH Actions: Bump ramsey/composer-install from 3.1.1 to 4.0.0 Bumps [ramsey/composer-install](https://github.com/ramsey/composer-install) from 3.1.1 to 4.0.0. - [Release notes](https://github.com/ramsey/composer-install/releases) - [Commits](https://github.com/ramsey/composer-install/compare/3cf229dc2919194e9e36783941438d17239e8520...65e4f84970763564f46a70b8a54b90d033b3bdda) --- updated-dependencies: - dependency-name: ramsey/composer-install dependency-version: 4.0.0 dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] --- .github/workflows/basic-qa.yml | 6 +++--- .github/workflows/quicktest.yml | 2 +- .github/workflows/unit-tests.yml | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/.github/workflows/basic-qa.yml b/.github/workflows/basic-qa.yml index f934355a39..8c0eadaafc 100644 --- a/.github/workflows/basic-qa.yml +++ b/.github/workflows/basic-qa.yml @@ -50,7 +50,7 @@ jobs: phpcsstandards/phpcsextra:"${{ env.EXTRA_DEV }}" - name: Install Composer dependencies - uses: ramsey/composer-install@3cf229dc2919194e9e36783941438d17239e8520 # 3.1.1 + uses: ramsey/composer-install@65e4f84970763564f46a70b8a54b90d033b3bdda # 4.0.0 with: # Bust the cache at least once a month - output format: YYYY-MM. custom-cache-suffix: $(date -u "+%Y-%m") @@ -182,7 +182,7 @@ jobs: run: composer config --unset lock - name: Install Composer dependencies - uses: ramsey/composer-install@3cf229dc2919194e9e36783941438d17239e8520 # 3.1.1 + uses: ramsey/composer-install@65e4f84970763564f46a70b8a54b90d033b3bdda # 4.0.0 with: composer-options: --no-dev # Bust the cache at least once a month - output format: YYYY-MM. @@ -255,7 +255,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@3cf229dc2919194e9e36783941438d17239e8520" # 3.1.1 + uses: "ramsey/composer-install@65e4f84970763564f46a70b8a54b90d033b3bdda" # 4.0.0 with: # Bust the cache at least once a month - output format: YYYY-MM. custom-cache-suffix: $(date -u "+%Y-%m") diff --git a/.github/workflows/quicktest.yml b/.github/workflows/quicktest.yml index 90de6af732..eb3514fc34 100644 --- a/.github/workflows/quicktest.yml +++ b/.github/workflows/quicktest.yml @@ -48,7 +48,7 @@ jobs: run: composer config --unset lock - name: Install Composer dependencies - uses: ramsey/composer-install@3cf229dc2919194e9e36783941438d17239e8520 # 3.1.1 + uses: ramsey/composer-install@65e4f84970763564f46a70b8a54b90d033b3bdda # 4.0.0 with: # Bust the cache at least once a month - output format: YYYY-MM. custom-cache-suffix: $(date -u "+%Y-%m") diff --git a/.github/workflows/unit-tests.yml b/.github/workflows/unit-tests.yml index 6d9c44dee5..8479e7897e 100644 --- a/.github/workflows/unit-tests.yml +++ b/.github/workflows/unit-tests.yml @@ -110,7 +110,7 @@ jobs: run: composer config --unset lock - name: Install Composer dependencies - uses: ramsey/composer-install@3cf229dc2919194e9e36783941438d17239e8520 # 3.1.1 + uses: ramsey/composer-install@65e4f84970763564f46a70b8a54b90d033b3bdda # 4.0.0 with: # Bust the cache at least once a month - output format: YYYY-MM. custom-cache-suffix: $(date -u "+%Y-%m") From ea5ca81e666859949812f5bebe66ad0be31dcf2e Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sun, 5 Apr 2026 22:12:38 +0000 Subject: [PATCH 070/108] GH Actions: Bump codecov/codecov-action from 5.5.3 to 6.0.0 Bumps [codecov/codecov-action](https://github.com/codecov/codecov-action) from 5.5.3 to 6.0.0. - [Release notes](https://github.com/codecov/codecov-action/releases) - [Changelog](https://github.com/codecov/codecov-action/blob/main/CHANGELOG.md) - [Commits](https://github.com/codecov/codecov-action/compare/1af58845a975a7985b0beb0cbe6fbbb71a41dbad...57e3a136b779b570ffcdbf80b3bdc90e7fab3de2) --- updated-dependencies: - dependency-name: codecov/codecov-action dependency-version: 6.0.0 dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] --- .github/workflows/quicktest.yml | 2 +- .github/workflows/unit-tests.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/quicktest.yml b/.github/workflows/quicktest.yml index f9febdd7d5..e587e77918 100644 --- a/.github/workflows/quicktest.yml +++ b/.github/workflows/quicktest.yml @@ -75,7 +75,7 @@ jobs: - name: Send coverage report to Codecov if: ${{ success() && github.event.repository.fork == false && github.ref_name == 'develop' }} - uses: codecov/codecov-action@1af58845a975a7985b0beb0cbe6fbbb71a41dbad # v5.5.3 + uses: codecov/codecov-action@57e3a136b779b570ffcdbf80b3bdc90e7fab3de2 # v6.0.0 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 2dedee376d..3e54a726eb 100644 --- a/.github/workflows/unit-tests.yml +++ b/.github/workflows/unit-tests.yml @@ -137,7 +137,7 @@ jobs: - name: Send coverage report to Codecov if: ${{ success() && matrix.coverage == true && github.event.repository.fork == false }} - uses: codecov/codecov-action@1af58845a975a7985b0beb0cbe6fbbb71a41dbad # v5.5.3 + uses: codecov/codecov-action@57e3a136b779b570ffcdbf80b3bdc90e7fab3de2 # v6.0.0 with: files: ./build/logs/clover.xml fail_ci_if_error: true From 5196e8683358d41f8751f9485e2699b2ec5c02d3 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 21 Apr 2026 08:00:44 +0200 Subject: [PATCH 071/108] GH Actions: Bump crate-ci/typos from 1.44.0 to 1.45.0 in the action-runners group (#2717) * 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.44.0 to 1.45.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/631208b7aac2daa8b707f55e7331f9112b0e062d...02ea592e44b3a53c302f697cddca7641cd051c3d) --- updated-dependencies: - dependency-name: crate-ci/typos dependency-version: 1.45.0 dependency-type: direct:production update-type: version-update:semver-minor dependency-group: action-runners ... Signed-off-by: dependabot[bot] * Typos config: add PHP `is_writeable` function as valid --------- Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: jrfnl --- .github/workflows/basic-qa.yml | 2 +- _typos.toml | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/basic-qa.yml b/.github/workflows/basic-qa.yml index bf4cecde32..3d3b7453ff 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@631208b7aac2daa8b707f55e7331f9112b0e062d" # v1.44.0 + uses: "crate-ci/typos@02ea592e44b3a53c302f697cddca7641cd051c3d" # v1.45.0 diff --git a/_typos.toml b/_typos.toml index 5cc842866c..c632b5ff33 100644 --- a/_typos.toml +++ b/_typos.toml @@ -19,6 +19,7 @@ extend-ignore-identifiers-re = [ # These are search targets for sniffs, can't be helped. 'avail_post_stati', 'url_is_accessable_via_ssl', + 'is_writeable', ] [default.extend-words] From 273ae339d76ee1aa9142eae83bad5811cf488500 Mon Sep 17 00:00:00 2001 From: Rodrigo Primo Date: Thu, 23 Apr 2026 19:00:20 +0530 Subject: [PATCH 072/108] UnslashingFunctionsHelper::is_unslashing_function(): add tests (#2715) --- .../IsUnslashingFunctionUnitTest.php | 64 +++++++++++++++++++ 1 file changed, 64 insertions(+) create mode 100644 WordPress/Tests/Helpers/UnslashingFunctionsHelper/IsUnslashingFunctionUnitTest.php diff --git a/WordPress/Tests/Helpers/UnslashingFunctionsHelper/IsUnslashingFunctionUnitTest.php b/WordPress/Tests/Helpers/UnslashingFunctionsHelper/IsUnslashingFunctionUnitTest.php new file mode 100644 index 0000000000..c797cb2443 --- /dev/null +++ b/WordPress/Tests/Helpers/UnslashingFunctionsHelper/IsUnslashingFunctionUnitTest.php @@ -0,0 +1,64 @@ +assertSame( + $expectedResult, + UnslashingFunctionsHelper::is_unslashing_function( $functionName ) + ); + } + + /** + * Data provider. + * + * @see testIsUnslashingFunction() + * + * @return array> + */ + public static function dataIsUnslashingFunction() { + return array( + 'lowercase_name' => array( + 'functionName' => 'wp_unslash', + 'expectedResult' => true, + ), + 'mixedcase_name' => array( + 'functionName' => 'sTrIpSlAsHeS_DeEp', + 'expectedResult' => true, + ), + 'not_an_unslashing_function' => array( + 'functionName' => 'stripslashes', + 'expectedResult' => false, + ), + ); + } +} From b40d9bd81465411666860257d40993e9d79c53a2 Mon Sep 17 00:00:00 2001 From: Rodrigo Primo Date: Thu, 23 Apr 2026 19:28:18 +0530 Subject: [PATCH 073/108] FormattingFunctionsHelper::is_formatting_function(): add tests (#2713) --- .../IsFormattingFunctionUnitTest.php | 64 +++++++++++++++++++ 1 file changed, 64 insertions(+) create mode 100644 WordPress/Tests/Helpers/FormattingFunctionsHelper/IsFormattingFunctionUnitTest.php diff --git a/WordPress/Tests/Helpers/FormattingFunctionsHelper/IsFormattingFunctionUnitTest.php b/WordPress/Tests/Helpers/FormattingFunctionsHelper/IsFormattingFunctionUnitTest.php new file mode 100644 index 0000000000..e567d0f7c3 --- /dev/null +++ b/WordPress/Tests/Helpers/FormattingFunctionsHelper/IsFormattingFunctionUnitTest.php @@ -0,0 +1,64 @@ +assertSame( + $expectedResult, + FormattingFunctionsHelper::is_formatting_function( $functionName ) + ); + } + + /** + * Data provider. + * + * @see testIsFormattingFunction() + * + * @return array> + */ + public static function dataIsFormattingFunction() { + return array( + 'lowercase_name' => array( + 'functionName' => 'sprintf', + 'expectedResult' => true, + ), + 'mixedcase_name' => array( + 'functionName' => 'iMpLoDe', + 'expectedResult' => true, + ), + 'not_a_formatting_function' => array( + 'functionName' => 'printf', + 'expectedResult' => false, + ), + ); + } +} From 2f89dc3d6a9fc09e98f8b739c350699630f1bf59 Mon Sep 17 00:00:00 2001 From: Rodrigo Primo Date: Thu, 16 Oct 2025 17:58:45 -0300 Subject: [PATCH 074/108] WP/DeprecatedParameters: add tests for namespaced names --- .../Tests/WP/DeprecatedParametersUnitTest.inc | 13 +++++++++++-- .../Tests/WP/DeprecatedParametersUnitTest.php | 15 +++++++++------ 2 files changed, 20 insertions(+), 8 deletions(-) diff --git a/WordPress/Tests/WP/DeprecatedParametersUnitTest.inc b/WordPress/Tests/WP/DeprecatedParametersUnitTest.inc index 40d309e71a..06a30cf56f 100644 --- a/WordPress/Tests/WP/DeprecatedParametersUnitTest.inc +++ b/WordPress/Tests/WP/DeprecatedParametersUnitTest.inc @@ -37,14 +37,23 @@ wp_install( user_name: '', deprecated: '', user_email: '', blog_title: '', is_pu // Error: Parameter is passed with incorrect default, unconventional order. wp_install( is_public: '', user_name: '', user_email: '', deprecated: 'should be empty', blog_title: '' ); +/* + * Safeguard correct handling of all types of namespaced function calls. + */ +\add_option( '', '', [] ); // Bad. +MyNamespace\get_blog_list( $foo, $bar, 'deprecated' ); // Ok. +\MyNamespace\get_wp_title_rss( 'deprecated' ); // Ok. +namespace\the_author( 'deprecated', 'deprecated' ); // The sniff should start flagging this once it can resolve relative namespaces. +namespace\Sub\wp_title_rss( 'deprecated' ); // Ok. + // All will give an ERROR. The functions are ordered alphabetically. _future_post_hook( 10, $post ); _load_remote_block_patterns( $value ); _wp_post_revision_fields( $foo, 'deprecated' ); add_option( '', '', [] ); -add_option( '', '', 1.23 ); -add_option( '', '', 10 ); +\Add_Option( '', '', 1.23 ); +ADD_OPTION( '', '', 10 ); add_option( '', '', false ); add_option( '', '', 'deprecated' ); comments_link( 'deprecated', 'deprecated' ); diff --git a/WordPress/Tests/WP/DeprecatedParametersUnitTest.php b/WordPress/Tests/WP/DeprecatedParametersUnitTest.php index 9f4d2d87d1..0b396055b1 100644 --- a/WordPress/Tests/WP/DeprecatedParametersUnitTest.php +++ b/WordPress/Tests/WP/DeprecatedParametersUnitTest.php @@ -27,8 +27,8 @@ final class DeprecatedParametersUnitTest extends AbstractSniffUnitTest { * @return array Key is the line number, value is the number of expected errors. */ public function getErrorList() { - $start_line = 42; - $end_line = 98; + $start_line = 51; + $end_line = 107; $errors = array_fill( $start_line, ( ( $end_line - $start_line ) + 1 ), 1 ); $errors[22] = 1; @@ -38,9 +38,12 @@ public function getErrorList() { // Named param. $errors[38] = 1; + // Fully qualified function call. + $errors[43] = 1; + // Override number of errors. - $errors[50] = 2; - $errors[76] = 2; + $errors[59] = 2; + $errors[85] = 2; return $errors; } @@ -52,8 +55,8 @@ public function getErrorList() { */ public function getWarningList() { return array( - 101 => 1, - 102 => 1, + 110 => 1, + 111 => 1, ); } } From 050c938047ce5a0cd0c590d0925cf3f965d77db4 Mon Sep 17 00:00:00 2001 From: Rodrigo Primo Date: Thu, 16 Oct 2025 17:59:35 -0300 Subject: [PATCH 075/108] WP/DeprecatedParameterValues: rename test case file Doing this to allow for additional testcase files. --- ...> DeprecatedParameterValuesUnitTest.1.inc} | 0 .../WP/DeprecatedParameterValuesUnitTest.php | 82 +++++++++++-------- 2 files changed, 49 insertions(+), 33 deletions(-) rename WordPress/Tests/WP/{DeprecatedParameterValuesUnitTest.inc => DeprecatedParameterValuesUnitTest.1.inc} (100%) diff --git a/WordPress/Tests/WP/DeprecatedParameterValuesUnitTest.inc b/WordPress/Tests/WP/DeprecatedParameterValuesUnitTest.1.inc similarity index 100% rename from WordPress/Tests/WP/DeprecatedParameterValuesUnitTest.inc rename to WordPress/Tests/WP/DeprecatedParameterValuesUnitTest.1.inc diff --git a/WordPress/Tests/WP/DeprecatedParameterValuesUnitTest.php b/WordPress/Tests/WP/DeprecatedParameterValuesUnitTest.php index c491b12a4d..2011793351 100644 --- a/WordPress/Tests/WP/DeprecatedParameterValuesUnitTest.php +++ b/WordPress/Tests/WP/DeprecatedParameterValuesUnitTest.php @@ -23,47 +23,63 @@ final class DeprecatedParameterValuesUnitTest 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( - 5 => 1, - 6 => 1, - 7 => 1, - 8 => 1, - 9 => 1, - 10 => 1, - 11 => 1, - 12 => 1, - 13 => 1, - 14 => 1, - 15 => 1, - 16 => 1, - 17 => 1, - 18 => 1, - 35 => 1, - 40 => 1, - 43 => 1, - 44 => 1, - 45 => 1, - 46 => 1, - 47 => 1, - 48 => 1, - 49 => 1, - 50 => 1, - 51 => 1, - ); + public function getErrorList( $testFile = '' ) { + switch ( $testFile ) { + case 'DeprecatedParameterValuesUnitTest.1.inc': + return array( + 5 => 1, + 6 => 1, + 7 => 1, + 8 => 1, + 9 => 1, + 10 => 1, + 11 => 1, + 12 => 1, + 13 => 1, + 14 => 1, + 15 => 1, + 16 => 1, + 17 => 1, + 18 => 1, + 35 => 1, + 40 => 1, + 43 => 1, + 44 => 1, + 45 => 1, + 46 => 1, + 47 => 1, + 48 => 1, + 49 => 1, + 50 => 1, + 51 => 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( - 55 => 1, - 56 => 1, - ); + public function getWarningList( $testFile = '' ) { + switch ( $testFile ) { + case 'DeprecatedParameterValuesUnitTest.1.inc': + return array( + 55 => 1, + 56 => 1, + ); + + default: + return array(); + } } } From c94a61473b42407f05c53a875ac348a773a433fe Mon Sep 17 00:00:00 2001 From: Rodrigo Primo Date: Thu, 16 Oct 2025 18:01:18 -0300 Subject: [PATCH 076/108] WP/DeprecatedParameterValues: move syntax error test to its own file --- .../Tests/WP/DeprecatedParameterValuesUnitTest.1.inc | 3 --- .../Tests/WP/DeprecatedParameterValuesUnitTest.2.inc | 8 ++++++++ 2 files changed, 8 insertions(+), 3 deletions(-) create mode 100644 WordPress/Tests/WP/DeprecatedParameterValuesUnitTest.2.inc diff --git a/WordPress/Tests/WP/DeprecatedParameterValuesUnitTest.1.inc b/WordPress/Tests/WP/DeprecatedParameterValuesUnitTest.1.inc index c2f75c8747..6c514cc36d 100644 --- a/WordPress/Tests/WP/DeprecatedParameterValuesUnitTest.1.inc +++ b/WordPress/Tests/WP/DeprecatedParameterValuesUnitTest.1.inc @@ -54,6 +54,3 @@ update_option(autoload: true, value: $value, option: 'blacklist_keys'); wp_get_typography_font_size_value( $preset, array() ); // OK. wp_get_typography_font_size_value( $preset, true ); // Error. wp_get_typography_font_size_value( $preset, false ); // Error. - -// Live coding/parse error. -get_bloginfo( show: /*to do*/, ); diff --git a/WordPress/Tests/WP/DeprecatedParameterValuesUnitTest.2.inc b/WordPress/Tests/WP/DeprecatedParameterValuesUnitTest.2.inc new file mode 100644 index 0000000000..b5923d40e4 --- /dev/null +++ b/WordPress/Tests/WP/DeprecatedParameterValuesUnitTest.2.inc @@ -0,0 +1,8 @@ + Date: Thu, 16 Oct 2025 18:31:39 -0300 Subject: [PATCH 077/108] WP/DeprecatedParameterValues: add tests for namespaced names --- .../WP/DeprecatedParameterValuesUnitTest.1.inc | 13 +++++++++++-- .../Tests/WP/DeprecatedParameterValuesUnitTest.php | 1 + 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/WordPress/Tests/WP/DeprecatedParameterValuesUnitTest.1.inc b/WordPress/Tests/WP/DeprecatedParameterValuesUnitTest.1.inc index 6c514cc36d..18a26a2b93 100644 --- a/WordPress/Tests/WP/DeprecatedParameterValuesUnitTest.1.inc +++ b/WordPress/Tests/WP/DeprecatedParameterValuesUnitTest.1.inc @@ -3,8 +3,8 @@ // All will give an ERROR. get_bloginfo( 'home' ); -get_bloginfo( 'siteurl' ); -get_bloginfo( "text_direction" ); +\GeT_bLoGiNfO( 'siteurl' ); +Get_Bloginfo( "text_direction" ); echo bloginfo( 'home' ); echo bloginfo( "siteurl" ); echo bloginfo( 'text_direction' ); @@ -54,3 +54,12 @@ update_option(autoload: true, value: $value, option: 'blacklist_keys'); wp_get_typography_font_size_value( $preset, array() ); // OK. wp_get_typography_font_size_value( $preset, true ); // Error. wp_get_typography_font_size_value( $preset, false ); // Error. + +/* + * Safeguard correct handling of all types of namespaced function calls. + */ +\get_bloginfo( 'home' ); // Bad. +MyNamespace\register_setting( 'privacy' ); // Ok. +\MyNamespace\unregister_setting( 'misc' ); // Ok. +namespace\get_option('blacklist_keys'); // The sniff should start flagging this once it can resolve relative namespaces. +namespace\Sub\add_option('comment_whitelist', $value); // Ok. diff --git a/WordPress/Tests/WP/DeprecatedParameterValuesUnitTest.php b/WordPress/Tests/WP/DeprecatedParameterValuesUnitTest.php index 2011793351..275191902e 100644 --- a/WordPress/Tests/WP/DeprecatedParameterValuesUnitTest.php +++ b/WordPress/Tests/WP/DeprecatedParameterValuesUnitTest.php @@ -56,6 +56,7 @@ public function getErrorList( $testFile = '' ) { 49 => 1, 50 => 1, 51 => 1, + 61 => 1, ); default: From ad1183f27fa05c715c8f004c04e989ebea5914bf Mon Sep 17 00:00:00 2001 From: Rodrigo Primo Date: Thu, 16 Oct 2025 18:31:58 -0300 Subject: [PATCH 078/108] WP/GetMetaSingle: add tests for namespaced names --- WordPress/Tests/WP/GetMetaSingleUnitTest.inc | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/WordPress/Tests/WP/GetMetaSingleUnitTest.inc b/WordPress/Tests/WP/GetMetaSingleUnitTest.inc index 54ea2fecc0..33aed6468d 100644 --- a/WordPress/Tests/WP/GetMetaSingleUnitTest.inc +++ b/WordPress/Tests/WP/GetMetaSingleUnitTest.inc @@ -31,7 +31,7 @@ $incorrect_but_ok = get_metadata( 'post' ); * These should all be flagged with a warning. */ $warning = \get_post_meta( $post_id, $meta_key ); -implode(', ', get_post_meta( $post_id, $meta_key )); +implode(', ', \GET_POST_META( $post_id, $meta_key )); if (get_post_meta( $post_id, key: $meta_key )) {} $warning = get_post_meta( $post_id, key: $meta_key, sinngle: true ); // Typo in parameter name. echo get_comment_meta( $comment_id, $meta_key ); @@ -46,3 +46,11 @@ $warning = get_metadata( ); $warning = get_metadata_raw( 'post', $post_id, $meta_key ); $warning = get_metadata_default( 'post', $post_id, $meta_key ); + +/* + * Safeguard correct handling of fully qualified and relative namespaced function calls (fully qualified global function + * call and partially qualified namespaced function call are already handled above). + */ +\MyNamespace\get_user_meta( $user_id, $meta_key ); +namespace\get_metadata( 'post', $post_id, $meta_key ); // The sniff should start flagging this once it can resolve relative namespaces. +namespace\Sub\get_comment_meta( $comment_id, $meta_key ); From eac44b4d0e7a06237f98ff50f018c5aeca9fbca4 Mon Sep 17 00:00:00 2001 From: Rodrigo Primo Date: Thu, 16 Oct 2025 18:35:44 -0300 Subject: [PATCH 079/108] WP/I18n: add tests for namespaced names I'm adding three different tests for fully qualified global function calls to cover all the global functions that are referenced directly in the `I18nSniff::process_matched_token()` method. --- WordPress/Tests/WP/I18nUnitTest.1.inc | 15 +++++++++++++-- WordPress/Tests/WP/I18nUnitTest.1.inc.fixed | 15 +++++++++++++-- WordPress/Tests/WP/I18nUnitTest.php | 3 +++ 3 files changed, 29 insertions(+), 4 deletions(-) diff --git a/WordPress/Tests/WP/I18nUnitTest.1.inc b/WordPress/Tests/WP/I18nUnitTest.1.inc index 6256e6d84a..3abf8ec3ba 100644 --- a/WordPress/Tests/WP/I18nUnitTest.1.inc +++ b/WordPress/Tests/WP/I18nUnitTest.1.inc @@ -47,7 +47,7 @@ _n( 'I have %d cat.', 'I have %d cats.', $number, 'my-slug' ); // OK. _n( 'I have %d cat.', 'I have %d cats.', $number, "illegal $string" ); // Bad. _n( 'I have %d cat.', 'I have %d cats.', $number, SOMETHING ); // Bad. -_n_noop( 'I have %d cat.', 'I have %d cats.' ); // Bad, no text domain. +_N_NOOP( 'I have %d cat.', 'I have %d cats.' ); // Bad, no text domain. _n_noop( 'I have %d cat.', 'I have %d cats.', 'my-slug' ); // OK. _n_noop( 'I have %d cat.', 'I have %d cats.', "illegal $string" ); // Bad. _n_noop( 'I have %d cat.', 'I have %d cats.', SOMETHING ); // Bad. @@ -75,7 +75,7 @@ __( 'foo', 'my-slug', 'too-many-args' ); // Bad. _x( 'string', 'context', 'my-slug', 'too-many-args' ); // Bad. _n( 'I have %d cat.', 'I have %d cats.', $number, 'my-slug', 'too-many-args' ); // Bad. _n_noop( 'I have %d cat.', 'I have %d cats.', 'my-slug', 'too-many-args' ); // Bad. -_nx_noop( 'I have %d cat.', 'I have %d cats.', 'Not really.', 'my-slug', 'too-many-args' ); // Bad. +\_Nx_Noop( 'I have %d cat.', 'I have %d cats.', 'Not really.', 'my-slug', 'too-many-args' ); // Bad. // Make sure that multi-line string literals are accepted. _nx( 'I have @@ -317,4 +317,15 @@ esc_html_e( 'foo', '' ); // Bad: text-domain can not be empty. // PHP 8.0+: safeguard handling of newly introduced placeholders. __( 'There are %1$h monkeys in the %H', 'my-slug' ); // Bad: multiple arguments should be numbered. +/* + * Safeguard correct handling of all types of namespaced function calls. + */ +\_( 'foo', 'my-slug' ); // Bad. +\translate( 'foo', 'my-slug' ); // Bad. +\translate_with_gettext_context( 'foo', 'bar', 'my-slug' ); // Bad. +MyNamespace\__( 'foo', 'my-slug' ); // Ok. +\MyNamespace\_e( 'foo', 'my-slug' ); // Ok. +namespace\esc_html_e( 'foo', '' ); // The sniff should start flagging this once it can resolve relative namespaces. +namespace\Sub\translate( 'foo', 'my-slug' ); // Ok. + // phpcs:enable WordPress.WP.I18n.MissingTranslatorsComment diff --git a/WordPress/Tests/WP/I18nUnitTest.1.inc.fixed b/WordPress/Tests/WP/I18nUnitTest.1.inc.fixed index b23e9b6192..ae6358abbf 100644 --- a/WordPress/Tests/WP/I18nUnitTest.1.inc.fixed +++ b/WordPress/Tests/WP/I18nUnitTest.1.inc.fixed @@ -47,7 +47,7 @@ _n( 'I have %d cat.', 'I have %d cats.', $number, 'my-slug' ); // OK. _n( 'I have %d cat.', 'I have %d cats.', $number, "illegal $string" ); // Bad. _n( 'I have %d cat.', 'I have %d cats.', $number, SOMETHING ); // Bad. -_n_noop( 'I have %d cat.', 'I have %d cats.' ); // Bad, no text domain. +_N_NOOP( 'I have %d cat.', 'I have %d cats.' ); // Bad, no text domain. _n_noop( 'I have %d cat.', 'I have %d cats.', 'my-slug' ); // OK. _n_noop( 'I have %d cat.', 'I have %d cats.', "illegal $string" ); // Bad. _n_noop( 'I have %d cat.', 'I have %d cats.', SOMETHING ); // Bad. @@ -75,7 +75,7 @@ __( 'foo', 'my-slug', 'too-many-args' ); // Bad. _x( 'string', 'context', 'my-slug', 'too-many-args' ); // Bad. _n( 'I have %d cat.', 'I have %d cats.', $number, 'my-slug', 'too-many-args' ); // Bad. _n_noop( 'I have %d cat.', 'I have %d cats.', 'my-slug', 'too-many-args' ); // Bad. -_nx_noop( 'I have %d cat.', 'I have %d cats.', 'Not really.', 'my-slug', 'too-many-args' ); // Bad. +\_Nx_Noop( 'I have %d cat.', 'I have %d cats.', 'Not really.', 'my-slug', 'too-many-args' ); // Bad. // Make sure that multi-line string literals are accepted. _nx( 'I have @@ -317,4 +317,15 @@ esc_html_e( 'foo', '' ); // Bad: text-domain can not be empty. // PHP 8.0+: safeguard handling of newly introduced placeholders. __( 'There are %1$h monkeys in the %H', 'my-slug' ); // Bad: multiple arguments should be numbered. +/* + * Safeguard correct handling of all types of namespaced function calls. + */ +\_( 'foo', 'my-slug' ); // Bad. +\translate( 'foo', 'my-slug' ); // Bad. +\translate_with_gettext_context( 'foo', 'bar', 'my-slug' ); // Bad. +MyNamespace\__( 'foo', 'my-slug' ); // Ok. +\MyNamespace\_e( 'foo', 'my-slug' ); // Ok. +namespace\esc_html_e( 'foo', '' ); // The sniff should start flagging this once it can resolve relative namespaces. +namespace\Sub\translate( 'foo', 'my-slug' ); // Ok. + // phpcs:enable WordPress.WP.I18n.MissingTranslatorsComment diff --git a/WordPress/Tests/WP/I18nUnitTest.php b/WordPress/Tests/WP/I18nUnitTest.php index 3834eb189f..20e7accaab 100644 --- a/WordPress/Tests/WP/I18nUnitTest.php +++ b/WordPress/Tests/WP/I18nUnitTest.php @@ -148,6 +148,7 @@ public function getErrorList( $testFile = '' ) { 311 => 1, 315 => 1, 318 => 1, + 323 => 1, ); case 'I18nUnitTest.2.inc': @@ -217,6 +218,8 @@ public function getWarningList( $testFile = '' ) { 300 => 1, 301 => 1, 302 => 1, + 324 => 1, + 325 => 1, ); case 'I18nUnitTest.2.inc': From 16a785eb26309975ab1938521de5839062eaac48 Mon Sep 17 00:00:00 2001 From: Rodrigo Primo Date: Mon, 27 Apr 2026 18:04:45 +0530 Subject: [PATCH 080/108] ContextHelper::is_in_isset_or_empty(): add basic tests (#2725) * ContextHelper::is_in_isset_or_empty(): add basic tests * Apply suggestions from code review * Apply more review suggestions --- .../IsInIssetOrEmptyUnitTest.inc | 34 ++++ .../IsInIssetOrEmptyUnitTest.php | 147 ++++++++++++++++++ .../Security/NonceVerificationUnitTest.php | 1 - 3 files changed, 181 insertions(+), 1 deletion(-) create mode 100644 WordPress/Tests/Helpers/ContextHelper/IsInIssetOrEmptyUnitTest.inc create mode 100644 WordPress/Tests/Helpers/ContextHelper/IsInIssetOrEmptyUnitTest.php diff --git a/WordPress/Tests/Helpers/ContextHelper/IsInIssetOrEmptyUnitTest.inc b/WordPress/Tests/Helpers/ContextHelper/IsInIssetOrEmptyUnitTest.inc new file mode 100644 index 0000000000..b3567121f8 --- /dev/null +++ b/WordPress/Tests/Helpers/ContextHelper/IsInIssetOrEmptyUnitTest.inc @@ -0,0 +1,34 @@ +array_key_exists( 'key', /* testObjectMethod */ $array ); +$obj?->key_exists( 'key', /* testNullsafeObjectMethod */ $array ); +MyClass::array_key_exists( 'key', /* testStaticMethod */ $array ); +key_exists( 'key', my_function( /* testNestedNonTargetFunctionCall */ $array ) ); +$obj->isset( /* testIssetObjectMethod */ $value ); +Foo::empty( /* testEmptyStaticMethod */ $value ); +MyNamespace\isset( /* testIssetNamespacedFunction */ $value ); + +/* + * The below should be recognized as being inside an isset/empty check. + */ + +isset( /* testIsset */ $value ); +empty( /* testEmpty */ $value ); +array_key_exists( 'key', /* testUnqualifiedFunction */ $array ); +Key_Exists( 'key', /* testMixedCaseFunction */ $array ); +\array_key_exists( 'key', /* testFullyQualifiedFunction */ $array ); +\KEY_EXISTS( 'key', /* testFullyQualifiedUpperCaseFunction */ $array ); +array_key_exists( array: /* testNamedParamReversedOrder */ $array, key: 'foo' ); +array_key_exists( 'key', \key_exists( 'key', /* testNestedValidFunctionCall */ $array ) ); diff --git a/WordPress/Tests/Helpers/ContextHelper/IsInIssetOrEmptyUnitTest.php b/WordPress/Tests/Helpers/ContextHelper/IsInIssetOrEmptyUnitTest.php new file mode 100644 index 0000000000..83bb739adb --- /dev/null +++ b/WordPress/Tests/Helpers/ContextHelper/IsInIssetOrEmptyUnitTest.php @@ -0,0 +1,147 @@ +getTargetToken( $testMarker, \T_VARIABLE ); + $result = ContextHelper::is_in_isset_or_empty( self::$phpcsFile, $stackPtr ); + + $this->assertSame( $expectedResult, $result ); + } + + /** + * Data provider. + * + * @see testIsInIssetOrEmpty() + * + * @return array> + */ + public static function dataIsInIssetOrEmpty() { + return array( + // Cases that should return false. + 'bare_variable' => array( + 'testMarker' => '/* testBareVariable */', + 'expectedResult' => false, + ), + 'other_function_call' => array( + 'testMarker' => '/* testOtherFunctionCall */', + 'expectedResult' => false, + ), + 'missing_array_param' => array( + 'testMarker' => '/* testMissingArrayParam */', + 'expectedResult' => false, + ), + 'key_param_not_array_param' => array( + 'testMarker' => '/* testKeyParamNotArrayParam */', + 'expectedResult' => false, + ), + 'partially_qualified_function' => array( + 'testMarker' => '/* testPartiallyQualifiedFunction */', + 'expectedResult' => false, + ), + 'fully_qualified_namespaced_function' => array( + 'testMarker' => '/* testFullyQualifiedNamespacedFunction */', + 'expectedResult' => false, + ), + 'namespace_relative_function' => array( + 'testMarker' => '/* testNamespaceRelativeFunction */', + 'expectedResult' => false, + ), + 'namespace_relative_sub_function' => array( + 'testMarker' => '/* testNamespaceRelativeSubFunction */', + 'expectedResult' => false, + ), + 'object_method' => array( + 'testMarker' => '/* testObjectMethod */', + 'expectedResult' => false, + ), + 'nullsafe_object_method' => array( + 'testMarker' => '/* testNullsafeObjectMethod */', + 'expectedResult' => false, + ), + 'static_method' => array( + 'testMarker' => '/* testStaticMethod */', + 'expectedResult' => false, + ), + 'nested_non_target_function_call' => array( + 'testMarker' => '/* testNestedNonTargetFunctionCall */', + 'expectedResult' => false, + ), + 'isset_object_method' => array( + 'testMarker' => '/* testIssetObjectMethod */', + 'expectedResult' => false, + ), + 'empty_static_method' => array( + 'testMarker' => '/* testEmptyStaticMethod */', + 'expectedResult' => false, + ), + 'isset_namespaced_function' => array( + 'testMarker' => '/* testIssetNamespacedFunction */', + 'expectedResult' => false, + ), + + // Cases that should return true. + 'isset' => array( + 'testMarker' => '/* testIsset */', + 'expectedResult' => true, + ), + 'empty' => array( + 'testMarker' => '/* testEmpty */', + 'expectedResult' => true, + ), + 'unqualified_function' => array( + 'testMarker' => '/* testUnqualifiedFunction */', + 'expectedResult' => true, + ), + 'mixed_case_function' => array( + 'testMarker' => '/* testMixedCaseFunction */', + 'expectedResult' => true, + ), + 'fully_qualified_function' => array( + 'testMarker' => '/* testFullyQualifiedFunction */', + 'expectedResult' => true, + ), + 'fully_qualified_upper_case_function' => array( + 'testMarker' => '/* testFullyQualifiedUpperCaseFunction */', + 'expectedResult' => true, + ), + 'named_param_reversed_order' => array( + 'testMarker' => '/* testNamedParamReversedOrder */', + 'expectedResult' => true, + ), + 'nested_valid_function_call' => array( + 'testMarker' => '/* testNestedValidFunctionCall */', + 'expectedResult' => true, + ), + ); + } +} diff --git a/WordPress/Tests/Security/NonceVerificationUnitTest.php b/WordPress/Tests/Security/NonceVerificationUnitTest.php index 7920859d6d..5f009f92e0 100644 --- a/WordPress/Tests/Security/NonceVerificationUnitTest.php +++ b/WordPress/Tests/Security/NonceVerificationUnitTest.php @@ -19,7 +19,6 @@ * @since 1.0.0 This sniff has been moved from the `CSRF` category to the `Security` category. * * @covers \WordPressCS\WordPress\Helpers\ContextHelper::is_in_type_test - * @covers \WordPressCS\WordPress\Helpers\ContextHelper::is_in_isset_or_empty * @covers \WordPressCS\WordPress\Helpers\ContextHelper::is_in_array_comparison * @covers \WordPressCS\WordPress\Sniffs\Security\NonceVerificationSniff */ From 22d4758e15c508e2da252cd7d514b9b90eb6ec73 Mon Sep 17 00:00:00 2001 From: Rodrigo Primo Date: Mon, 27 Apr 2026 18:19:19 +0530 Subject: [PATCH 081/108] ContextHelper::is_in_array_comparison(): add basic tests (#2726) * ContextHelper::is_in_array_comparison(): add basic tests * Add a bare variable test for consistency with the other similar helper method tests --- .../IsInArrayComparisonUnitTest.inc | 30 ++++ .../IsInArrayComparisonUnitTest.php | 131 ++++++++++++++++++ .../Security/NonceVerificationUnitTest.php | 1 - 3 files changed, 161 insertions(+), 1 deletion(-) create mode 100644 WordPress/Tests/Helpers/ContextHelper/IsInArrayComparisonUnitTest.inc create mode 100644 WordPress/Tests/Helpers/ContextHelper/IsInArrayComparisonUnitTest.php diff --git a/WordPress/Tests/Helpers/ContextHelper/IsInArrayComparisonUnitTest.inc b/WordPress/Tests/Helpers/ContextHelper/IsInArrayComparisonUnitTest.inc new file mode 100644 index 0000000000..09385129a0 --- /dev/null +++ b/WordPress/Tests/Helpers/ContextHelper/IsInArrayComparisonUnitTest.inc @@ -0,0 +1,30 @@ +array_search( /* testObjectMethod */ $value, $haystack ); +$obj?->array_keys( $array, /* testNullsafeObjectMethod */ $value ); +ArrayHelper::in_array( /* testStaticMethod */ $value, $haystack ); +array_keys( /* testArrayKeysFirstParamOnly */ $array ); +array_keys( array: /* testArrayKeysWrongNamedParam */ $array, search_value: 'value', strict: true ); + +/* + * The below should be recognized as being inside an array comparison function call. + */ + +in_array( /* testInArray */ $value, $haystack ); +array_search( /* testArraySearch */ $value, $haystack ); +array_keys( $array, /* testArrayKeysWithFilterValue */ $value ); +array_keys( filter_value: /* testArrayKeysNamedParam */ $value, array: $array ); +IN_array( /* testMixedCaseFunction */ $value, $haystack ); +\array_search( /* testFullyQualifiedFunction */ $value, $haystack ); +\ARRAY_KEYS( $array, /* testFullyQualifiedUpperCaseFunction */ $value ); +in_array( my_function( /* testNestedFunctionCall */ $value ), $haystack ); diff --git a/WordPress/Tests/Helpers/ContextHelper/IsInArrayComparisonUnitTest.php b/WordPress/Tests/Helpers/ContextHelper/IsInArrayComparisonUnitTest.php new file mode 100644 index 0000000000..e92a450d14 --- /dev/null +++ b/WordPress/Tests/Helpers/ContextHelper/IsInArrayComparisonUnitTest.php @@ -0,0 +1,131 @@ +getTargetToken( $testMarker, \T_VARIABLE ); + $result = ContextHelper::is_in_array_comparison( self::$phpcsFile, $stackPtr ); + + $this->assertSame( $expectedResult, $result ); + } + + /** + * Data provider. + * + * @see testIsInArrayComparison() + * + * @return array> + */ + public static function dataIsInArrayComparison() { + return array( + // Cases that should return false. + 'bare_variable' => array( + 'testMarker' => '/* testBareVariable */', + 'expectedResult' => false, + ), + 'other_function_call' => array( + 'testMarker' => '/* testOtherFunctionCall */', + 'expectedResult' => false, + ), + 'partially_qualified_function' => array( + 'testMarker' => '/* testPartiallyQualifiedFunction */', + 'expectedResult' => false, + ), + 'fully_qualified_namespaced_function' => array( + 'testMarker' => '/* testFullyQualifiedNamespacedFunction */', + 'expectedResult' => false, + ), + 'namespace_relative_function' => array( + 'testMarker' => '/* testNamespaceRelativeFunction */', + 'expectedResult' => false, + ), + 'namespace_relative_sub_function' => array( + 'testMarker' => '/* testNamespaceRelativeSubFunction */', + 'expectedResult' => false, + ), + 'object_method' => array( + 'testMarker' => '/* testObjectMethod */', + 'expectedResult' => false, + ), + 'nullsafe_object_method' => array( + 'testMarker' => '/* testNullsafeObjectMethod */', + 'expectedResult' => false, + ), + 'static_method' => array( + 'testMarker' => '/* testStaticMethod */', + 'expectedResult' => false, + ), + 'array_keys_first_param_only' => array( + 'testMarker' => '/* testArrayKeysFirstParamOnly */', + 'expectedResult' => false, + ), + 'array_keys_wrong_named_param' => array( + 'testMarker' => '/* testArrayKeysWrongNamedParam */', + 'expectedResult' => false, + ), + + // Cases that should return true. + 'in_array' => array( + 'testMarker' => '/* testInArray */', + 'expectedResult' => true, + ), + 'array_search' => array( + 'testMarker' => '/* testArraySearch */', + 'expectedResult' => true, + ), + 'array_keys_with_filter_value' => array( + 'testMarker' => '/* testArrayKeysWithFilterValue */', + 'expectedResult' => true, + ), + 'array_keys_named_param' => array( + 'testMarker' => '/* testArrayKeysNamedParam */', + 'expectedResult' => true, + ), + 'mixed_case_function' => array( + 'testMarker' => '/* testMixedCaseFunction */', + 'expectedResult' => true, + ), + 'fully_qualified_function' => array( + 'testMarker' => '/* testFullyQualifiedFunction */', + 'expectedResult' => true, + ), + 'fully_qualified_upper_case_function' => array( + 'testMarker' => '/* testFullyQualifiedUpperCaseFunction */', + 'expectedResult' => true, + ), + 'nested_function_call' => array( + 'testMarker' => '/* testNestedFunctionCall */', + 'expectedResult' => true, + ), + ); + } +} diff --git a/WordPress/Tests/Security/NonceVerificationUnitTest.php b/WordPress/Tests/Security/NonceVerificationUnitTest.php index 5f009f92e0..081de9a00f 100644 --- a/WordPress/Tests/Security/NonceVerificationUnitTest.php +++ b/WordPress/Tests/Security/NonceVerificationUnitTest.php @@ -19,7 +19,6 @@ * @since 1.0.0 This sniff has been moved from the `CSRF` category to the `Security` category. * * @covers \WordPressCS\WordPress\Helpers\ContextHelper::is_in_type_test - * @covers \WordPressCS\WordPress\Helpers\ContextHelper::is_in_array_comparison * @covers \WordPressCS\WordPress\Sniffs\Security\NonceVerificationSniff */ final class NonceVerificationUnitTest extends AbstractSniffUnitTest { From 6dfd8f1fb3b3dd5df7a697eff569e947289a089b Mon Sep 17 00:00:00 2001 From: Rodrigo Primo Date: Mon, 27 Apr 2026 18:36:40 +0530 Subject: [PATCH 082/108] WPDBTrait::is_wpdb_method_call(): improve docblock description (#2719) - Clarified that the method supports static method calls as well. - Replaced incomplete description with a list of the three properties that may be automatically set: `$methodPtr`, `$i`, and `$end`. - Added clarification that `$methodPtr` and `$i` may be set even when the method returns false (e.g., for property access like `$wpdb->show_errors`). - Updated `$stackPtr` parameter description to mention it can be a "wpdb class name token" as well. - Made the `$end` description more precise: it points to the comma after the first parameter, or to one past the last token of the first parameter if there is no comma. --- WordPress/Helpers/WPDBTrait.php | 23 +++++++++++++++++------ 1 file changed, 17 insertions(+), 6 deletions(-) diff --git a/WordPress/Helpers/WPDBTrait.php b/WordPress/Helpers/WPDBTrait.php index afa6ffc54f..d2f729da5b 100644 --- a/WordPress/Helpers/WPDBTrait.php +++ b/WordPress/Helpers/WPDBTrait.php @@ -23,12 +23,23 @@ trait WPDBTrait { /** - * Checks whether this is a call to a $wpdb method that we want to sniff. + * Checks whether this is a call to one of a specific group of $wpdb method(s). * - * If available in the class using this trait, the $methodPtr, $i and $end properties - * are automatically set to correspond to the start and end of the method call. - * The $i property is also set if this is not a method call but rather the - * use of a $wpdb property. + * Supports both instance method calls (e.g., `$wpdb->prepare()`) and static + * method calls (e.g., `wpdb::esc_like()`). + * + * Note: Static calls on non-static wpdb methods are problematic at runtime, but this + * helper still matches them so sniffs can flag them in the code under scan. + * + * If the following properties are explicitly declared in the class using this trait, + * they will be automatically set: + * - `$methodPtr`: Stack pointer to the method name. + * - `$i`: Stack pointer to the opening parenthesis of the method call. + * - `$end`: Stack pointer to the comma after the first parameter, or to the + * token directly after the first parameter if there is no comma. + * + * The `$methodPtr` and `$i` properties may be set even when this method returns `false` + * (e.g., for property access like `$wpdb->show_errors`). * * @since 0.8.0 * @since 0.9.0 The return value is now always boolean. The $end and $i member @@ -41,7 +52,7 @@ trait WPDBTrait { * for properties in the sniff class(es) using it.}} * * @param \PHP_CodeSniffer\Files\File $phpcsFile The file being scanned. - * @param int $stackPtr The index of the $wpdb variable. + * @param int $stackPtr The index of the $wpdb variable or wpdb (class) name token. * @param array $target_methods Array of methods. Key(s) should be method name * in lowercase. * From adaf62d34724afd0c46481aa40bf85566b1265ac Mon Sep 17 00:00:00 2001 From: Rodrigo Primo Date: Mon, 27 Apr 2026 18:41:33 +0530 Subject: [PATCH 083/108] ContextHelper::is_in_type_test(): add tests (#2721) --- .../ContextHelper/IsInTypeTestUnitTest.inc | 26 ++++ .../ContextHelper/IsInTypeTestUnitTest.php | 115 ++++++++++++++++++ .../Security/NonceVerificationUnitTest.php | 1 - 3 files changed, 141 insertions(+), 1 deletion(-) create mode 100644 WordPress/Tests/Helpers/ContextHelper/IsInTypeTestUnitTest.inc create mode 100644 WordPress/Tests/Helpers/ContextHelper/IsInTypeTestUnitTest.php diff --git a/WordPress/Tests/Helpers/ContextHelper/IsInTypeTestUnitTest.inc b/WordPress/Tests/Helpers/ContextHelper/IsInTypeTestUnitTest.inc new file mode 100644 index 0000000000..b3b2015bf2 --- /dev/null +++ b/WordPress/Tests/Helpers/ContextHelper/IsInTypeTestUnitTest.inc @@ -0,0 +1,26 @@ +is_string( /* testObjectMethod */ $value ); +$obj?->is_object( /* testNullsafeObjectMethod */ $value ); +TypeChecker::is_int( /* testStaticMethod */ $value ); +is_scalar( my_function( /* testNestedNonTargetFunctionCall */ $value ) ); + +/* + * The below should be recognized as being inside a type test function call. + */ + +is_array( /* testUnqualifiedFunction */ $value ); +Is_Bool( /* testMixedCaseFunction */ $value ); +\is_string( /* testFullyQualifiedFunction */ $value ); +\IS_NUMERIC( /* testFullyQualifiedUpperCaseFunction */ $value ); +is_int( is_float( /* testNestedTypeTestCall */ $value ) ); diff --git a/WordPress/Tests/Helpers/ContextHelper/IsInTypeTestUnitTest.php b/WordPress/Tests/Helpers/ContextHelper/IsInTypeTestUnitTest.php new file mode 100644 index 0000000000..cc731c6713 --- /dev/null +++ b/WordPress/Tests/Helpers/ContextHelper/IsInTypeTestUnitTest.php @@ -0,0 +1,115 @@ +getTargetToken( $testMarker, \T_VARIABLE ); + $result = ContextHelper::is_in_type_test( self::$phpcsFile, $stackPtr ); + + $this->assertSame( $expectedResult, $result ); + } + + /** + * Data provider. + * + * @see testIsInTypeTest() + * + * @return array> + */ + public static function dataIsInTypeTest() { + return array( + // Cases that should return false. + 'bare_variable' => array( + 'testMarker' => '/* testBareVariable */', + 'expectedResult' => false, + ), + 'other_function_call' => array( + 'testMarker' => '/* testOtherFunctionCall */', + 'expectedResult' => false, + ), + 'partially_qualified_function' => array( + 'testMarker' => '/* testPartiallyQualifiedFunction */', + 'expectedResult' => false, + ), + 'fully_qualified_namespaced_function' => array( + 'testMarker' => '/* testFullyQualifiedNamespacedFunction */', + 'expectedResult' => false, + ), + 'namespace_relative_function' => array( + 'testMarker' => '/* testNamespaceRelativeFunction */', + 'expectedResult' => false, + ), + 'namespace_relative_sub_function' => array( + 'testMarker' => '/* testNamespaceRelativeSubFunction */', + 'expectedResult' => false, + ), + 'object_method' => array( + 'testMarker' => '/* testObjectMethod */', + 'expectedResult' => false, + ), + 'nullsafe_object_method' => array( + 'testMarker' => '/* testNullsafeObjectMethod */', + 'expectedResult' => false, + ), + 'static_method' => array( + 'testMarker' => '/* testStaticMethod */', + 'expectedResult' => false, + ), + 'nested_non_target_function_call' => array( + 'testMarker' => '/* testNestedNonTargetFunctionCall */', + 'expectedResult' => false, + ), + + // Cases that should return true. + 'unqualified_function' => array( + 'testMarker' => '/* testUnqualifiedFunction */', + 'expectedResult' => true, + ), + 'mixed_case_function' => array( + 'testMarker' => '/* testMixedCaseFunction */', + 'expectedResult' => true, + ), + 'fully_qualified_function' => array( + 'testMarker' => '/* testFullyQualifiedFunction */', + 'expectedResult' => true, + ), + 'fully_qualified_upper_case_function' => array( + 'testMarker' => '/* testFullyQualifiedUpperCaseFunction */', + 'expectedResult' => true, + ), + 'nested_type_test_call' => array( + 'testMarker' => '/* testNestedTypeTestCall */', + 'expectedResult' => true, + ), + ); + } +} diff --git a/WordPress/Tests/Security/NonceVerificationUnitTest.php b/WordPress/Tests/Security/NonceVerificationUnitTest.php index 081de9a00f..d5ee162048 100644 --- a/WordPress/Tests/Security/NonceVerificationUnitTest.php +++ b/WordPress/Tests/Security/NonceVerificationUnitTest.php @@ -18,7 +18,6 @@ * @since 0.13.0 Class name changed: this class is now namespaced. * @since 1.0.0 This sniff has been moved from the `CSRF` category to the `Security` category. * - * @covers \WordPressCS\WordPress\Helpers\ContextHelper::is_in_type_test * @covers \WordPressCS\WordPress\Sniffs\Security\NonceVerificationSniff */ final class NonceVerificationUnitTest extends AbstractSniffUnitTest { From f812c2559a97abce6d1332d1613cf98e7876e895 Mon Sep 17 00:00:00 2001 From: Rodrigo Primo Date: Fri, 14 Nov 2025 11:41:18 -0300 Subject: [PATCH 084/108] Security/EscapeOutput: make basename( __FILE__ ) pattern matching case-insensitive The sniff has special handling for `_deprecated_file()` calls where the first parameter follows the `basename( __FILE__ )` pattern. The regex pattern was case-sensitive, which meant it would only match lowercase `basename()` and uppercase `__FILE__`. This is incorrect because both function names and magic constants (https://3v4l.org/8nAEV and https://www.php.net/manual/en/language.constants.magic.php) in PHP are case-insensitive. This commit fixes the regex pattern to be case-insensitive. --- WordPress/Sniffs/Security/EscapeOutputSniff.php | 2 +- WordPress/Tests/Security/EscapeOutputUnitTest.1.inc | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/WordPress/Sniffs/Security/EscapeOutputSniff.php b/WordPress/Sniffs/Security/EscapeOutputSniff.php index 8a964cc020..b05732e823 100644 --- a/WordPress/Sniffs/Security/EscapeOutputSniff.php +++ b/WordPress/Sniffs/Security/EscapeOutputSniff.php @@ -438,7 +438,7 @@ public function process_matched_token( $stackPtr, $group_name, $matched_content if ( false !== $file_param ) { // Check for a particular code pattern which can safely be ignored. - if ( preg_match( '`^[\\\\]?basename\s*\(\s*__FILE__\s*\)$`', $file_param['clean'] ) === 1 ) { + if ( preg_match( '`^[\\\\]?basename\s*\(\s*__FILE__\s*\)$`i', $file_param['clean'] ) === 1 ) { unset( $params[1], $params['file'] ); // Remove the param, whether passed positionally or named. } } diff --git a/WordPress/Tests/Security/EscapeOutputUnitTest.1.inc b/WordPress/Tests/Security/EscapeOutputUnitTest.1.inc index 5946578951..f744f385da 100644 --- a/WordPress/Tests/Security/EscapeOutputUnitTest.1.inc +++ b/WordPress/Tests/Security/EscapeOutputUnitTest.1.inc @@ -365,7 +365,7 @@ $obj = new User_Error( $foo ); // OK. // Make sure special casing of select functions is handled case-insensitively. Trigger_ERROR( 'This is fine', $second_param_should_be_ignored ); // OK. -_Deprecated_File( basename( __FILE__ ), '1.3.0' ); // OK. +_Deprecated_File( BASENAME( __file__ ), '1.3.0' ); // OK. _EX( 'all_params_should_be_ignored_if_function_is_reported_as_unsafe', 'another_param' ); // Bad x 1 for unsafe function. // Allow for comments in the $file parameter. From 6af12d37d3d53531deaee4b4b28898c30d47ee5f Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 21 May 2026 00:16:42 +0000 Subject: [PATCH 085/108] GH Actions: Bump the action-runners group across 1 directory with 3 updates Bumps the action-runners group with 3 updates in the / directory: [shivammathur/setup-php](https://github.com/shivammathur/setup-php), [crate-ci/typos](https://github.com/crate-ci/typos) and [codecov/codecov-action](https://github.com/codecov/codecov-action). Updates `shivammathur/setup-php` from 2.37.0 to 2.37.1 - [Release notes](https://github.com/shivammathur/setup-php/releases) - [Commits](https://github.com/shivammathur/setup-php/compare/accd6127cb78bee3e8082180cb391013d204ef9f...7c071dfe9dc99bdf297fa79cb49ea005b9fcadbc) Updates `crate-ci/typos` from 1.45.0 to 1.46.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/02ea592e44b3a53c302f697cddca7641cd051c3d...aca895bf05aec0cb7dffa6f94495e923224d9f17) Updates `codecov/codecov-action` from 6.0.0 to 6.0.1 - [Release notes](https://github.com/codecov/codecov-action/releases) - [Changelog](https://github.com/codecov/codecov-action/blob/main/CHANGELOG.md) - [Commits](https://github.com/codecov/codecov-action/compare/57e3a136b779b570ffcdbf80b3bdc90e7fab3de2...e79a6962e0d4c0c17b229090214935d2e33f8354) --- updated-dependencies: - dependency-name: shivammathur/setup-php dependency-version: 2.37.1 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: action-runners - dependency-name: crate-ci/typos dependency-version: 1.46.2 dependency-type: direct:production update-type: version-update:semver-minor dependency-group: action-runners - dependency-name: codecov/codecov-action dependency-version: 6.0.1 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: action-runners ... Signed-off-by: dependabot[bot] --- .github/workflows/basic-qa.yml | 8 ++++---- .github/workflows/quicktest.yml | 4 ++-- .github/workflows/unit-tests.yml | 4 ++-- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/.github/workflows/basic-qa.yml b/.github/workflows/basic-qa.yml index 3d3b7453ff..f782c4a639 100644 --- a/.github/workflows/basic-qa.yml +++ b/.github/workflows/basic-qa.yml @@ -31,7 +31,7 @@ jobs: persist-credentials: false - name: Setup PHP - uses: shivammathur/setup-php@accd6127cb78bee3e8082180cb391013d204ef9f # 2.37.0 + uses: shivammathur/setup-php@7c071dfe9dc99bdf297fa79cb49ea005b9fcadbc # 2.37.1 with: php-version: 'latest' coverage: none @@ -162,7 +162,7 @@ jobs: persist-credentials: false - name: Set up PHP - uses: shivammathur/setup-php@accd6127cb78bee3e8082180cb391013d204ef9f # 2.37.0 + uses: shivammathur/setup-php@7c071dfe9dc99bdf297fa79cb49ea005b9fcadbc # 2.37.1 with: php-version: ${{ matrix.php }} # Allow for PHP deprecation notices. @@ -245,7 +245,7 @@ jobs: persist-credentials: false - name: Install PHP - uses: shivammathur/setup-php@accd6127cb78bee3e8082180cb391013d204ef9f # 2.37.0 + uses: shivammathur/setup-php@7c071dfe9dc99bdf297fa79cb49ea005b9fcadbc # 2.37.1 with: php-version: 'latest' coverage: none @@ -275,4 +275,4 @@ jobs: persist-credentials: false - name: "Search for misspellings" - uses: "crate-ci/typos@02ea592e44b3a53c302f697cddca7641cd051c3d" # v1.45.0 + uses: "crate-ci/typos@aca895bf05aec0cb7dffa6f94495e923224d9f17" # v1.46.2 diff --git a/.github/workflows/quicktest.yml b/.github/workflows/quicktest.yml index e587e77918..afe220a276 100644 --- a/.github/workflows/quicktest.yml +++ b/.github/workflows/quicktest.yml @@ -35,7 +35,7 @@ jobs: persist-credentials: false - name: Set up PHP - uses: shivammathur/setup-php@accd6127cb78bee3e8082180cb391013d204ef9f # 2.37.0 + uses: shivammathur/setup-php@7c071dfe9dc99bdf297fa79cb49ea005b9fcadbc # 2.37.1 with: php-version: ${{ matrix.php }} # With stable PHPCS dependencies, allow for PHP deprecation notices. @@ -75,7 +75,7 @@ jobs: - name: Send coverage report to Codecov if: ${{ success() && github.event.repository.fork == false && github.ref_name == 'develop' }} - uses: codecov/codecov-action@57e3a136b779b570ffcdbf80b3bdc90e7fab3de2 # v6.0.0 + uses: codecov/codecov-action@e79a6962e0d4c0c17b229090214935d2e33f8354 # v6.0.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 3e54a726eb..e7dce879cd 100644 --- a/.github/workflows/unit-tests.yml +++ b/.github/workflows/unit-tests.yml @@ -90,7 +90,7 @@ jobs: fi - name: Set up PHP - uses: shivammathur/setup-php@accd6127cb78bee3e8082180cb391013d204ef9f # 2.37.0 + uses: shivammathur/setup-php@7c071dfe9dc99bdf297fa79cb49ea005b9fcadbc # 2.37.1 with: php-version: ${{ matrix.php }} ini-values: ${{ steps.set_ini.outputs.PHP_INI }} @@ -137,7 +137,7 @@ jobs: - name: Send coverage report to Codecov if: ${{ success() && matrix.coverage == true && github.event.repository.fork == false }} - uses: codecov/codecov-action@57e3a136b779b570ffcdbf80b3bdc90e7fab3de2 # v6.0.0 + uses: codecov/codecov-action@e79a6962e0d4c0c17b229090214935d2e33f8354 # v6.0.1 with: files: ./build/logs/clover.xml fail_ci_if_error: true From 3ff295709b50dee45666765678f9410c024463e0 Mon Sep 17 00:00:00 2001 From: Dion Hulse Date: Tue, 2 Jun 2026 23:33:00 +1000 Subject: [PATCH 086/108] Update project Code of Conduct to match WordPress Project (#2733) * Remove project-specific CODE_OF_CONDUCT.md * Link to CoC from readme * Update Code of Conduct link to WordPress Project CoC in CONTRIBUTING.md --- .github/CONTRIBUTING.md | 2 +- CODE_OF_CONDUCT.md | 128 ---------------------------------------- README.md | 2 + 3 files changed, 3 insertions(+), 129 deletions(-) delete mode 100644 CODE_OF_CONDUCT.md diff --git a/.github/CONTRIBUTING.md b/.github/CONTRIBUTING.md index 337db8e8fa..29909cd49f 100644 --- a/.github/CONTRIBUTING.md +++ b/.github/CONTRIBUTING.md @@ -29,7 +29,7 @@ We welcome contributions from everyone, and want your PR to have the best chance 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). + 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](https://github.com/WordPress/.github/blob/trunk/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. diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md deleted file mode 100644 index c0a53dc110..0000000000 --- a/CODE_OF_CONDUCT.md +++ /dev/null @@ -1,128 +0,0 @@ -# Contributor Covenant Code of Conduct - -## Our Pledge - -We as members, contributors, and leaders pledge to make participation in our -community a harassment-free experience for everyone, regardless of age, body -size, visible or invisible disability, ethnicity, sex characteristics, gender -identity and expression, level of experience, education, socio-economic status, -nationality, personal appearance, race, religion, or sexual identity -and orientation. - -We pledge to act and interact in ways that contribute to an open, welcoming, -diverse, inclusive, and healthy community. - -## Our Standards - -Examples of behavior that contributes to a positive environment for our -community include: - -* Demonstrating empathy and kindness toward other people -* Being respectful of differing opinions, viewpoints, and experiences -* Giving and gracefully accepting constructive feedback -* Accepting responsibility and apologizing to those affected by our mistakes, - and learning from the experience -* Focusing on what is best not just for us as individuals, but for the - overall community - -Examples of unacceptable behavior include: - -* The use of sexualized language or imagery, and sexual attention or - advances of any kind -* Trolling, insulting or derogatory comments, and personal or political attacks -* Public or private harassment -* Publishing others' private information, such as a physical or email - address, without their explicit permission -* Other conduct which could reasonably be considered inappropriate in a - professional setting - -## Enforcement Responsibilities - -Community leaders are responsible for clarifying and enforcing our standards of -acceptable behavior and will take appropriate and fair corrective action in -response to any behavior that they deem inappropriate, threatening, offensive, -or harmful. - -Community leaders have the right and responsibility to remove, edit, or reject -comments, commits, code, wiki edits, issues, and other contributions that are -not aligned to this Code of Conduct, and will communicate reasons for moderation -decisions when appropriate. - -## Scope - -This Code of Conduct applies within all community spaces, and also applies when -an individual is officially representing the community in public spaces. -Examples of representing our community include using an official e-mail address, -posting via an official social media account, or acting as an appointed -representative at an online or offline event. - -## Enforcement - -Instances of abusive, harassing, or otherwise unacceptable behavior may be -reported to the community leaders responsible for enforcement in -the [WordPress Slack](https://make.wordpress.org/chat/) in the [#core-coding-standards channel](https://wordpress.slack.com/archives/C5VCTJGH3). -All complaints will be reviewed and investigated promptly and fairly. - -All community leaders are obligated to respect the privacy and security of the -reporter of any incident. - -## Enforcement Guidelines - -Community leaders will follow these Community Impact Guidelines in determining -the consequences for any action they deem in violation of this Code of Conduct: - -### 1. Correction - -**Community Impact**: Use of inappropriate language or other behavior deemed -unprofessional or unwelcome in the community. - -**Consequence**: A private, written warning from community leaders, providing -clarity around the nature of the violation and an explanation of why the -behavior was inappropriate. A public apology may be requested. - -### 2. Warning - -**Community Impact**: A violation through a single incident or series -of actions. - -**Consequence**: A warning with consequences for continued behavior. No -interaction with the people involved, including unsolicited interaction with -those enforcing the Code of Conduct, for a specified period of time. This -includes avoiding interactions in community spaces as well as external channels -like social media. Violating these terms may lead to a temporary or -permanent ban. - -### 3. Temporary Ban - -**Community Impact**: A serious violation of community standards, including -sustained inappropriate behavior. - -**Consequence**: A temporary ban from any sort of interaction or public -communication with the community for a specified period of time. No public or -private interaction with the people involved, including unsolicited interaction -with those enforcing the Code of Conduct, is allowed during this period. -Violating these terms may lead to a permanent ban. - -### 4. Permanent Ban - -**Community Impact**: Demonstrating a pattern of violation of community -standards, including sustained inappropriate behavior, harassment of an -individual, or aggression toward or disparagement of classes of individuals. - -**Consequence**: A permanent ban from any sort of public interaction within -the community. - -## Attribution - -This Code of Conduct is adapted from the [Contributor Covenant][homepage], -version 2.0, available at -https://www.contributor-covenant.org/version/2/0/code_of_conduct.html. - -Community Impact Guidelines were inspired by [Mozilla's code of conduct -enforcement ladder](https://github.com/mozilla/diversity). - -[homepage]: https://www.contributor-covenant.org - -For answers to common questions about this code of conduct, see the FAQ at -https://www.contributor-covenant.org/faq. Translations are available at -https://www.contributor-covenant.org/translations. diff --git a/README.md b/README.md index febabd8ad4..8cc41d9cd6 100644 --- a/README.md +++ b/README.md @@ -253,6 +253,8 @@ At this moment, WordPressCS offer the following tools: See [CONTRIBUTING](.github/CONTRIBUTING.md), including information about [unit testing](.github/CONTRIBUTING.md#unit-testing) the standard. +Anyone contributing to the WordPress Coding Standards is expected to conduct themselves in accordance with the WordPress project's [Code of Conduct](https://github.com/WordPress/.github/blob/trunk/CODE_OF_CONDUCT.md). + ## Funding If you want to sponsor the work on WordPressCS, you can do so by donating to the [PHP_CodeSniffer Open Collective](https://opencollective.com/php_codesniffer). From a4116cf1519917c91e6211421eddc7bd998e2258 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 5 Jun 2026 22:13:06 +0000 Subject: [PATCH 087/108] 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 6.0.2 to 6.0.3 - [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/de0fac2e4500dabe0009e67214ff5f5447ce83dd...df4cb1c069e1874edd31b4311f1884172cec0e10) Updates `crate-ci/typos` from 1.46.2 to 1.47.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/aca895bf05aec0cb7dffa6f94495e923224d9f17...37bb98842b0d8c4ffebdb75301a13db0267cef89) --- updated-dependencies: - dependency-name: actions/checkout dependency-version: 6.0.3 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: action-runners - dependency-name: crate-ci/typos dependency-version: 1.47.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 | 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 f782c4a639..aacbe3cf89 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@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3 with: persist-credentials: false @@ -117,7 +117,7 @@ jobs: steps: - name: Checkout code - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3 with: persist-credentials: false @@ -157,7 +157,7 @@ jobs: steps: - name: Checkout repository - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3 with: persist-credentials: false @@ -240,7 +240,7 @@ jobs: steps: - name: Checkout code - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3 with: persist-credentials: false @@ -270,9 +270,9 @@ jobs: steps: - name: "Checkout" - uses: "actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd" # v6.0.2 + uses: "actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10" # v6.0.3 with: persist-credentials: false - name: "Search for misspellings" - uses: "crate-ci/typos@aca895bf05aec0cb7dffa6f94495e923224d9f17" # v1.46.2 + uses: "crate-ci/typos@37bb98842b0d8c4ffebdb75301a13db0267cef89" # v1.47.2 diff --git a/.github/workflows/quicktest.yml b/.github/workflows/quicktest.yml index afe220a276..782b062a13 100644 --- a/.github/workflows/quicktest.yml +++ b/.github/workflows/quicktest.yml @@ -30,7 +30,7 @@ jobs: steps: - name: Checkout repository - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3 with: persist-credentials: false diff --git a/.github/workflows/unit-tests.yml b/.github/workflows/unit-tests.yml index e7dce879cd..4a752e5666 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@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3 with: persist-credentials: false From b8b3275b2959b7d7d2124174e367e2473fcc879d Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 15 Jun 2026 12:58:15 +0000 Subject: [PATCH 088/108] GH Actions: Bump codecov/codecov-action from 6.0.1 to 7.0.0 Bumps [codecov/codecov-action](https://github.com/codecov/codecov-action) from 6.0.1 to 7.0.0. - [Release notes](https://github.com/codecov/codecov-action/releases) - [Changelog](https://github.com/codecov/codecov-action/blob/main/CHANGELOG.md) - [Commits](https://github.com/codecov/codecov-action/compare/e79a6962e0d4c0c17b229090214935d2e33f8354...fb8b3582c8e4def4969c97caa2f19720cb33a72f) --- updated-dependencies: - dependency-name: codecov/codecov-action dependency-version: 7.0.0 dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] --- .github/workflows/quicktest.yml | 2 +- .github/workflows/unit-tests.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/quicktest.yml b/.github/workflows/quicktest.yml index 782b062a13..929da1f155 100644 --- a/.github/workflows/quicktest.yml +++ b/.github/workflows/quicktest.yml @@ -75,7 +75,7 @@ jobs: - name: Send coverage report to Codecov if: ${{ success() && github.event.repository.fork == false && github.ref_name == 'develop' }} - uses: codecov/codecov-action@e79a6962e0d4c0c17b229090214935d2e33f8354 # v6.0.1 + uses: codecov/codecov-action@fb8b3582c8e4def4969c97caa2f19720cb33a72f # v7.0.0 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 4a752e5666..3a102358ab 100644 --- a/.github/workflows/unit-tests.yml +++ b/.github/workflows/unit-tests.yml @@ -137,7 +137,7 @@ jobs: - name: Send coverage report to Codecov if: ${{ success() && matrix.coverage == true && github.event.repository.fork == false }} - uses: codecov/codecov-action@e79a6962e0d4c0c17b229090214935d2e33f8354 # v6.0.1 + uses: codecov/codecov-action@fb8b3582c8e4def4969c97caa2f19720cb33a72f # v7.0.0 with: files: ./build/logs/clover.xml fail_ci_if_error: true From a553836e26636f366dd42943c736d19ef18e23b0 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 15 Jun 2026 13:14:32 +0000 Subject: [PATCH 089/108] GH Actions: Bump the action-runners group across 1 directory with 2 updates Bumps the action-runners group with 2 updates in the / directory: [shivammathur/setup-php](https://github.com/shivammathur/setup-php) and [korelstar/xmllint-problem-matcher](https://github.com/korelstar/xmllint-problem-matcher). Updates `shivammathur/setup-php` from 2.37.1 to 2.37.2 - [Release notes](https://github.com/shivammathur/setup-php/releases) - [Commits](https://github.com/shivammathur/setup-php/compare/7c071dfe9dc99bdf297fa79cb49ea005b9fcadbc...f3e473d116dcccaddc5834248c87452386958240) Updates `korelstar/xmllint-problem-matcher` from 1.2.0 to 1.3.0 - [Release notes](https://github.com/korelstar/xmllint-problem-matcher/releases) - [Commits](https://github.com/korelstar/xmllint-problem-matcher/compare/1bd292d642ddf3d369d02aaa8b262834d61198c0...dd2ad21bd8a2de0187cb621419537f345e7e509c) --- updated-dependencies: - dependency-name: korelstar/xmllint-problem-matcher dependency-version: 1.3.0 dependency-type: direct:production update-type: version-update:semver-minor dependency-group: action-runners - dependency-name: shivammathur/setup-php dependency-version: 2.37.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 | 8 ++++---- .github/workflows/quicktest.yml | 2 +- .github/workflows/unit-tests.yml | 2 +- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/.github/workflows/basic-qa.yml b/.github/workflows/basic-qa.yml index aacbe3cf89..e0ca7e5b7a 100644 --- a/.github/workflows/basic-qa.yml +++ b/.github/workflows/basic-qa.yml @@ -31,7 +31,7 @@ jobs: persist-credentials: false - name: Setup PHP - uses: shivammathur/setup-php@7c071dfe9dc99bdf297fa79cb49ea005b9fcadbc # 2.37.1 + uses: shivammathur/setup-php@f3e473d116dcccaddc5834248c87452386958240 # 2.37.2 with: php-version: 'latest' coverage: none @@ -133,7 +133,7 @@ jobs: # Show XML violations inline in the file diff. - name: Enable showing XML issues inline - uses: korelstar/xmllint-problem-matcher@1bd292d642ddf3d369d02aaa8b262834d61198c0 # v1.2.0 + uses: korelstar/xmllint-problem-matcher@dd2ad21bd8a2de0187cb621419537f345e7e509c # v1.3.0 - name: Check the code-style consistency of the xml files run: | @@ -162,7 +162,7 @@ jobs: persist-credentials: false - name: Set up PHP - uses: shivammathur/setup-php@7c071dfe9dc99bdf297fa79cb49ea005b9fcadbc # 2.37.1 + uses: shivammathur/setup-php@f3e473d116dcccaddc5834248c87452386958240 # 2.37.2 with: php-version: ${{ matrix.php }} # Allow for PHP deprecation notices. @@ -245,7 +245,7 @@ jobs: persist-credentials: false - name: Install PHP - uses: shivammathur/setup-php@7c071dfe9dc99bdf297fa79cb49ea005b9fcadbc # 2.37.1 + uses: shivammathur/setup-php@f3e473d116dcccaddc5834248c87452386958240 # 2.37.2 with: php-version: 'latest' coverage: none diff --git a/.github/workflows/quicktest.yml b/.github/workflows/quicktest.yml index 929da1f155..2ccd32eff9 100644 --- a/.github/workflows/quicktest.yml +++ b/.github/workflows/quicktest.yml @@ -35,7 +35,7 @@ jobs: persist-credentials: false - name: Set up PHP - uses: shivammathur/setup-php@7c071dfe9dc99bdf297fa79cb49ea005b9fcadbc # 2.37.1 + uses: shivammathur/setup-php@f3e473d116dcccaddc5834248c87452386958240 # 2.37.2 with: php-version: ${{ matrix.php }} # With stable PHPCS dependencies, allow for PHP deprecation notices. diff --git a/.github/workflows/unit-tests.yml b/.github/workflows/unit-tests.yml index 3a102358ab..b84f123183 100644 --- a/.github/workflows/unit-tests.yml +++ b/.github/workflows/unit-tests.yml @@ -90,7 +90,7 @@ jobs: fi - name: Set up PHP - uses: shivammathur/setup-php@7c071dfe9dc99bdf297fa79cb49ea005b9fcadbc # 2.37.1 + uses: shivammathur/setup-php@f3e473d116dcccaddc5834248c87452386958240 # 2.37.2 with: php-version: ${{ matrix.php }} ini-values: ${{ steps.set_ini.outputs.PHP_INI }} From 50db73c84a09315292a5661bb6c12b496090aceb Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sat, 20 Jun 2026 22:12:31 +0000 Subject: [PATCH 090/108] GH Actions: Bump actions/checkout from 6.0.3 to 7.0.0 Bumps [actions/checkout](https://github.com/actions/checkout) from 6.0.3 to 7.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/df4cb1c069e1874edd31b4311f1884172cec0e10...9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0) --- updated-dependencies: - dependency-name: actions/checkout dependency-version: 7.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 e0ca7e5b7a..40d3cca9f5 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@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3 + uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 with: persist-credentials: false @@ -117,7 +117,7 @@ jobs: steps: - name: Checkout code - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3 + uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 with: persist-credentials: false @@ -157,7 +157,7 @@ jobs: steps: - name: Checkout repository - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3 + uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 with: persist-credentials: false @@ -240,7 +240,7 @@ jobs: steps: - name: Checkout code - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3 + uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 with: persist-credentials: false @@ -270,7 +270,7 @@ jobs: steps: - name: "Checkout" - uses: "actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10" # v6.0.3 + uses: "actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0" # v7.0.0 with: persist-credentials: false diff --git a/.github/workflows/quicktest.yml b/.github/workflows/quicktest.yml index 2ccd32eff9..5da0c17a35 100644 --- a/.github/workflows/quicktest.yml +++ b/.github/workflows/quicktest.yml @@ -30,7 +30,7 @@ jobs: steps: - name: Checkout repository - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3 + uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 with: persist-credentials: false diff --git a/.github/workflows/unit-tests.yml b/.github/workflows/unit-tests.yml index b84f123183..3a9514793c 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@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3 + uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 with: persist-credentials: false From 36813dba42b89318bd84093add9f027665665a00 Mon Sep 17 00:00:00 2001 From: Rodrigo Primo Date: Thu, 2 Jul 2026 09:49:39 -0300 Subject: [PATCH 091/108] WP/ClassNameCase: fix typo --- WordPress/Sniffs/WP/ClassNameCaseSniff.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/WordPress/Sniffs/WP/ClassNameCaseSniff.php b/WordPress/Sniffs/WP/ClassNameCaseSniff.php index ef8170e275..72c560b769 100644 --- a/WordPress/Sniffs/WP/ClassNameCaseSniff.php +++ b/WordPress/Sniffs/WP/ClassNameCaseSniff.php @@ -826,7 +826,7 @@ final class ClassNameCaseSniff extends AbstractClassRestrictionsSniff { /** * List of all GetID3 classes in lowercase. * - * This array is automatically generated in the class constructor based on the $phpmailer_classes property. + * This array is automatically generated in the class constructor based on the $getid3_classes property. * * @since 3.0.0 * From fb13790e2c34ed9e318a8f501c1b7fa4d0a741ff Mon Sep 17 00:00:00 2001 From: jrfnl Date: Fri, 3 Jul 2026 00:21:46 +0200 Subject: [PATCH 092/108] Update .gitattributes Follow up to 2539 and 2733 which both either added or removed a file which should be in the repo, but should not be distributed with releases. --- .gitattributes | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.gitattributes b/.gitattributes index 3472eccbfa..78c933e3f4 100644 --- a/.gitattributes +++ b/.gitattributes @@ -8,7 +8,7 @@ /.gitignore export-ignore /.codecov.yml export-ignore /.phpcs.xml.dist export-ignore -/CODE_OF_CONDUCT.md export-ignore +/_typos.toml export-ignore /phpstan.neon.dist export-ignore /phpunit.xml.dist export-ignore /.github export-ignore From ff923bf73b2d22a56a274e80ebb33e121ee55a8c Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sun, 5 Jul 2026 22:12:42 +0000 Subject: [PATCH 093/108] 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.47.2 to 1.48.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/37bb98842b0d8c4ffebdb75301a13db0267cef89...bee27e3a4fd1ea2111cf90ab89cd076c870fce14) --- updated-dependencies: - dependency-name: crate-ci/typos dependency-version: 1.48.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 40d3cca9f5..20d820184e 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@37bb98842b0d8c4ffebdb75301a13db0267cef89" # v1.47.2 + uses: "crate-ci/typos@bee27e3a4fd1ea2111cf90ab89cd076c870fce14" # v1.48.0 From 8611846958e9b84c4b389f34ade97c6c7ff09c66 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sun, 5 Jul 2026 22:12:46 +0000 Subject: [PATCH 094/108] GH Actions: Bump phpcsstandards/xmllint-validate from 1.0.1 to 2.0.0 Bumps [phpcsstandards/xmllint-validate](https://github.com/phpcsstandards/xmllint-validate) from 1.0.1 to 2.0.0. - [Release notes](https://github.com/phpcsstandards/xmllint-validate/releases) - [Commits](https://github.com/phpcsstandards/xmllint-validate/compare/0fd9c4a9046055f621fca4bbdccb8eab1fd59fdc...5189514594c8d5f4cf21b7e5af50f54d697973d7) --- updated-dependencies: - dependency-name: phpcsstandards/xmllint-validate dependency-version: 2.0.0 dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] --- .github/workflows/basic-qa.yml | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/.github/workflows/basic-qa.yml b/.github/workflows/basic-qa.yml index 40d3cca9f5..14bdd472e8 100644 --- a/.github/workflows/basic-qa.yml +++ b/.github/workflows/basic-qa.yml @@ -66,38 +66,38 @@ jobs: # Validate the Ruleset XML files. # @link http://xmlsoft.org/xmllint.html - name: Validate the WordPress rulesets - uses: phpcsstandards/xmllint-validate@0fd9c4a9046055f621fca4bbdccb8eab1fd59fdc # v1.0.1 + uses: phpcsstandards/xmllint-validate@5189514594c8d5f4cf21b7e5af50f54d697973d7 # v2.0.0 with: pattern: "./*/ruleset.xml" xsd-file: "vendor/squizlabs/php_codesniffer/phpcs.xsd" - name: Validate the sample ruleset - uses: phpcsstandards/xmllint-validate@0fd9c4a9046055f621fca4bbdccb8eab1fd59fdc # v1.0.1 + uses: phpcsstandards/xmllint-validate@5189514594c8d5f4cf21b7e5af50f54d697973d7 # v2.0.0 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@0fd9c4a9046055f621fca4bbdccb8eab1fd59fdc # v1.0.1 + uses: phpcsstandards/xmllint-validate@5189514594c8d5f4cf21b7e5af50f54d697973d7 # v2.0.0 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@0fd9c4a9046055f621fca4bbdccb8eab1fd59fdc # v1.0.1 + uses: phpcsstandards/xmllint-validate@5189514594c8d5f4cf21b7e5af50f54d697973d7 # v2.0.0 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@0fd9c4a9046055f621fca4bbdccb8eab1fd59fdc # v1.0.1 + uses: phpcsstandards/xmllint-validate@5189514594c8d5f4cf21b7e5af50f54d697973d7 # v2.0.0 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@0fd9c4a9046055f621fca4bbdccb8eab1fd59fdc # v1.0.1 + uses: phpcsstandards/xmllint-validate@5189514594c8d5f4cf21b7e5af50f54d697973d7 # v2.0.0 with: pattern: "phpunit.xml.dist" xsd-file: "vendor/phpunit/phpunit/schema/9.2.xsd" From 322f84c0d25840ccb1c3aa5805cc63edf4812cdf Mon Sep 17 00:00:00 2001 From: Rodrigo Primo Date: Mon, 6 Jul 2026 03:35:01 -0300 Subject: [PATCH 095/108] WPHookHelper::get_hook_name_param(): add basic tests (#2727) * WPHookHelper::get_hook_name_param(): add basic tests --------- Co-authored-by: Juliette <663378+jrfnl@users.noreply.github.com> --- .../WPHookHelper/GetHookNameParamUnitTest.inc | 24 ++++++ .../WPHookHelper/GetHookNameParamUnitTest.php | 83 +++++++++++++++++++ .../ValidHookNameUnitTest.php | 2 +- 3 files changed, 108 insertions(+), 1 deletion(-) create mode 100644 WordPress/Tests/Helpers/WPHookHelper/GetHookNameParamUnitTest.inc create mode 100644 WordPress/Tests/Helpers/WPHookHelper/GetHookNameParamUnitTest.php diff --git a/WordPress/Tests/Helpers/WPHookHelper/GetHookNameParamUnitTest.inc b/WordPress/Tests/Helpers/WPHookHelper/GetHookNameParamUnitTest.inc new file mode 100644 index 0000000000..e1992e34b8 --- /dev/null +++ b/WordPress/Tests/Helpers/WPHookHelper/GetHookNameParamUnitTest.inc @@ -0,0 +1,24 @@ +getTargetToken( $testMarker, \T_STRING ); + $functionName = self::$phpcsFile->getTokens()[ $stackPtr ]['content']; + $parameters = PassedParameters::getParameters( self::$phpcsFile, $stackPtr ); + + $result = WPHookHelper::get_hook_name_param( $functionName, $parameters ); + + if ( is_array( $result ) ) { + // The details of the parameter are populated by PassedParameters::getParameters(). + // Here we only verify which parameter was selected. + $result = $result['clean']; + } + + $this->assertSame( $expectedResult, $result ); + } + + /** + * Data provider. + * + * @see testGetHookNameParam() + * + * @return array> + */ + public static function dataGetHookNameParam() { + return array( + 'not_a_hook_function' => array( + 'testMarker' => '/* testNotAHookFunction */', + 'expectedResult' => false, + ), + 'hook_name_param_missing' => array( + 'testMarker' => '/* testHookNameParamMissing */', + 'expectedResult' => false, + ), + 'lowercase_name' => array( + 'testMarker' => '/* testLowercaseName */', + 'expectedResult' => "'my_action'", + ), + 'mixedcase_name' => array( + 'testMarker' => '/* testMixedCaseName */', + 'expectedResult' => "'my_filter'", + ), + 'named_parameter' => array( + 'testMarker' => '/* testNamedParameter */', + 'expectedResult' => "'my_action'", + ), + ); + } +} diff --git a/WordPress/Tests/NamingConventions/ValidHookNameUnitTest.php b/WordPress/Tests/NamingConventions/ValidHookNameUnitTest.php index 98649fb620..763760f1c3 100644 --- a/WordPress/Tests/NamingConventions/ValidHookNameUnitTest.php +++ b/WordPress/Tests/NamingConventions/ValidHookNameUnitTest.php @@ -17,7 +17,7 @@ * @since 0.10.0 * @since 0.13.0 Class name changed: this class is now namespaced. * - * @covers \WordPressCS\WordPress\Helpers\WPHookHelper + * @covers \WordPressCS\WordPress\Helpers\WPHookHelper::get_functions * @covers \WordPressCS\WordPress\Sniffs\NamingConventions\ValidHookNameSniff */ final class ValidHookNameUnitTest extends AbstractSniffUnitTest { From 2f2e6722e40259a4c36d73b29317edbb592d8f93 Mon Sep 17 00:00:00 2001 From: Rodrigo Primo Date: Mon, 6 Jul 2026 04:26:19 -0300 Subject: [PATCH 096/108] WP/CronInterval: make callback function name lookup case-insensitive (#2730) * WP/CronInterval: make callback function name lookup case-insensitive The sniff was incorrectly treating callback function names as case-sensitive when trying to locate the callback function definition. This led to false positives when the callback reference case did not match the function declaration case. The fix ensures callback names are compared case-insensitively using `strcasecmp()` when searching for function declarations in the code. * Apply PR review suggestion --- WordPress/Sniffs/WP/CronIntervalSniff.php | 2 +- WordPress/Tests/WP/CronIntervalUnitTest.inc | 5 +++-- WordPress/Tests/WP/CronIntervalUnitTest.php | 3 ++- 3 files changed, 6 insertions(+), 4 deletions(-) diff --git a/WordPress/Sniffs/WP/CronIntervalSniff.php b/WordPress/Sniffs/WP/CronIntervalSniff.php index a93315daa9..886eee073f 100644 --- a/WordPress/Sniffs/WP/CronIntervalSniff.php +++ b/WordPress/Sniffs/WP/CronIntervalSniff.php @@ -291,7 +291,7 @@ private function find_function_by_name( $functionName ) { for ( $ptr = 0; $ptr < $this->phpcsFile->numTokens; $ptr++ ) { if ( \T_FUNCTION === $this->tokens[ $ptr ]['code'] ) { $foundName = FunctionDeclarations::getName( $this->phpcsFile, $ptr ); - if ( $foundName === $functionName ) { + if ( strcasecmp( $foundName, $functionName ) === 0 ) { $functionPtr = $ptr; break; } elseif ( isset( $this->tokens[ $ptr ]['scope_closer'] ) ) { diff --git a/WordPress/Tests/WP/CronIntervalUnitTest.inc b/WordPress/Tests/WP/CronIntervalUnitTest.inc index 5ebc161d4c..b4b81fc714 100644 --- a/WordPress/Tests/WP/CronIntervalUnitTest.inc +++ b/WordPress/Tests/WP/CronIntervalUnitTest.inc @@ -166,7 +166,7 @@ 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, 'ADD_HUNDRED_MINUTE_SCHEDULE' ) ); // Warning: time undetermined. \Add_Filter( 'cron_schedules', array( $this, 'sneaky_fake_wp_constant_schedule' ) ); // Warning: time undetermined. } @@ -284,7 +284,7 @@ class FirstClassCallables { public function add_schedules() { add_filter( 'cron_schedules', $this->cron_weekly_schedule(...) ); // Ok: > 15 min. add_filter( 'cron_schedules', $this->cron_eight_minute_schedule(...) ); // Warning: 8 min. - add_filter( 'cron_schedules', self::cron_weekly_schedule(...) ); // Ok: > 15 min. + add_filter( 'cron_schedules', self::Cron_Weekly_Schedule(...) ); // Ok: > 15 min. add_filter( 'cron_schedules', static::cron_eight_minute_schedule(...) ); // Warning: 8 min. add_filter( 'cron_schedules', [$this, 'cron_weekly_schedule'](...) ); // Ok: > 15 min. add_filter( 'cron_schedules', array($this, 'cron_eight_minute_schedule')(...) ); // Warning: 8 min. @@ -328,6 +328,7 @@ 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', \FIRST_CLASS_SIX_MIN_SCHEDULE(...)); // Warning: 6 min. add_filter( 'cron_schedules', namespace\first_class_six_min_schedule(...)); // Warning: 6 min. /* diff --git a/WordPress/Tests/WP/CronIntervalUnitTest.php b/WordPress/Tests/WP/CronIntervalUnitTest.php index 2417abaf41..4bd6add5b3 100644 --- a/WordPress/Tests/WP/CronIntervalUnitTest.php +++ b/WordPress/Tests/WP/CronIntervalUnitTest.php @@ -69,9 +69,10 @@ public function getWarningList() { 329 => 1, 330 => 1, 331 => 1, - 351 => 1, + 332 => 1, 352 => 1, 353 => 1, + 354 => 1, ); } } From 4ec02fc70b1dd104575f492861cebff24ac8f32c Mon Sep 17 00:00:00 2001 From: Rodrigo Primo Date: Thu, 7 Aug 2025 15:25:04 -0300 Subject: [PATCH 097/108] DB/PreparedSQL: move intentional syntax error test to its own file --- WordPress/Tests/DB/PreparedSQLUnitTest.1.inc | 3 --- WordPress/Tests/DB/PreparedSQLUnitTest.3.inc | 8 ++++++++ 2 files changed, 8 insertions(+), 3 deletions(-) create mode 100644 WordPress/Tests/DB/PreparedSQLUnitTest.3.inc diff --git a/WordPress/Tests/DB/PreparedSQLUnitTest.1.inc b/WordPress/Tests/DB/PreparedSQLUnitTest.1.inc index 1f1a49076c..c6dce05c20 100644 --- a/WordPress/Tests/DB/PreparedSQLUnitTest.1.inc +++ b/WordPress/Tests/DB/PreparedSQLUnitTest.1.inc @@ -142,6 +142,3 @@ echo $wpdb::CONSTANT_NAME; // Not an identifiable method call. $wpdb->{$methodName}('query'); - -// Don't throw an error during live coding. -wpdb::prepare( "SELECT * FROM $wpdb->posts diff --git a/WordPress/Tests/DB/PreparedSQLUnitTest.3.inc b/WordPress/Tests/DB/PreparedSQLUnitTest.3.inc new file mode 100644 index 0000000000..4047216b82 --- /dev/null +++ b/WordPress/Tests/DB/PreparedSQLUnitTest.3.inc @@ -0,0 +1,8 @@ +posts From 9874d4fe9599aa954ba4d6524484a0703c28ea73 Mon Sep 17 00:00:00 2001 From: Rodrigo Primo Date: Wed, 1 Jul 2026 18:46:56 +0000 Subject: [PATCH 098/108] NamingConventions/PrefixAllGlobals: update the functions list based on WP 7.0.0 Based on a scan of WP Core at commit WordPress/wordpress-develop@26b6802 (the WP 7.0.0 release tag) using a preliminary sniff created for issue #1803. --- .../NamingConventions/PrefixAllGlobalsSniff.php | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/WordPress/Sniffs/NamingConventions/PrefixAllGlobalsSniff.php b/WordPress/Sniffs/NamingConventions/PrefixAllGlobalsSniff.php index fb5b1bdb02..85c79f2c09 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.9.0-RC2.} + * {@internal To be updated after every major release. Last updated for WordPress 7.0.0.} * * @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.9.0-RC2.} + * {@internal To be updated after every major release. Last updated for WordPress 7.0.0.} * * @since 3.0.0. * @@ -337,6 +337,11 @@ final class PrefixAllGlobalsSniff extends AbstractFunctionParameterSniff { 'twentytwentytwo_styles' => true, 'twentytwentytwo_support' => true, 'wp_authenticate' => true, + + /* + * The wp_cache_* functions below are conditionally (re)declared as pluggable in wp-includes/cache-compat.php, + * allowing a persistent object cache drop-in to override them. Their primary declarations are in wp-includes/cache.php. + */ 'wp_cache_add_multiple' => true, 'wp_cache_delete_multiple' => true, 'wp_cache_flush_group' => true, @@ -348,6 +353,8 @@ final class PrefixAllGlobalsSniff extends AbstractFunctionParameterSniff { 'wp_cache_set_multiple_salted' => true, 'wp_cache_set_salted' => true, 'wp_cache_supports' => true, + 'wp_cache_switch_to_blog' => true, + 'wp_check_password' => true, 'wp_clear_auth_cookie' => true, 'wp_clearcookie' => true, // Deprecated. @@ -396,7 +403,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.9.0-RC2.} + * {@internal To be updated after every major release. Last updated for WordPress 7.0.0.} * * @since 3.0.0. * From e1911c70ecaf3fe4a7b74f6bdf48e2caaf79980f Mon Sep 17 00:00:00 2001 From: Rodrigo Primo Date: Wed, 1 Jul 2026 18:46:56 +0000 Subject: [PATCH 099/108] WP/ClassNameCase: update the class lists based on WP 7.0.0 Based on a scan of WP Core at commit WordPress/wordpress-develop@26b6802 (the WP 7.0.0 release tag) using a preliminary sniff created for issue #1803. This includes the classes of the new bundled AI Client library (`WordPress\AiClient\*` and its dependencies `WordPress\AiClientDependencies\*`), added as a dedicated `$aiclient_classes` group. Includes tests. --- WordPress/Sniffs/WP/ClassNameCaseSniff.php | 202 ++++++++++++++++++- WordPress/Tests/WP/ClassNameCaseUnitTest.inc | 8 + WordPress/Tests/WP/ClassNameCaseUnitTest.php | 34 ++-- 3 files changed, 221 insertions(+), 23 deletions(-) diff --git a/WordPress/Sniffs/WP/ClassNameCaseSniff.php b/WordPress/Sniffs/WP/ClassNameCaseSniff.php index ef8170e275..8a614cbbe8 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.9.0-RC2.} + * {@internal To be updated after every major release. Last updated for WordPress 7.0.0.} * * @since 3.0.0 * @@ -115,6 +115,12 @@ final class ClassNameCaseSniff extends AbstractClassRestrictionsSniff { 'Walker_Page', 'Walker_PageDropdown', 'WP', + 'WP_AI_Client_Ability_Function_Resolver', + 'WP_AI_Client_Cache', + 'WP_AI_Client_Discovery_Strategy', + 'WP_AI_Client_Event_Dispatcher', + 'WP_AI_Client_HTTP_Client', + 'WP_AI_Client_Prompt_Builder', 'WP_Abilities_Registry', 'WP_Ability', 'WP_Ability_Categories_Registry', @@ -149,6 +155,7 @@ final class ClassNameCaseSniff extends AbstractClassRestrictionsSniff { 'WP_Comment_Query', 'WP_Comments_List_Table', 'WP_Community_Events', + 'WP_Connector_Registry', 'WP_Customize_Background_Image_Control', 'WP_Customize_Background_Image_Setting', 'WP_Customize_Background_Position_Control', @@ -234,6 +241,7 @@ final class ClassNameCaseSniff extends AbstractClassRestrictionsSniff { 'WP_Http_Curl', 'WP_Http_Encoding', 'WP_Http_Streams', + 'WP_Icons_Registry', 'WP_Image_Editor', 'WP_Image_Editor_GD', 'WP_Image_Editor_Imagick', @@ -296,6 +304,7 @@ final class ClassNameCaseSniff extends AbstractClassRestrictionsSniff { 'WP_REST_Font_Families_Controller', 'WP_REST_Global_Styles_Controller', 'WP_REST_Global_Styles_Revisions_Controller', + 'WP_REST_Icons_Controller', 'WP_REST_Menu_Items_Controller', 'WP_REST_Menu_Locations_Controller', 'WP_REST_Menus_Controller', @@ -432,7 +441,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.9.0-RC2.} + * {@internal To be updated after every major release. Last updated for WordPress 7.0.0.} * * @since 3.0.0 * @@ -459,12 +468,179 @@ final class ClassNameCaseSniff extends AbstractClassRestrictionsSniff { 'Twenty_Twenty_One_SVG_Icons', ); + /** + * List of all AI Client classes included in WP Core. + * + * Includes both the WP AI Client classes and the bundled dependencies. + * + * Note: this list will be enhanced in the class constructor. + * + * {@internal To be updated after every major release. Last updated for WordPress 7.0.0.} + * + * @since 3.4.0 + * + * @var string[] The class names in their "proper" case. + * The constructor will add the lowercased class name as a key to each entry. + */ + private $aiclient_classes = array( + // Classes. + 'WordPress\AiClientDependencies\Http\Discovery\ClassDiscovery', + 'WordPress\AiClientDependencies\Http\Discovery\Exception\ClassInstantiationFailedException', + 'WordPress\AiClientDependencies\Http\Discovery\Exception\DiscoveryFailedException', + 'WordPress\AiClientDependencies\Http\Discovery\Exception\NoCandidateFoundException', + 'WordPress\AiClientDependencies\Http\Discovery\Exception\NotFoundException', + 'WordPress\AiClientDependencies\Http\Discovery\Exception\PuliUnavailableException', + 'WordPress\AiClientDependencies\Http\Discovery\Exception\StrategyUnavailableException', + 'WordPress\AiClientDependencies\Http\Discovery\Psr17FactoryDiscovery', + 'WordPress\AiClientDependencies\Http\Discovery\Psr18ClientDiscovery', + 'WordPress\AiClientDependencies\Http\Discovery\Strategy\CommonClassesStrategy', + 'WordPress\AiClientDependencies\Http\Discovery\Strategy\CommonPsr17ClassesStrategy', + 'WordPress\AiClientDependencies\Http\Discovery\Strategy\PuliBetaStrategy', + 'WordPress\AiClientDependencies\Nyholm\Psr7\Factory\HttplugFactory', + 'WordPress\AiClientDependencies\Nyholm\Psr7\Factory\Psr17Factory', + 'WordPress\AiClientDependencies\Nyholm\Psr7\Request', + 'WordPress\AiClientDependencies\Nyholm\Psr7\Response', + 'WordPress\AiClientDependencies\Nyholm\Psr7\ServerRequest', + 'WordPress\AiClientDependencies\Nyholm\Psr7\Stream', + 'WordPress\AiClientDependencies\Nyholm\Psr7\UploadedFile', + 'WordPress\AiClientDependencies\Nyholm\Psr7\Uri', + 'WordPress\AiClient\AiClient', + 'WordPress\AiClient\Builders\MessageBuilder', + 'WordPress\AiClient\Builders\PromptBuilder', + 'WordPress\AiClient\Common\AbstractDataTransferObject', + 'WordPress\AiClient\Common\AbstractEnum', + 'WordPress\AiClient\Common\Exception\InvalidArgumentException', + 'WordPress\AiClient\Common\Exception\RuntimeException', + 'WordPress\AiClient\Common\Exception\TokenLimitReachedException', + 'WordPress\AiClient\Events\AfterGenerateResultEvent', + 'WordPress\AiClient\Events\BeforeGenerateResultEvent', + 'WordPress\AiClient\Files\DTO\File', + 'WordPress\AiClient\Files\Enums\FileTypeEnum', + 'WordPress\AiClient\Files\Enums\MediaOrientationEnum', + 'WordPress\AiClient\Files\ValueObjects\MimeType', + 'WordPress\AiClient\Messages\DTO\Message', + 'WordPress\AiClient\Messages\DTO\MessagePart', + 'WordPress\AiClient\Messages\DTO\ModelMessage', + 'WordPress\AiClient\Messages\DTO\UserMessage', + 'WordPress\AiClient\Messages\Enums\MessagePartChannelEnum', + 'WordPress\AiClient\Messages\Enums\MessagePartTypeEnum', + 'WordPress\AiClient\Messages\Enums\MessageRoleEnum', + 'WordPress\AiClient\Messages\Enums\ModalityEnum', + 'WordPress\AiClient\Operations\DTO\GenerativeAiOperation', + 'WordPress\AiClient\Operations\Enums\OperationStateEnum', + 'WordPress\AiClient\Providers\AbstractProvider', + 'WordPress\AiClient\Providers\ApiBasedImplementation\AbstractApiBasedModel', + 'WordPress\AiClient\Providers\ApiBasedImplementation\AbstractApiBasedModelMetadataDirectory', + 'WordPress\AiClient\Providers\ApiBasedImplementation\AbstractApiProvider', + 'WordPress\AiClient\Providers\ApiBasedImplementation\GenerateTextApiBasedProviderAvailability', + 'WordPress\AiClient\Providers\ApiBasedImplementation\ListModelsApiBasedProviderAvailability', + 'WordPress\AiClient\Providers\DTO\ProviderMetadata', + 'WordPress\AiClient\Providers\DTO\ProviderModelsMetadata', + 'WordPress\AiClient\Providers\Enums\ProviderTypeEnum', + 'WordPress\AiClient\Providers\Enums\ToolTypeEnum', + 'WordPress\AiClient\Providers\Http\Abstracts\AbstractClientDiscoveryStrategy', + 'WordPress\AiClient\Providers\Http\Collections\HeadersCollection', + 'WordPress\AiClient\Providers\Http\DTO\ApiKeyRequestAuthentication', + 'WordPress\AiClient\Providers\Http\DTO\Request', + 'WordPress\AiClient\Providers\Http\DTO\RequestOptions', + 'WordPress\AiClient\Providers\Http\DTO\Response', + 'WordPress\AiClient\Providers\Http\Enums\HttpMethodEnum', + 'WordPress\AiClient\Providers\Http\Enums\RequestAuthenticationMethod', + 'WordPress\AiClient\Providers\Http\Exception\ClientException', + 'WordPress\AiClient\Providers\Http\Exception\NetworkException', + 'WordPress\AiClient\Providers\Http\Exception\RedirectException', + 'WordPress\AiClient\Providers\Http\Exception\ResponseException', + 'WordPress\AiClient\Providers\Http\Exception\ServerException', + 'WordPress\AiClient\Providers\Http\HttpTransporter', + 'WordPress\AiClient\Providers\Http\HttpTransporterFactory', + 'WordPress\AiClient\Providers\Http\Util\ErrorMessageExtractor', + 'WordPress\AiClient\Providers\Http\Util\ResponseUtil', + 'WordPress\AiClient\Providers\Models\DTO\ModelConfig', + 'WordPress\AiClient\Providers\Models\DTO\ModelMetadata', + 'WordPress\AiClient\Providers\Models\DTO\ModelRequirements', + 'WordPress\AiClient\Providers\Models\DTO\RequiredOption', + 'WordPress\AiClient\Providers\Models\DTO\SupportedOption', + 'WordPress\AiClient\Providers\Models\Enums\CapabilityEnum', + 'WordPress\AiClient\Providers\Models\Enums\OptionEnum', + 'WordPress\AiClient\Providers\OpenAiCompatibleImplementation\AbstractOpenAiCompatibleImageGenerationModel', + 'WordPress\AiClient\Providers\OpenAiCompatibleImplementation\AbstractOpenAiCompatibleModelMetadataDirectory', + 'WordPress\AiClient\Providers\OpenAiCompatibleImplementation\AbstractOpenAiCompatibleTextGenerationModel', + 'WordPress\AiClient\Providers\ProviderRegistry', + 'WordPress\AiClient\Results\DTO\Candidate', + 'WordPress\AiClient\Results\DTO\GenerativeAiResult', + 'WordPress\AiClient\Results\DTO\TokenUsage', + 'WordPress\AiClient\Results\Enums\FinishReasonEnum', + 'WordPress\AiClient\Tools\DTO\FunctionCall', + 'WordPress\AiClient\Tools\DTO\FunctionDeclaration', + 'WordPress\AiClient\Tools\DTO\FunctionResponse', + 'WordPress\AiClient\Tools\DTO\WebSearch', + + // Interfaces. + 'WordPress\AiClientDependencies\Http\Discovery\Exception', + 'WordPress\AiClientDependencies\Http\Discovery\Strategy\DiscoveryStrategy', + 'WordPress\AiClientDependencies\Psr\EventDispatcher\EventDispatcherInterface', + 'WordPress\AiClientDependencies\Psr\Http\Client\ClientExceptionInterface', + 'WordPress\AiClientDependencies\Psr\Http\Client\ClientInterface', + 'WordPress\AiClientDependencies\Psr\Http\Client\NetworkExceptionInterface', + 'WordPress\AiClientDependencies\Psr\Http\Client\RequestExceptionInterface', + 'WordPress\AiClientDependencies\Psr\Http\Message\MessageInterface', + 'WordPress\AiClientDependencies\Psr\Http\Message\RequestFactoryInterface', + 'WordPress\AiClientDependencies\Psr\Http\Message\RequestInterface', + 'WordPress\AiClientDependencies\Psr\Http\Message\ResponseFactoryInterface', + 'WordPress\AiClientDependencies\Psr\Http\Message\ResponseInterface', + 'WordPress\AiClientDependencies\Psr\Http\Message\ServerRequestFactoryInterface', + 'WordPress\AiClientDependencies\Psr\Http\Message\ServerRequestInterface', + 'WordPress\AiClientDependencies\Psr\Http\Message\StreamFactoryInterface', + 'WordPress\AiClientDependencies\Psr\Http\Message\StreamInterface', + 'WordPress\AiClientDependencies\Psr\Http\Message\UploadedFileFactoryInterface', + 'WordPress\AiClientDependencies\Psr\Http\Message\UploadedFileInterface', + 'WordPress\AiClientDependencies\Psr\Http\Message\UriFactoryInterface', + 'WordPress\AiClientDependencies\Psr\Http\Message\UriInterface', + 'WordPress\AiClientDependencies\Psr\SimpleCache\CacheInterface', + 'WordPress\AiClient\Common\Contracts\AiClientExceptionInterface', + 'WordPress\AiClient\Common\Contracts\CachesDataInterface', + 'WordPress\AiClient\Common\Contracts\WithArrayTransformationInterface', + 'WordPress\AiClient\Common\Contracts\WithJsonSchemaInterface', + 'WordPress\AiClient\Operations\Contracts\OperationInterface', + 'WordPress\AiClient\Providers\ApiBasedImplementation\Contracts\ApiBasedModelInterface', + 'WordPress\AiClient\Providers\Contracts\ModelMetadataDirectoryInterface', + 'WordPress\AiClient\Providers\Contracts\ProviderAvailabilityInterface', + 'WordPress\AiClient\Providers\Contracts\ProviderInterface', + 'WordPress\AiClient\Providers\Contracts\ProviderOperationsHandlerInterface', + 'WordPress\AiClient\Providers\Contracts\ProviderWithOperationsHandlerInterface', + 'WordPress\AiClient\Providers\Http\Contracts\ClientWithOptionsInterface', + 'WordPress\AiClient\Providers\Http\Contracts\HttpTransporterInterface', + 'WordPress\AiClient\Providers\Http\Contracts\RequestAuthenticationInterface', + 'WordPress\AiClient\Providers\Http\Contracts\WithHttpTransporterInterface', + 'WordPress\AiClient\Providers\Http\Contracts\WithRequestAuthenticationInterface', + 'WordPress\AiClient\Providers\Models\Contracts\ModelInterface', + 'WordPress\AiClient\Providers\Models\ImageGeneration\Contracts\ImageGenerationModelInterface', + 'WordPress\AiClient\Providers\Models\ImageGeneration\Contracts\ImageGenerationOperationModelInterface', + 'WordPress\AiClient\Providers\Models\SpeechGeneration\Contracts\SpeechGenerationModelInterface', + 'WordPress\AiClient\Providers\Models\SpeechGeneration\Contracts\SpeechGenerationOperationModelInterface', + 'WordPress\AiClient\Providers\Models\TextGeneration\Contracts\TextGenerationModelInterface', + 'WordPress\AiClient\Providers\Models\TextGeneration\Contracts\TextGenerationOperationModelInterface', + 'WordPress\AiClient\Providers\Models\TextToSpeechConversion\Contracts\TextToSpeechConversionModelInterface', + 'WordPress\AiClient\Providers\Models\TextToSpeechConversion\Contracts\TextToSpeechConversionOperationModelInterface', + 'WordPress\AiClient\Providers\Models\VideoGeneration\Contracts\VideoGenerationModelInterface', + 'WordPress\AiClient\Providers\Models\VideoGeneration\Contracts\VideoGenerationOperationModelInterface', + 'WordPress\AiClient\Results\Contracts\ResultInterface', + + // Traits. + 'WordPress\AiClientDependencies\Nyholm\Psr7\MessageTrait', + 'WordPress\AiClientDependencies\Nyholm\Psr7\RequestTrait', + 'WordPress\AiClientDependencies\Nyholm\Psr7\StreamTrait', + 'WordPress\AiClient\Common\Traits\WithDataCachingTrait', + 'WordPress\AiClient\Providers\Http\Traits\WithHttpTransporterTrait', + 'WordPress\AiClient\Providers\Http\Traits\WithRequestAuthenticationTrait', + ); + /** * List of all AVIF classes included in WP Core. * * Note: this list will be enhanced in the class constructor. * - * {@internal To be updated after every major release. Last updated for WordPress 6.9.0-RC2.} + * {@internal To be updated after every major release. Last updated for WordPress 7.0.0.} * * @since 3.1.0 * @@ -486,7 +662,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.9.0-RC2.} + * {@internal To be updated after every major release. Last updated for WordPress 7.0.0.} * * @since 3.0.0 * @@ -522,7 +698,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.9.0-RC2.} + * {@internal To be updated after every major release. Last updated for WordPress 7.0.0.} * * @since 3.0.0 * @@ -547,7 +723,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.9.0-RC2.} + * {@internal To be updated after every major release. Last updated for WordPress 7.0.0.} * * @since 3.0.0 * @@ -691,7 +867,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.9.0-RC2.} + * {@internal To be updated after every major release. Last updated for WordPress 7.0.0.} * * @since 3.0.0 * @@ -812,6 +988,17 @@ final class ClassNameCaseSniff extends AbstractClassRestrictionsSniff { */ private $wp_themes_classes_lc = array(); + /** + * List of all AI Client classes in lowercase. + * + * This array is automatically generated in the class constructor based on the $aiclient_classes property. + * + * @since 3.4.0 + * + * @var string[] The class names in lowercase. + */ + private $aiclient_classes_lc = array(); + /** * List of all AVIF classes in lowercase. * @@ -879,6 +1066,7 @@ final class ClassNameCaseSniff extends AbstractClassRestrictionsSniff { private $class_groups = array( 'wp_classes', 'wp_themes_classes', + 'aiclient_classes', 'avif_classes', 'getid3_classes', 'phpmailer_classes', diff --git a/WordPress/Tests/WP/ClassNameCaseUnitTest.inc b/WordPress/Tests/WP/ClassNameCaseUnitTest.inc index 70af2b1484..4ddaed0bea 100644 --- a/WordPress/Tests/WP/ClassNameCaseUnitTest.inc +++ b/WordPress/Tests/WP/ClassNameCaseUnitTest.inc @@ -91,3 +91,11 @@ MyNamespace\Avifinfo\CHAN_PROP::prepare_query(); \MyNamespace\Avifinfo\features::prepare_query(); namespace\Sub\AVIFINFO\parser::prepare_query(); namespace\AVIFINFO\TILE::prepare_query(); // Warning. + +/* + * AI Client classes. + */ +$obj = new WP_AI_Client_Cache(); +$obj = new \WP_ai_client_cache(); // Warning. +$obj = new \WordPress\AiClient\AiClient(); +$obj = new WordPress\AiClient\aiclient(); // Warning. diff --git a/WordPress/Tests/WP/ClassNameCaseUnitTest.php b/WordPress/Tests/WP/ClassNameCaseUnitTest.php index 62f9f6b179..f34d832c2d 100644 --- a/WordPress/Tests/WP/ClassNameCaseUnitTest.php +++ b/WordPress/Tests/WP/ClassNameCaseUnitTest.php @@ -36,22 +36,24 @@ public function getErrorList() { */ public function getWarningList() { return array( - 37 => 1, - 38 => 1, - 40 => 1, - 42 => 1, - 43 => 1, - 46 => 1, - 47 => 1, - 48 => 1, - 49 => 1, - 70 => 1, - 79 => 1, - 83 => 1, - 84 => 1, - 88 => 1, - 89 => 1, - 93 => 1, + 37 => 1, + 38 => 1, + 40 => 1, + 42 => 1, + 43 => 1, + 46 => 1, + 47 => 1, + 48 => 1, + 49 => 1, + 70 => 1, + 79 => 1, + 83 => 1, + 84 => 1, + 88 => 1, + 89 => 1, + 93 => 1, + 99 => 1, + 101 => 1, ); } } From a4e1404d9b835c257da6444b7e7f3bb484cdc4ea Mon Sep 17 00:00:00 2001 From: Rodrigo Primo Date: Wed, 1 Jul 2026 18:46:56 +0000 Subject: [PATCH 100/108] WP/DeprecatedFunctions: update the functions list based on WP 7.0.0 Based on a scan of WP Core at commit WordPress/wordpress-develop@26b6802 (the WP 7.0.0 release tag) using a preliminary sniff created for issue #1803. Includes tests. --- WordPress/Sniffs/WP/DeprecatedFunctionsSniff.php | 16 +++++++++++++++- .../Tests/WP/DeprecatedFunctionsUnitTest.1.inc | 4 ++++ .../Tests/WP/DeprecatedFunctionsUnitTest.php | 5 +++-- 3 files changed, 22 insertions(+), 3 deletions(-) diff --git a/WordPress/Sniffs/WP/DeprecatedFunctionsSniff.php b/WordPress/Sniffs/WP/DeprecatedFunctionsSniff.php index 6b74d6294b..76647d9aff 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.9.0-RC2.} + * {@internal To be updated after every major release. Last updated for WordPress 7.0.0.} * * @var array */ @@ -1720,6 +1720,20 @@ final class DeprecatedFunctionsSniff extends AbstractFunctionRestrictionsSniff { 'alt' => 'wp_enqueue_img_auto_sizes_contain_css_fix()', 'version' => '6.9.0', ), + + // WP 7.0.0. + 'addslashes_gpc' => array( + 'alt' => 'wp_slash()', + 'version' => '7.0.0', + ), + 'block_core_navigation_block_contains_core_navigation' => array( + 'alt' => 'block_core_navigation_block_tree_has_block_type()', + 'version' => '7.0.0', + ), + 'wp_sanitize_script_attributes' => array( + 'alt' => 'wp_get_script_tag() or wp_get_inline_script_tag()', + 'version' => '7.0.0', + ), ); /** diff --git a/WordPress/Tests/WP/DeprecatedFunctionsUnitTest.1.inc b/WordPress/Tests/WP/DeprecatedFunctionsUnitTest.1.inc index 57a44658ef..0c2e91cd68 100644 --- a/WordPress/Tests/WP/DeprecatedFunctionsUnitTest.1.inc +++ b/WordPress/Tests/WP/DeprecatedFunctionsUnitTest.1.inc @@ -444,3 +444,7 @@ wp_add_editor_classic_theme_styles(); /* ============ WP 6.9 ============ */ seems_utf8(); wp_print_auto_sizes_contain_css_fix(); +/* ============ WP 7.0 ============ */ +addslashes_gpc(); +block_core_navigation_block_contains_core_navigation(); +wp_sanitize_script_attributes(); diff --git a/WordPress/Tests/WP/DeprecatedFunctionsUnitTest.php b/WordPress/Tests/WP/DeprecatedFunctionsUnitTest.php index 4e36fa091b..595d5b9cc1 100644 --- a/WordPress/Tests/WP/DeprecatedFunctionsUnitTest.php +++ b/WordPress/Tests/WP/DeprecatedFunctionsUnitTest.php @@ -113,14 +113,15 @@ public function getWarningList( $testFile = '' ) { switch ( $testFile ) { case 'DeprecatedFunctionsUnitTest.1.inc': $start_line = 430; - $end_line = 446; + $end_line = 450; $warnings = array_fill( $start_line, ( ( $end_line - $start_line ) + 1 ), 1 ); // Unset the lines related to version comments. unset( $warnings[432], $warnings[442], - $warnings[444] + $warnings[444], + $warnings[447] ); return $warnings; From 1c527d455def159a1bbd31b3b37f0bd9b60f5dc8 Mon Sep 17 00:00:00 2001 From: Rodrigo Primo Date: Wed, 1 Jul 2026 18:46:56 +0000 Subject: [PATCH 101/108] Various sniffs: update docs to document when the lists were last verified against WP Core WP 7.0.0 introduced no new deprecated classes, deprecated parameters, deprecated parameter values, reserved post types, pluggable classes/constants, WP time constants or capabilities, so for those sniffs only the "last verified" marker was updated. --- WordPress/Sniffs/NamingConventions/ValidPostTypeSlugSniff.php | 2 +- WordPress/Sniffs/WP/CapabilitiesSniff.php | 2 +- WordPress/Sniffs/WP/DeprecatedClassesSniff.php | 2 +- WordPress/Sniffs/WP/DeprecatedParameterValuesSniff.php | 2 +- WordPress/Sniffs/WP/DeprecatedParametersSniff.php | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/WordPress/Sniffs/NamingConventions/ValidPostTypeSlugSniff.php b/WordPress/Sniffs/NamingConventions/ValidPostTypeSlugSniff.php index f5cb955b03..384b74e74e 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.9.0-RC2.} + * {@internal To be updated after every major release. Last updated for WordPress 7.0.0.} * * @since 2.2.0 * diff --git a/WordPress/Sniffs/WP/CapabilitiesSniff.php b/WordPress/Sniffs/WP/CapabilitiesSniff.php index 758359f9c6..6e9cb8fad9 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.9.0-RC2.} + * {@internal To be updated after every major release. Last updated for WordPress 7.0.0.} * * @since 3.0.0 * diff --git a/WordPress/Sniffs/WP/DeprecatedClassesSniff.php b/WordPress/Sniffs/WP/DeprecatedClassesSniff.php index eec0d8f7cc..38232b5e3c 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.9.0-RC2.} + * {@internal To be updated after every major release. Last updated for WordPress 7.0.0.} * * @var array */ diff --git a/WordPress/Sniffs/WP/DeprecatedParameterValuesSniff.php b/WordPress/Sniffs/WP/DeprecatedParameterValuesSniff.php index 1eefb6596c..b88826d990 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.9.0-RC2.} + * {@internal To be updated after every major release. Last updated for WordPress 7.0.0.} * * @since 1.0.0 * @since 3.0.0 The format of the value has changed to support function calls diff --git a/WordPress/Sniffs/WP/DeprecatedParametersSniff.php b/WordPress/Sniffs/WP/DeprecatedParametersSniff.php index 265035f249..2133e3903d 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.9.0-RC2.} + * {@internal To be updated after every major release. Last updated for WordPress 7.0.0.} * * @since 0.12.0 * From 43dc9bebc8ca8226ea8c80736602a9c55e1c3a48 Mon Sep 17 00:00:00 2001 From: Rodrigo Primo Date: Thu, 4 Dec 2025 16:11:38 -0300 Subject: [PATCH 102/108] ArrayWalkingFunctionsHelper: add tests for is_array_walking_function() and get_callback_parameter() --- .../GetCallbackParameterUnitTest.inc | 21 +++++ .../GetCallbackParameterUnitTest.php | 85 +++++++++++++++++++ .../IsArrayWalkingFunctionUnitTest.php | 64 ++++++++++++++ 3 files changed, 170 insertions(+) create mode 100644 WordPress/Tests/Helpers/ArrayWalkingFunctionsHelper/GetCallbackParameterUnitTest.inc create mode 100644 WordPress/Tests/Helpers/ArrayWalkingFunctionsHelper/GetCallbackParameterUnitTest.php create mode 100644 WordPress/Tests/Helpers/ArrayWalkingFunctionsHelper/IsArrayWalkingFunctionUnitTest.php diff --git a/WordPress/Tests/Helpers/ArrayWalkingFunctionsHelper/GetCallbackParameterUnitTest.inc b/WordPress/Tests/Helpers/ArrayWalkingFunctionsHelper/GetCallbackParameterUnitTest.inc new file mode 100644 index 0000000000..731fa04732 --- /dev/null +++ b/WordPress/Tests/Helpers/ArrayWalkingFunctionsHelper/GetCallbackParameterUnitTest.inc @@ -0,0 +1,21 @@ +assertFalse( ArrayWalkingFunctionsHelper::get_callback_parameter( self::$phpcsFile, -1 ) ); + } + + /** + * Test get_callback_parameter() returns the callback parameter info or false. + * + * @dataProvider dataGetCallbackParameter + * + * @param string $testMarker The comment which prefaces the target token in the test file. + * @param string|false $expectedContent The expected 'clean' content of the callback parameter, + * or false if the method should return false. + * + * @return void + */ + public function testGetCallbackParameter( $testMarker, $expectedContent ) { + $stackPtr = $this->getTargetToken( $testMarker, array( \T_STRING, \T_NAME_FULLY_QUALIFIED ) ); + $result = ArrayWalkingFunctionsHelper::get_callback_parameter( self::$phpcsFile, $stackPtr ); + + if ( false === $expectedContent ) { + $this->assertFalse( $result ); + } else { + $this->assertSame( $expectedContent, $result['clean'] ); + } + } + + /** + * Data provider. + * + * @see testGetCallbackParameter() + * + * @return array> + */ + public static function dataGetCallbackParameter() { + return array( + // Cases where false should be returned. + 'not_array_walking_function' => array( + 'testMarker' => '/* testNotArrayWalkingFunction */', + 'expectedContent' => false, + ), + 'callback_param_missing' => array( + 'testMarker' => '/* testCallbackParamMissing */', + 'expectedContent' => false, + ), + + // Cases where the callback parameter should be returned. + 'array_map_callback' => array( + 'testMarker' => '/* testArrayMapCallback */', + 'expectedContent' => "'sanitize_text_field'", + ), + 'map_deep_mixed_case' => array( + 'testMarker' => '/* testMapDeepMixedCase */', + 'expectedContent' => "'esc_html'", + ), + ); + } +} diff --git a/WordPress/Tests/Helpers/ArrayWalkingFunctionsHelper/IsArrayWalkingFunctionUnitTest.php b/WordPress/Tests/Helpers/ArrayWalkingFunctionsHelper/IsArrayWalkingFunctionUnitTest.php new file mode 100644 index 0000000000..16f3e0ac35 --- /dev/null +++ b/WordPress/Tests/Helpers/ArrayWalkingFunctionsHelper/IsArrayWalkingFunctionUnitTest.php @@ -0,0 +1,64 @@ +assertSame( + $expectedResult, + ArrayWalkingFunctionsHelper::is_array_walking_function( $functionName ) + ); + } + + /** + * Data provider. + * + * @see testIsArrayWalkingFunction() + * + * @return array> + */ + public static function dataIsArrayWalkingFunction() { + return array( + 'lowercase_name' => array( + 'functionName' => 'array_map', + 'expectedResult' => true, + ), + 'mixedcase_name' => array( + 'functionName' => 'mAp_DeEp', + 'expectedResult' => true, + ), + 'not_an_array_walking_function' => array( + 'functionName' => 'array_filter', + 'expectedResult' => false, + ), + ); + } +} From e1e226083bb6a8b86a5a8d2cffbd05739f911522 Mon Sep 17 00:00:00 2001 From: Rodrigo Primo Date: Mon, 6 Jul 2026 19:57:30 +0000 Subject: [PATCH 103/108] WPDBTrait::is_wpdb_method_call(): fix false positives for static method calls to non-global classes called wpdb The `DB/PreparedSQL` and `DB/PreparedSQLPlaceholders` sniffs were producing false positives for static method calls to a class named `wpdb` that is preceded by a namespace. The root cause was in `WPDBTrait::is_wpdb_method_call()`, which did not check whether the `wpdb` token was namespaced before treating it as a call to the global `wpdb` class. The fix makes the method return `false` when the `wpdb` token is a namespaced call to a non-global `wpdb` class. Fixes 2710 --- WordPress/Helpers/WPDBTrait.php | 6 ++++++ .../Tests/DB/PreparedSQLPlaceholdersUnitTest.inc | 14 ++++++++++++++ .../Tests/DB/PreparedSQLPlaceholdersUnitTest.php | 4 ++++ WordPress/Tests/DB/PreparedSQLUnitTest.1.inc | 15 +++++++++++++++ WordPress/Tests/DB/PreparedSQLUnitTest.php | 2 ++ 5 files changed, 41 insertions(+) diff --git a/WordPress/Helpers/WPDBTrait.php b/WordPress/Helpers/WPDBTrait.php index d2f729da5b..5843ea4225 100644 --- a/WordPress/Helpers/WPDBTrait.php +++ b/WordPress/Helpers/WPDBTrait.php @@ -13,6 +13,7 @@ use PHP_CodeSniffer\Util\Tokens; use PHPCSUtils\BackCompat\BCFile; use PHPCSUtils\Tokens\Collections; +use WordPressCS\WordPress\Helpers\ContextHelper; /** * Helper utilities for sniffs which examine WPDB method calls. @@ -79,6 +80,11 @@ final protected function is_wpdb_method_call( File $phpcsFile, $stackPtr, array return false; } + // If calling the method statically, ensure we are calling the global wpdb class. + if ( \T_STRING === $tokens[ $stackPtr ]['code'] && ContextHelper::is_token_namespaced( $phpcsFile, $stackPtr ) ) { + return false; + } + $methodPtr = $phpcsFile->findNext( Tokens::$emptyTokens, ( $is_object_call + 1 ), null, true, null, true ); if ( false === $methodPtr ) { return false; diff --git a/WordPress/Tests/DB/PreparedSQLPlaceholdersUnitTest.inc b/WordPress/Tests/DB/PreparedSQLPlaceholdersUnitTest.inc index 601877bfa4..791df5a509 100644 --- a/WordPress/Tests/DB/PreparedSQLPlaceholdersUnitTest.inc +++ b/WordPress/Tests/DB/PreparedSQLPlaceholdersUnitTest.inc @@ -518,3 +518,17 @@ $where = $wpdb->prepare( */ $callback = $wpdb->prepare(...); // OK. +/* + * Safeguard correct handling of all types of namespaced calls to the wpdb::prepare() method. + * + * Note that calling wpdb::prepare() statically will result in an error. Still, the tests are included here since the + * sniff handles those calls. + * + * Related to: https://github.com/WordPress/WordPress-Coding-Standards/issues/2710. + */ +$sql = \wpdb::prepare( "SELECT * FROM $wpdb->users WHERE id = %d AND user_login = %s" ); // Error. +$sql = \WPDB::prepare( "SELECT * FROM $wpdb->users WHERE id = %d AND user_login = %s" ); // Error. +$sql = MyNamespace\wpdb::prepare( "SELECT * FROM $wpdb->users WHERE id = %d AND user_login = %s" ); // OK. +$sql = \MyNamespace\WPDB::prepare( "SELECT * FROM $wpdb->users WHERE id = %d AND user_login = %s" ); // OK. +$sql = namespace\wpdb::prepare( "SELECT * FROM $wpdb->users WHERE id = %d AND user_login = %s" ); // Ok. The sniff should start flagging this once it can resolve relative namespaces as this test file is not namespaced. +$sql = namespace\Sub\wpdb::prepare( "SELECT * FROM $wpdb->users WHERE id = %d AND user_login = %s" ); // OK. diff --git a/WordPress/Tests/DB/PreparedSQLPlaceholdersUnitTest.php b/WordPress/Tests/DB/PreparedSQLPlaceholdersUnitTest.php index df0bc753bf..916567cf3e 100644 --- a/WordPress/Tests/DB/PreparedSQLPlaceholdersUnitTest.php +++ b/WordPress/Tests/DB/PreparedSQLPlaceholdersUnitTest.php @@ -106,6 +106,10 @@ public function getErrorList() { // Named parameter support. 418 => 1, + + // Fully qualified calls to the global class wpdb. + 529 => 1, + 530 => 1, ); } diff --git a/WordPress/Tests/DB/PreparedSQLUnitTest.1.inc b/WordPress/Tests/DB/PreparedSQLUnitTest.1.inc index c6dce05c20..ac97d71ce8 100644 --- a/WordPress/Tests/DB/PreparedSQLUnitTest.1.inc +++ b/WordPress/Tests/DB/PreparedSQLUnitTest.1.inc @@ -142,3 +142,18 @@ echo $wpdb::CONSTANT_NAME; // Not an identifiable method call. $wpdb->{$methodName}('query'); + +/* + * Safeguard correct handling of all types of namespaced calls to the wpdb::prepare() method. + * + * Note that calling wpdb::prepare() statically will result in an error. Still, the tests are included here since the + * sniff handles those calls. + * + * Related to: https://github.com/WordPress/WordPress-Coding-Standards/issues/2710. + */ +\wpdb::prepare( "SELECT * FROM $wpdb->posts WHERE post_title LIKE '" . foo() . "';" ); // Bad. +\WPDB::prepare( "SELECT * FROM $wpdb->posts WHERE post_title LIKE '" . foo() . "';" ); // Bad. +MyNamespace\wpdb::prepare( "SELECT * FROM $wpdb->posts WHERE post_title LIKE '" . foo() . "';" ); // Ok. +\MyNamespace\WPDB::prepare( "SELECT * FROM $wpdb->posts WHERE post_title LIKE '" . foo() . "';" ); // Ok. +namespace\wpdb::prepare( "SELECT * FROM $wpdb->posts WHERE post_title LIKE '" . foo() . "';" ); // Ok. The sniff should start flagging this once it can resolve relative namespaces as this test file is not namespaced. +namespace\Sub\wpdb::prepare( "SELECT * FROM $wpdb->posts WHERE post_title LIKE '" . foo() . "';" ); // Ok. diff --git a/WordPress/Tests/DB/PreparedSQLUnitTest.php b/WordPress/Tests/DB/PreparedSQLUnitTest.php index 0a296ff984..8d887dd044 100644 --- a/WordPress/Tests/DB/PreparedSQLUnitTest.php +++ b/WordPress/Tests/DB/PreparedSQLUnitTest.php @@ -66,6 +66,8 @@ public function getErrorList( $testFile = '' ) { 124 => 1, 128 => 1, 132 => 2, + 154 => 1, + 155 => 1, ); case 'PreparedSQLUnitTest.2.inc': From 4920864bdbe36218824c47fefa64f9f15aebef9f Mon Sep 17 00:00:00 2001 From: Rodrigo Primo Date: Thu, 2 Jul 2026 12:44:33 +0000 Subject: [PATCH 104/108] Update the minimum_wp_version to WP 6.7 The minimum version should be three versions behind the latest WP release. With WP 7.0 released, it should now become 6.7. Includes updating the tests to match. --- WordPress/Helpers/MinimumWPVersionTrait.php | 2 +- .../Tests/WP/DeprecatedFunctionsUnitTest.1.inc | 6 +++--- .../Tests/WP/DeprecatedFunctionsUnitTest.php | 8 ++++---- .../WP/DeprecatedParameterValuesUnitTest.php | 17 ++++------------- .../Tests/WP/DeprecatedParametersUnitTest.inc | 4 ++-- .../Tests/WP/DeprecatedParametersUnitTest.php | 3 +-- 6 files changed, 15 insertions(+), 25 deletions(-) diff --git a/WordPress/Helpers/MinimumWPVersionTrait.php b/WordPress/Helpers/MinimumWPVersionTrait.php index b651e80bb6..2cc6f0b120 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.6'; + private $default_minimum_wp_version = '6.7'; /** * 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 0c2e91cd68..34d92a3b62 100644 --- a/WordPress/Tests/WP/DeprecatedFunctionsUnitTest.1.inc +++ b/WordPress/Tests/WP/DeprecatedFunctionsUnitTest.1.inc @@ -422,13 +422,13 @@ wp_update_https_detection_errors(); block_core_file_ensure_interactivity_dependency(); block_core_image_ensure_interactivity_dependency(); block_core_query_ensure_interactivity_dependency(); +/* ============ WP 6.6 ============ */ +wp_interactivity_process_directives_of_interactive_blocks(); +wp_render_elements_support(); /* * Warning. */ -/* ============ WP 6.6 ============ */ -wp_interactivity_process_directives_of_interactive_blocks(); -wp_render_elements_support(); /* ============ WP 6.7 ============ */ current_user_can_for_blog(); wp_create_block_style_variation_instance_name(); diff --git a/WordPress/Tests/WP/DeprecatedFunctionsUnitTest.php b/WordPress/Tests/WP/DeprecatedFunctionsUnitTest.php index 595d5b9cc1..451d635219 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 = 424; + $end_line = 427; $errors = array_fill( $start_line, ( ( $end_line - $start_line ) + 1 ), 1 ); // Unset the lines related to version comments. @@ -85,7 +85,8 @@ public function getErrorList( $testFile = '' ) { $errors[383], $errors[386], $errors[410], - $errors[421] + $errors[421], + $errors[425] ); return $errors; @@ -112,13 +113,12 @@ public function getErrorList( $testFile = '' ) { public function getWarningList( $testFile = '' ) { switch ( $testFile ) { case 'DeprecatedFunctionsUnitTest.1.inc': - $start_line = 430; + $start_line = 433; $end_line = 450; $warnings = array_fill( $start_line, ( ( $end_line - $start_line ) + 1 ), 1 ); // Unset the lines related to version comments. unset( - $warnings[432], $warnings[442], $warnings[444], $warnings[447] diff --git a/WordPress/Tests/WP/DeprecatedParameterValuesUnitTest.php b/WordPress/Tests/WP/DeprecatedParameterValuesUnitTest.php index 275191902e..958738ab87 100644 --- a/WordPress/Tests/WP/DeprecatedParameterValuesUnitTest.php +++ b/WordPress/Tests/WP/DeprecatedParameterValuesUnitTest.php @@ -56,6 +56,8 @@ public function getErrorList( $testFile = '' ) { 49 => 1, 50 => 1, 51 => 1, + 55 => 1, + 56 => 1, 61 => 1, ); @@ -67,20 +69,9 @@ public function getErrorList( $testFile = '' ) { /** * 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( $testFile = '' ) { - switch ( $testFile ) { - case 'DeprecatedParameterValuesUnitTest.1.inc': - return array( - 55 => 1, - 56 => 1, - ); - - default: - return array(); - } + public function getWarningList() { + return array(); } } diff --git a/WordPress/Tests/WP/DeprecatedParametersUnitTest.inc b/WordPress/Tests/WP/DeprecatedParametersUnitTest.inc index 06a30cf56f..80d5026d86 100644 --- a/WordPress/Tests/WP/DeprecatedParametersUnitTest.inc +++ b/WordPress/Tests/WP/DeprecatedParametersUnitTest.inc @@ -105,7 +105,7 @@ wp_upload_bits( '', 'deprecated' ); xfn_check( '', '', 'deprecated' ); global_terms( $foo, 'deprecated' ); 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'); + +// All will give an WARNING as they have been deprecated after WP 6.7. _wp_can_use_pcre_u('deprecated'); diff --git a/WordPress/Tests/WP/DeprecatedParametersUnitTest.php b/WordPress/Tests/WP/DeprecatedParametersUnitTest.php index 0b396055b1..51c9e11751 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 = 51; - $end_line = 107; + $end_line = 108; $errors = array_fill( $start_line, ( ( $end_line - $start_line ) + 1 ), 1 ); $errors[22] = 1; @@ -55,7 +55,6 @@ public function getErrorList() { */ public function getWarningList() { return array( - 110 => 1, 111 => 1, ); } From d69ed7fb6d307604c50e2902138cb66306261198 Mon Sep 17 00:00:00 2001 From: jrfnl Date: Fri, 10 Jul 2026 19:53:37 +0200 Subject: [PATCH 105/108] Composer: raise the minimum supported PHPCS version to 3.13.5 While not strictly _necessary_, raising the minimum supported PHPCS and PHPCSUtils versions buys us improved support for PHP 8.4 and 8.5, both runtime support, as well as improved syntax support. --- .github/CONTRIBUTING.md | 4 ++-- composer.json | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/CONTRIBUTING.md b/.github/CONTRIBUTING.md index 29909cd49f..80032cba98 100644 --- a/.github/CONTRIBUTING.md +++ b/.github/CONTRIBUTING.md @@ -62,8 +62,8 @@ When you introduce new `public` sniff properties, or your sniff extends a class ### Pre-requisites * WordPress-Coding-Standards -* PHP_CodeSniffer 3.13.4 or higher -* PHPCSUtils 1.1.0 or higher +* PHP_CodeSniffer 3.13.5 or higher +* PHPCSUtils 1.2.2 or higher * PHPCSExtra 1.5.0 or higher * PHPUnit 8.x - 9.x diff --git a/composer.json b/composer.json index 898bf88b73..4961107d8d 100644 --- a/composer.json +++ b/composer.json @@ -21,8 +21,8 @@ "ext-libxml": "*", "ext-tokenizer": "*", "ext-xmlreader": "*", - "squizlabs/php_codesniffer": "^3.13.4", - "phpcsstandards/phpcsutils": "^1.1.0", + "squizlabs/php_codesniffer": "^3.13.5", + "phpcsstandards/phpcsutils": "^1.2.2", "phpcsstandards/phpcsextra": "^1.5.0" }, "require-dev": { From 00931f5b9701ac94fb5202764ddd3077bc09807d Mon Sep 17 00:00:00 2001 From: Rodrigo Primo Date: Mon, 13 Jul 2026 10:57:30 -0300 Subject: [PATCH 106/108] Update minimum_wp_version in phpcs.xml.dist.sample This commit updates the example `phpcs.xml.dist.sample` file to reflect that WP 6.7 is now the minimum supported version (three versions behind the latest release). --- phpcs.xml.dist.sample | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/phpcs.xml.dist.sample b/phpcs.xml.dist.sample index 60b9c27e9d..9bed296db1 100644 --- a/phpcs.xml.dist.sample +++ b/phpcs.xml.dist.sample @@ -100,7 +100,7 @@ the wiki: https://github.com/WordPress/WordPress-Coding-Standards/wiki/Customizable-sniff-properties --> - + From 2b16e0193ec09a9463d4ebe6b8dd9996fd4c432f Mon Sep 17 00:00:00 2001 From: jrfnl Date: Wed, 28 Jan 2026 08:53:31 +0100 Subject: [PATCH 107/108] Changelog for the release of WordPressCS 3.4.0 Release date tentatively set to Monday July 13th (with an option to delay till Thursday). Note: as Rodrigo is now a co-maintainer, I've not included "props" for his contributions. We may want to check if our policy regarding this (explicit props for contributors, but not for maintainers) needs to be documented somewhere. --- CHANGELOG.md | 97 +++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 96 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index d08d7fbc7c..9fa867d25a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,12 +2,94 @@ All notable changes to this project will be documented in this file. -This projects adheres to [Semantic Versioning](https://semver.org/) and [Keep a CHANGELOG](https://keepachangelog.com/). +This project adheres to [Semantic Versioning](https://semver.org/) and [Keep a CHANGELOG](https://keepachangelog.com/). ## [Unreleased] _No documentation available about unreleased changes as of yet._ +## [3.4.0] - 2026-07-16 + +We're happy to welcome [@rodrigoprimo] as co-maintainer of WordPressCS as of this release. + +### Added +- `WordPress.Arrays.ArrayDeclarationSpacing`: new `allow_single_item_single_line_explicit_key_arrays` property to replace the, now deprecated, `allow_single_item_single_line_associative_arrays` property. [#2696] +- End-user documentation to the following existing sniffs: `WordPress.Arrays.ArrayDeclarationSpacing` (props [@RafaelFunchal], [@mattgaldino] and [@rodrigoprimo], [#2489], [#2593], [#2682]), `WordPress.CodeAnalysis.AssignmentInTernaryCondition` (props [@Nic-Sevic] and [@rodrigoprimo], [#2488], [#2678]), `WordPress.DB.RestrictedClasses` (props [@paulgibbs] and [@rodrigoprimo], [#2455], [#2689]), `WordPress.DB.DirectDatabaseQuery` (props [@jaymcp] and [@rodrigoprimo], [#2458], [#2697]), `WordPress.DB.RestrictedFunctions` (props [@paulgibbs] and [@rodrigoprimo], [#2453], [#2676]), `WordPress.DB.SlowDBQuery` (props [@petitphp] and [@rodrigoprimo], [#2464], [#2699]), `WordPress.PHP.DevelopmentFunctions` (props [@gogdzl] and [@rodrigoprimo], [#2490], [#2690]), `WordPress.PHP.NoSilencedErrors` (props [@gogdzl] and [@rodrigoprimo], [#2495], [#2694]), `WordPress.PHP.PregQuoteDelimiter` (props [@tikifez] and [@rodrigoprimo], [#2487], [#2677]), `WordPress.PHP.RestrictedPHPFunctions` (props [@gogdzl] and [@rodrigoprimo], [#2491], [#2693]), `WordPress.Security.PluginMenuSlug` (props [@jasonkenison], [#2592]), `WordPress.WP.AlternativeFunctions` (props [@pamprn09], [@bhubbard] and [@rodrigoprimo], [#2496], [#2588], [#2687]), `WordPress.WP.DiscouragedConstants` (props [@RafaelFunchal], [@paulopmt1] and [@rodrigoprimo], [#2493], [#2589], [#2680]), `WordPress.WP.GlobalVariablesOverride` (props [@paulopmt1] and [@rodrigoprimo], [#2586], [#2679]). + This documentation can be exposed via the [`PHP_CodeSniffer` `--generator=...` command-line argument](https://github.com/PHPCSStandards/PHP_CodeSniffer/wiki/Usage). + +### Changed +- The minimum required `PHP_CodeSniffer` version to 3.13.5 (was 3.13.4). [#2761] +- The minimum required `PHPCSUtils` version to 1.2.2 (was 1.1.0). [#2761] +- 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.7`. [#2757] +- `WordPress.NamingConventions.PrefixAllGlobals` has been updated to recognize pluggable functions introduced in WP up to WP 7.0.0. [#2747] +- `WordPress.WP.ClassNameCase` has been updated to recognize classes introduced in WP up to WP 7.0.0. [#2747] +- `WordPress.WP.DeprecatedFunctions` now detects functions deprecated in WordPress up to WP 7.0.0. [#2747] +- The `ConstantsHelper::is_use_of_global_constant()` method will no longer flag a constant alias created via an import `use` statement as it were the use of a global constant. [#2579] +- The `ConstantsHelper::is_in_function_call()` method will now act fully case-agnostic for the function names being checked. [#2706] + Previously, the `$valid_functions` parameter would need to be passed with the function names as keys in lowercase. +- `WordPress.PHP.NoSilencedErrors`: error silencing is no longer accepted for the `parse_url()` function. [#2701] +- Improved the wording of the error message for `WordPress.Arrays.ArrayDeclarationSpacing.AssociativeArrayFound`. [#2688] +- Improved the wording of the error message for `WordPress.PHP.RestrictedPHPFunctions`. [#2702] +- Various housekeeping, including documentation and test improvements. Includes a contribution by [@dd32]. + +### Deprecated +- `WordPress.Arrays.ArrayDeclarationSpacing`: the `allow_single_item_single_line_associative_arrays` property has been deprecated in favor of the new `allow_single_item_single_line_explicit_key_arrays` property. [#2696] + This is a name change only. The functionality of these properties is the same. + +### Fixed +- `WordPress.DB.PreparedSQL` and `WordPress.DB.PreparedSQLPlaceholders`: false positive for static method calls to a non-global class named `wpdb`. [#2753] +- `WordPress.Security.EscapeOutput`: false positive for `get_search_query()` when the `$escaped` parameter was passed as fully qualified or non-lowercase `true`. [#2618] +- `WordPress.Security.EscapeOutput`: false negative for `_deprecated_file()` calls when the `basename( __FILE__ )` pattern used non-standard casing for either `basename()` and/or `__FILE__`. [#2729] +- `WordPress.WP.AlternativeFunctions`: false negative when class functions/constants/properties use the same name as select global WP constants/functions. [#2617] +- `WordPress.WP.AlternativeFunctions`: false positive for fully qualified references to the global PHP stream constants \STDIN, \STDOUT, and \STDERR. [#2617] +- `WordPress.WP.CronInterval`: false positive when the callback function reference used a different case than the function declaration, even though they are in the same file. [#2730] + +[#2453]: https://github.com/WordPress/WordPress-Coding-Standards/pull/2453 +[#2455]: https://github.com/WordPress/WordPress-Coding-Standards/pull/2455 +[#2458]: https://github.com/WordPress/WordPress-Coding-Standards/pull/2458 +[#2464]: https://github.com/WordPress/WordPress-Coding-Standards/pull/2464 +[#2487]: https://github.com/WordPress/WordPress-Coding-Standards/pull/2487 +[#2488]: https://github.com/WordPress/WordPress-Coding-Standards/pull/2488 +[#2489]: https://github.com/WordPress/WordPress-Coding-Standards/pull/2489 +[#2490]: https://github.com/WordPress/WordPress-Coding-Standards/pull/2490 +[#2491]: https://github.com/WordPress/WordPress-Coding-Standards/pull/2491 +[#2493]: https://github.com/WordPress/WordPress-Coding-Standards/pull/2493 +[#2495]: https://github.com/WordPress/WordPress-Coding-Standards/pull/2495 +[#2496]: https://github.com/WordPress/WordPress-Coding-Standards/pull/2496 +[#2579]: https://github.com/WordPress/WordPress-Coding-Standards/pull/2579 +[#2586]: https://github.com/WordPress/WordPress-Coding-Standards/pull/2586 +[#2588]: https://github.com/WordPress/WordPress-Coding-Standards/pull/2588 +[#2589]: https://github.com/WordPress/WordPress-Coding-Standards/pull/2589 +[#2592]: https://github.com/WordPress/WordPress-Coding-Standards/pull/2592 +[#2593]: https://github.com/WordPress/WordPress-Coding-Standards/pull/2593 +[#2617]: https://github.com/WordPress/WordPress-Coding-Standards/pull/2617 +[#2618]: https://github.com/WordPress/WordPress-Coding-Standards/pull/2618 +[#2676]: https://github.com/WordPress/WordPress-Coding-Standards/pull/2676 +[#2677]: https://github.com/WordPress/WordPress-Coding-Standards/pull/2677 +[#2678]: https://github.com/WordPress/WordPress-Coding-Standards/pull/2678 +[#2679]: https://github.com/WordPress/WordPress-Coding-Standards/pull/2679 +[#2680]: https://github.com/WordPress/WordPress-Coding-Standards/pull/2680 +[#2682]: https://github.com/WordPress/WordPress-Coding-Standards/pull/2682 +[#2687]: https://github.com/WordPress/WordPress-Coding-Standards/pull/2687 +[#2688]: https://github.com/WordPress/WordPress-Coding-Standards/pull/2688 +[#2689]: https://github.com/WordPress/WordPress-Coding-Standards/pull/2689 +[#2690]: https://github.com/WordPress/WordPress-Coding-Standards/pull/2690 +[#2693]: https://github.com/WordPress/WordPress-Coding-Standards/pull/2693 +[#2694]: https://github.com/WordPress/WordPress-Coding-Standards/pull/2694 +[#2696]: https://github.com/WordPress/WordPress-Coding-Standards/pull/2696 +[#2697]: https://github.com/WordPress/WordPress-Coding-Standards/pull/2697 +[#2699]: https://github.com/WordPress/WordPress-Coding-Standards/pull/2699 +[#2701]: https://github.com/WordPress/WordPress-Coding-Standards/pull/2701 +[#2702]: https://github.com/WordPress/WordPress-Coding-Standards/pull/2702 +[#2706]: https://github.com/WordPress/WordPress-Coding-Standards/pull/2706 +[#2729]: https://github.com/WordPress/WordPress-Coding-Standards/pull/2729 +[#2730]: https://github.com/WordPress/WordPress-Coding-Standards/pull/2730 +[#2747]: https://github.com/WordPress/WordPress-Coding-Standards/pull/2747 +[#2753]: https://github.com/WordPress/WordPress-Coding-Standards/pull/2753 +[#2757]: https://github.com/WordPress/WordPress-Coding-Standards/pull/2757 +[#2761]: https://github.com/WordPress/WordPress-Coding-Standards/pull/2761 + + ## [3.3.0] - 2025-11-25 ### Added @@ -1715,6 +1797,7 @@ Initial tagged release. [PHPCompatibility]: https://github.com/PHPCompatibility/PHPCompatibility [Unreleased]: https://github.com/WordPress/WordPress-Coding-Standards/compare/main...HEAD +[3.4.0]: https://github.com/WordPress/WordPress-Coding-Standards/compare/3.3.0...3.4.0 [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 @@ -1750,17 +1833,21 @@ Initial tagged release. [@anomiex]: https://github.com/anomiex [@aiolachiara]: https://github.com/aiolachiara +[@bhubbard]: https://github.com/bhubbard [@Chouby]: https://github.com/Chouby [@ckanitz]: https://github.com/ckanitz [@craigfrancis]: https://github.com/craigfrancis [@davidperezgar]: https://github.com/davidperezgar [@dawidurbanski]: https://github.com/dawidurbanski +[@dd32]: https://github.com/dd32 [@desrosj]: https://github.com/desrosj [@dingo-d]: https://github.com/dingo-d [@fredden]: https://github.com/fredden [@GaryJones]: https://github.com/GaryJones +[@gogdzl]: https://github.com/gogdzl [@grappler]: https://github.com/grappler [@Ipstenu]: https://github.com/Ipstenu +[@jasonkenison]: https://github.com/jasonkenison [@jaymcp]: https://github.com/jaymcp [@JDGrimes]: https://github.com/JDGrimes [@johnjago]: https://github.com/johnjago @@ -1768,10 +1855,18 @@ Initial tagged release. [@khacoder]: https://github.com/khacoder [@Luc45]: https://github.com/Luc45 [@marconmartins]: https://github.com/marconmartins +[@mattgaldino]: https://github.com/mattgaldino +[@Nic-Sevic]: https://github.com/Nic-Sevic [@NielsdeBlaauw]: https://github.com/NielsdeBlaauw +[@pamprn09]: https://github.com/pamprn09 +[@paulgibbs]: https://github.com/paulgibbs +[@paulopmt1]: https://github.com/paulopmt1 +[@petitphp]: https://github.com/petitphp +[@RafaelFunchal]: https://github.com/RafaelFunchal [@richardkorthuis]: https://github.com/richardkorthuis [@rodrigoprimo]: https://github.com/rodrigoprimo [@slaFFik]: https://github.com/slaFFik [@sandeshjangam]: https://github.com/sandeshjangam [@szepeviktor]: https://github.com/szepeviktor +[@tikifez]: https://github.com/tikifez [@westonruter]: https://github.com/westonruter From 598dab1a7cb29111d2664ec550202adb5905c5d5 Mon Sep 17 00:00:00 2001 From: jrfnl Date: Fri, 10 Jul 2026 19:41:47 +0200 Subject: [PATCH 108/108] README: minor markdown fix --- README.md | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/README.md b/README.md index 8cc41d9cd6..c72802d69b 100644 --- a/README.md +++ b/README.md @@ -13,8 +13,7 @@ [![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://img.shields.io/github/license/WordPress/WordPress-Coding-Standards)](https://github.com/WordPress/WordPress-Coding-Standards/blob/develop/LICENSE) -[![Total Downloads](https://img.shields.io/packagist/dt/wp-coding-standards/wpcs -)](https://packagist.org/packages/wp-coding-standards/wpcs/stats) +[![Total Downloads](https://img.shields.io/packagist/dt/wp-coding-standards/wpcs)](https://packagist.org/packages/wp-coding-standards/wpcs/stats)