From 8349f909e82155c2e3ff06ed5699f5f1e3e72130 Mon Sep 17 00:00:00 2001 From: jrfnl Date: Wed, 14 Dec 2022 11:25:16 +0100 Subject: [PATCH 1/3] Sniff: remove the `$hookFunctions` property ... as it is not currently used anywhere in the WPCS codebase. --- WordPress/Sniff.php | 23 ----------------------- 1 file changed, 23 deletions(-) diff --git a/WordPress/Sniff.php b/WordPress/Sniff.php index 58ebd3c7d8..9cd7a877b2 100644 --- a/WordPress/Sniff.php +++ b/WordPress/Sniff.php @@ -487,29 +487,6 @@ abstract class Sniff implements PHPCS_Sniff { 'apply_filters_deprecated' => true, ); - /** - * A list of functions that are used to interact with the WP plugins API. - * - * @since 0.10.0 - * @since 0.11.0 Changed from public static to protected non-static. - * - * @var array => - */ - protected $hookFunctions = array( - 'has_filter' => 1, - 'add_filter' => 1, - 'remove_filter' => 1, - 'remove_all_filters' => 1, - 'doing_filter' => 1, // Hook name optional. - 'has_action' => 1, - 'add_action' => 1, - 'doing_action' => 1, // Hook name optional. - 'did_action' => 1, - 'remove_action' => 1, - 'remove_all_actions' => 1, - 'current_filter' => 0, // No hook name argument. - ); - /** * List of global WP variables. * From 610d371587f4b6ae0853368953936fa4723306f1 Mon Sep 17 00:00:00 2001 From: jrfnl Date: Wed, 14 Dec 2022 11:49:46 +0100 Subject: [PATCH 2/3] Move "hook" related utilities to dedicated `WPHookHelper` The "hook" related property is only used by a small set of sniffs, so are better placed in a dedicated class. This commit moves the `$hookInvokeFunctions` property to a new `WordPressCS\WordPress\Helpers\WPHookHelper` class and starts using that class in the relevant sniffs. Note: * The property is now `private` (and `static`). * Access to the property can be obtained via the new `WPHookHelper::get_functions()` method. * This new method can also pre-filter the list to only return thos functions which are not specifically to invoke deprecated hooks. Related to 1465 --- WordPress/Helpers/WPHookHelper.php | 63 +++++++++++++++++++ WordPress/Sniff.php | 17 ----- .../PrefixAllGlobalsSniff.php | 9 +-- .../NamingConventions/ValidHookNameSniff.php | 12 ++-- 4 files changed, 70 insertions(+), 31 deletions(-) create mode 100644 WordPress/Helpers/WPHookHelper.php diff --git a/WordPress/Helpers/WPHookHelper.php b/WordPress/Helpers/WPHookHelper.php new file mode 100644 index 0000000000..5686e48cc1 --- /dev/null +++ b/WordPress/Helpers/WPHookHelper.php @@ -0,0 +1,63 @@ + + */ + private static $hookInvokeFunctions = array( + 'do_action' => true, + 'do_action_ref_array' => true, + 'do_action_deprecated' => true, + 'apply_filters' => true, + 'apply_filters_ref_array' => true, + 'apply_filters_deprecated' => true, + ); + + /** + * Retrieve a list of the WordPress functions which invoke hooks. + * + * @since 3.0.0 + * + * @param bool $include_deprecated Whether to include the names of functions + * which are used to invoke deprecated hooks. + * Defaults to `true`. + * + * @return array Array with the function names as keys. The value is irrelevant. + */ + public static function get_functions( $include_deprecated = true ) { + $hooks = self::$hookInvokeFunctions; + if ( false === $include_deprecated ) { + unset( + $hooks['do_action_deprecated'], + $hooks['apply_filters_deprecated'] + ); + } + + return $hooks; + } +} diff --git a/WordPress/Sniff.php b/WordPress/Sniff.php index 9cd7a877b2..f2595de926 100644 --- a/WordPress/Sniff.php +++ b/WordPress/Sniff.php @@ -470,23 +470,6 @@ abstract class Sniff implements PHPCS_Sniff { 'clean_user_cache' => true, ); - /** - * A list of functions that invoke WP hooks (filters/actions). - * - * @since 0.10.0 - * @since 0.11.0 Changed from public static to protected non-static. - * - * @var array - */ - protected $hookInvokeFunctions = array( - 'do_action' => true, - 'do_action_ref_array' => true, - 'do_action_deprecated' => true, - 'apply_filters' => true, - 'apply_filters_ref_array' => true, - 'apply_filters_deprecated' => true, - ); - /** * List of global WP variables. * diff --git a/WordPress/Sniffs/NamingConventions/PrefixAllGlobalsSniff.php b/WordPress/Sniffs/NamingConventions/PrefixAllGlobalsSniff.php index 45d7749eaa..1faf338b06 100644 --- a/WordPress/Sniffs/NamingConventions/PrefixAllGlobalsSniff.php +++ b/WordPress/Sniffs/NamingConventions/PrefixAllGlobalsSniff.php @@ -20,6 +20,7 @@ use WordPressCS\WordPress\AbstractFunctionParameterSniff; use WordPressCS\WordPress\Helpers\DeprecationHelper; use WordPressCS\WordPress\Helpers\IsUnitTestTrait; +use WordPressCS\WordPress\Helpers\WPHookHelper; /** * Verify that everything defined in the global namespace is prefixed with a theme/plugin specific prefix. @@ -254,12 +255,8 @@ public function register() { * @return array */ public function getGroups() { - $this->target_functions = $this->hookInvokeFunctions; - unset( - $this->target_functions['do_action_deprecated'], - $this->target_functions['apply_filters_deprecated'] - ); - + // Only retrieve functions which are not used for deprecated hooks. + $this->target_functions = WPHookHelper::get_functions( false ); $this->target_functions['define'] = true; return parent::getGroups(); diff --git a/WordPress/Sniffs/NamingConventions/ValidHookNameSniff.php b/WordPress/Sniffs/NamingConventions/ValidHookNameSniff.php index c4c4fe58fe..d72d64651b 100644 --- a/WordPress/Sniffs/NamingConventions/ValidHookNameSniff.php +++ b/WordPress/Sniffs/NamingConventions/ValidHookNameSniff.php @@ -9,9 +9,10 @@ namespace WordPressCS\WordPress\Sniffs\NamingConventions; -use WordPressCS\WordPress\AbstractFunctionParameterSniff; use PHP_CodeSniffer\Util\Tokens; use PHPCSUtils\Utils\TextStrings; +use WordPressCS\WordPress\AbstractFunctionParameterSniff; +use WordPressCS\WordPress\Helpers\WPHookHelper; /** * Use lowercase letters in action and filter names. Separate words via underscores. @@ -73,13 +74,8 @@ class ValidHookNameSniff extends AbstractFunctionParameterSniff { * @return array */ public function getGroups() { - $this->target_functions = $this->hookInvokeFunctions; - - // No need to examine the names of deprecated hooks. - unset( - $this->target_functions['do_action_deprecated'], - $this->target_functions['apply_filters_deprecated'] - ); + // Only retrieve functions which are not used for deprecated hooks. + $this->target_functions = WPHookHelper::get_functions( false ); return parent::getGroups(); } From 73ea966e47336fd270af094e289b88c5e6fb998c Mon Sep 17 00:00:00 2001 From: jrfnl Date: Wed, 14 Dec 2022 12:18:22 +0100 Subject: [PATCH 3/3] WPHookHelper: add new `get_hook_name_param()` method ... to support retrieving the hook name parameters from a stack of parameters, while supporting PHP 8.0+ function calls using named arguments. This new method will be tested via the implementations in the `ValidHookName` and the `PrefixAllGlobals` sniffs. --- WordPress/Helpers/WPHookHelper.php | 67 ++++++++++++++++++++++++++---- 1 file changed, 59 insertions(+), 8 deletions(-) diff --git a/WordPress/Helpers/WPHookHelper.php b/WordPress/Helpers/WPHookHelper.php index 5686e48cc1..625712d4c1 100644 --- a/WordPress/Helpers/WPHookHelper.php +++ b/WordPress/Helpers/WPHookHelper.php @@ -9,6 +9,8 @@ namespace WordPressCS\WordPress\Helpers; +use PHPCSUtils\Utils\PassedParameters; + /** * Helper utilities for recognizing functions related to the WP Hook mechanism. * @@ -26,16 +28,37 @@ final class WPHookHelper { * @since 3.0.0 - Moved from the Sniff class to this class. * - The property visibility has changed from `protected` to `private static`. * Use the `get_function_names()` method for access. + * - The format of the value has changed from a non-relevant boolean to + * an array with the parameter position and name(s) for the hook name parameter. * - * @var array + * @var array> Function name as key, array with target + * parameter position and name(s) as value. */ private static $hookInvokeFunctions = array( - 'do_action' => true, - 'do_action_ref_array' => true, - 'do_action_deprecated' => true, - 'apply_filters' => true, - 'apply_filters_ref_array' => true, - 'apply_filters_deprecated' => true, + 'do_action' => array( + 'position' => 1, + 'name' => 'hook_name', + ), + 'do_action_ref_array' => array( + 'position' => 1, + 'name' => 'hook_name', + ), + 'do_action_deprecated' => array( + 'position' => 1, + 'name' => 'hook_name', + ), + 'apply_filters' => array( + 'position' => 1, + 'name' => 'hook_name', + ), + 'apply_filters_ref_array' => array( + 'position' => 1, + 'name' => 'hook_name', + ), + 'apply_filters_deprecated' => array( + 'position' => 1, + 'name' => 'hook_name', + ), ); /** @@ -50,7 +73,7 @@ final class WPHookHelper { * @return array Array with the function names as keys. The value is irrelevant. */ public static function get_functions( $include_deprecated = true ) { - $hooks = self::$hookInvokeFunctions; + $hooks = array_fill_keys( array_keys( self::$hookInvokeFunctions ), true ); if ( false === $include_deprecated ) { unset( $hooks['do_action_deprecated'], @@ -60,4 +83,32 @@ public static function get_functions( $include_deprecated = true ) { return $hooks; } + + /** + * Retrieve the parameter information for the hook name parameter from a stack of parameters + * passed to one of the WP hook functions. + * + * @since 3.0.0 + * + * @param string $function_name The name of the WP hook function which the parameters were passed to. + * @param array $parameters The output of a previous call to PassedParameters::getParameters(). + * + * @return array|false Array with information on the parameter at the specified offset, + * or with the specified name. + * Or `FALSE` if the specified parameter is not found. + * See the PHPCSUtils PassedParameters::getParameters() documentation + * for the format of the returned (single-dimensional) array. + */ + public static function get_hook_name_param( $function_name, array $parameters ) { + $function_lc = strtolower( $function_name ); + if ( isset( self::$hookInvokeFunctions[ $function_lc ] ) === false ) { + return false; + } + + return PassedParameters::getParameterFromStack( + $parameters, + self::$hookInvokeFunctions[ $function_lc ]['position'], + self::$hookInvokeFunctions[ $function_lc ]['name'] + ); + } }