-
-
Notifications
You must be signed in to change notification settings - Fork 492
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
✨ New WordPress.WP.GetMetaSingle sniff
This sniff warns when get_*_meta() and get_metadata*() functions are used with the $meta_key/$key param, but without the $single parameter. This could lead to unexpected behavior as an array will be returned, but a string might be expected.
- Loading branch information
1 parent
d77b020
commit 4b47564
Showing
5 changed files
with
294 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,33 @@ | ||
<?xml version="1.0"?> | ||
<documentation xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" | ||
xsi:noNamespaceSchemaLocation="https://phpcsstandards.github.io/PHPCSDevTools/phpcsdocs.xsd" | ||
title="Get Meta Single" | ||
> | ||
<standard> | ||
<![CDATA[ | ||
When calling the get_(comment|post|site|term|user)_meta(), get_metadata(), get_metadata_default(), | ||
and get_metadata_raw() functions, if the $meta_key/$key parameter is passed, the $single parameter | ||
should be passed as well to make it explicit what is the expected return type. | ||
]]> | ||
</standard> | ||
<code_comparison> | ||
<code title="Valid: get meta functions used with or without both $meta_key/$key and $single parameters."> | ||
<![CDATA[ | ||
$admin_color = get_user_meta( | ||
$user_id, | ||
<em>'admin_color', | ||
true</em> | ||
); | ||
$post_meta = get_metadata( 'post', $post_id<em></em> ); | ||
]]> | ||
</code> | ||
<code title="Invalid: get meta function used with $meta_key/$key parameter and without $single parameter."> | ||
<![CDATA[ | ||
$admin_color = get_user_meta( | ||
$user_id, | ||
<em>'admin_color'</em> | ||
); | ||
]]> | ||
</code> | ||
</code_comparison> | ||
</documentation> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,172 @@ | ||
<?php | ||
/** | ||
* WordPress Coding Standard. | ||
* | ||
* @package WPCS\WordPressCodingStandards | ||
* @link https://github.com/WordPress/WordPress-Coding-Standards | ||
* @license https://opensource.org/licenses/MIT MIT | ||
*/ | ||
|
||
namespace WordPressCS\WordPress\Sniffs\WP; | ||
|
||
use PHPCSUtils\Utils\PassedParameters; | ||
use WordPressCS\WordPress\AbstractFunctionParameterSniff; | ||
|
||
/** | ||
* Flags calls to get_(comment|post|site|term|user)_meta(), get_metadata(), get_metadata_default() | ||
* and get_metadata_raw() functions that include the $key/$meta_key parameter, but omit the $single | ||
* parameter. Omitting $single in this situation can result in unexpected return types and lead to | ||
* bugs. | ||
* | ||
* @link https://github.com/WordPress/WordPress-Coding-Standards/issues/2459 | ||
* | ||
* @since 3.2.0 | ||
*/ | ||
final class GetMetaSingleSniff extends AbstractFunctionParameterSniff { | ||
|
||
/** | ||
* The group name for this group of functions. | ||
* | ||
* @since 3.2.0 | ||
* | ||
* @var string | ||
*/ | ||
protected $group_name = 'get_meta'; | ||
|
||
/** | ||
* List of functions this sniff should examine. | ||
* | ||
* @link https://developer.wordpress.org/reference/functions/get_comment_meta/ | ||
* @link https://developer.wordpress.org/reference/functions/get_metadata/ | ||
* @link https://developer.wordpress.org/reference/functions/get_metadata_default/ | ||
* @link https://developer.wordpress.org/reference/functions/get_metadata_raw/ | ||
* @link https://developer.wordpress.org/reference/functions/get_post_meta/ | ||
* @link https://developer.wordpress.org/reference/functions/get_site_meta/ | ||
* @link https://developer.wordpress.org/reference/functions/get_term_meta/ | ||
* @link https://developer.wordpress.org/reference/functions/get_user_meta/ | ||
* | ||
* @since 3.2.0 | ||
* | ||
* @var array<string, array> Key is function name, value is an array containing information | ||
* about the name and position of the relevant parameters. | ||
*/ | ||
protected $target_functions = array( | ||
'get_comment_meta' => array( | ||
'condition' => array( | ||
'parameter' => 'key', | ||
'position' => 2, | ||
), | ||
'recommended' => array( | ||
'parameter' => 'single', | ||
'position' => 3, | ||
), | ||
), | ||
'get_metadata' => array( | ||
'condition' => array( | ||
'parameter' => 'meta_key', | ||
'position' => 3, | ||
), | ||
'recommended' => array( | ||
'parameter' => 'single', | ||
'position' => 4, | ||
), | ||
), | ||
'get_metadata_default' => array( | ||
'condition' => array( | ||
'parameter' => 'meta_key', | ||
'position' => 3, | ||
), | ||
'recommended' => array( | ||
'parameter' => 'single', | ||
'position' => 4, | ||
), | ||
), | ||
'get_metadata_raw' => array( | ||
'condition' => array( | ||
'parameter' => 'meta_key', | ||
'position' => 3, | ||
), | ||
'recommended' => array( | ||
'parameter' => 'single', | ||
'position' => 4, | ||
), | ||
), | ||
'get_post_meta' => array( | ||
'condition' => array( | ||
'parameter' => 'key', | ||
'position' => 2, | ||
), | ||
'recommended' => array( | ||
'parameter' => 'single', | ||
'position' => 3, | ||
), | ||
), | ||
'get_site_meta' => array( | ||
'condition' => array( | ||
'parameter' => 'key', | ||
'position' => 2, | ||
), | ||
'recommended' => array( | ||
'parameter' => 'single', | ||
'position' => 3, | ||
), | ||
), | ||
'get_term_meta' => array( | ||
'condition' => array( | ||
'parameter' => 'key', | ||
'position' => 2, | ||
), | ||
'recommended' => array( | ||
'parameter' => 'single', | ||
'position' => 3, | ||
), | ||
), | ||
'get_user_meta' => array( | ||
'condition' => array( | ||
'parameter' => 'key', | ||
'position' => 2, | ||
), | ||
'recommended' => array( | ||
'parameter' => 'single', | ||
'position' => 3, | ||
), | ||
), | ||
); | ||
|
||
/** | ||
* Process the parameters of a matched function. | ||
* | ||
* @since 3.2.0 | ||
* | ||
* @param int $stackPtr The position of the current token in the stack. | ||
* @param string $group_name The name of the group which was matched. | ||
* @param string $matched_content The token content (function name) which was matched | ||
* in lowercase. | ||
* @param array $parameters Array with information about the parameters. | ||
* | ||
* @return void | ||
*/ | ||
public function process_parameters( $stackPtr, $group_name, $matched_content, $parameters ) { | ||
$condition = $this->target_functions[ $matched_content ]['condition']; | ||
$recommended = $this->target_functions[ $matched_content ]['recommended']; | ||
|
||
$meta_key = PassedParameters::getParameterFromStack( $parameters, $condition['position'], $condition['parameter'] ); | ||
if ( false === $meta_key ) { | ||
return; | ||
} | ||
|
||
$single = PassedParameters::getParameterFromStack( $parameters, $recommended['position'], $recommended['parameter'] ); | ||
if ( is_array( $single ) ) { | ||
return; | ||
} | ||
|
||
$tokens = $this->phpcsFile->getTokens(); | ||
|
||
$this->phpcsFile->addWarning( | ||
'When passing the $%s parameter to %s(), the $%s parameter must also be passed to make it explicit whether an array or a string is expected.', | ||
$stackPtr, | ||
'ReturnTypeNotExplicit', | ||
array( $condition['parameter'], $tokens[ $stackPtr ]['content'], $recommended['parameter'] ) | ||
); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,32 @@ | ||
<?php | ||
|
||
// Invalid calls (missing mandatory parameter), but still useful to check that the sniff does not flag them. | ||
$invalid_but_ok = get_post_meta(); | ||
$invalid_but_ok = get_post_meta( single: true, $post_id ); | ||
$invalid_but_ok = get_post_meta( single: true ); | ||
$invalid_but_ok = get_metadata( 'post' ); | ||
|
||
$ok = get_post_meta( $post_id ); | ||
$ok = get_post_meta( $post_id, $meta_key, false ); | ||
$ok = get_post_meta( $post_id, single: true ); | ||
$ok = get_post_meta( $post_id, single: true, key: $meta_key ); | ||
$ok = get_metadata( 'post', $post_id ); | ||
$ok = get_metadata( 'post', $post_id, $meta_key, true ); | ||
$ok = get_metadata( 'post', $post_id, single: true ); | ||
$ok = get_metadata( 'post', $post_id, single: true, meta_key: $meta_key ); | ||
|
||
$warning = get_post_meta( $post_id, $meta_key ); | ||
$warning = get_post_meta( $post_id, key: $meta_key ); | ||
$warning = get_post_meta( $post_id, key: $meta_key, sinngle: true ); // Typo in parameter name. | ||
$warning = get_comment_meta( $comment_id, $meta_key ); | ||
$warning = get_site_meta( $site_id, $meta_key ); | ||
$warning = get_term_meta( $term_id, $meta_key ); | ||
$warning = get_user_meta( $user_id, $meta_key ); | ||
$warning = GET_METADATA( 'post', $post_id, $meta_key ); | ||
$warning = get_metadata( | ||
'post', | ||
$post_id, | ||
meta_key: $meta_key | ||
); | ||
$warning = get_metadata_raw( 'post', $post_id, $meta_key ); | ||
$warning = get_metadata_default( 'post', $post_id, $meta_key ); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,52 @@ | ||
<?php | ||
/** | ||
* Unit test class for WordPress Coding Standard. | ||
* | ||
* @package WPCS\WordPressCodingStandards | ||
* @link https://github.com/WordPress/WordPress-Coding-Standards | ||
* @license https://opensource.org/licenses/MIT MIT | ||
*/ | ||
|
||
namespace WordPressCS\WordPress\Tests\WP; | ||
|
||
use PHP_CodeSniffer\Tests\Standards\AbstractSniffUnitTest; | ||
|
||
/** | ||
* Unit test class for the GetMetaSingle sniff. | ||
* | ||
* @since 3.2.0 | ||
* | ||
* @covers \WordPressCS\WordPress\Sniffs\WP\GetMetaSingleSniff | ||
*/ | ||
final class GetMetaSingleUnitTest extends AbstractSniffUnitTest { | ||
|
||
/** | ||
* Returns the lines where errors should occur. | ||
* | ||
* @return array<int, int> Key is the line number, value is the number of expected errors. | ||
*/ | ||
public function getErrorList() { | ||
return array(); | ||
} | ||
|
||
/** | ||
* Returns the lines where warnings should occur. | ||
* | ||
* @return array<int, int> Key is the line number, value is the number of expected warnings. | ||
*/ | ||
public function getWarningList() { | ||
return array( | ||
18 => 1, | ||
19 => 1, | ||
20 => 1, | ||
21 => 1, | ||
22 => 1, | ||
23 => 1, | ||
24 => 1, | ||
25 => 1, | ||
26 => 1, | ||
31 => 1, | ||
32 => 1, | ||
); | ||
} | ||
} |