Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions WordPress-VIP-Go/ruleset-test.inc
Original file line number Diff line number Diff line change
Expand Up @@ -137,6 +137,7 @@ get_next_post_link(); // Warning.
// WordPressVIPMinimum.Functions.RestrictedFunctions.get_posts_get_children
get_child(); // Ok.
get_children(); // Warning + Message.
get_children( [ 'suppress_filters' => false ] ); // Warning + Message.

// WordPressVIPMinimum.Functions.RestrictedFunctions.get_posts_get_posts
get_posts(); // Warning.
Expand Down
164 changes: 84 additions & 80 deletions WordPress-VIP-Go/ruleset-test.php
Original file line number Diff line number Diff line change
Expand Up @@ -20,33 +20,32 @@
56 => 1,
72 => 1,
83 => 1,
165 => 1,
180 => 1,
166 => 1,
181 => 1,
187 => 1,
182 => 1,
188 => 1,
252 => 1,
255 => 1,
189 => 1,
253 => 1,
256 => 1,
258 => 1,
257 => 1,
259 => 1,
318 => 1,
329 => 1,
334 => 1,
337 => 1,
341 => 1,
260 => 1,
319 => 1,
330 => 1,
335 => 1,
338 => 1,
342 => 1,
350 => 1,
343 => 1,
351 => 1,
352 => 1,
353 => 1,
354 => 1,
355 => 1,
357 => 1,
356 => 1,
358 => 1,
359 => 1,
360 => 1,
362 => 1,
361 => 1,
363 => 1,
364 => 1,
365 => 1,
Expand Down Expand Up @@ -75,26 +74,26 @@
388 => 1,
389 => 1,
390 => 1,
409 => 1,
391 => 1,
410 => 1,
411 => 1,
412 => 1,
413 => 1,
414 => 1,
415 => 1,
431 => 1,
441 => 1,
462 => 1,
466 => 1,
468 => 1,
470 => 1,
475 => 1,
477 => 1,
483 => 1,
489 => 1,
497 => 1,
510 => 1,
514 => 1,
416 => 1,
432 => 1,
442 => 1,
463 => 1,
467 => 1,
469 => 1,
471 => 1,
476 => 1,
478 => 1,
484 => 1,
490 => 1,
498 => 1,
511 => 1,
515 => 1,
516 => 1,
517 => 1,
Expand All @@ -105,16 +104,17 @@
522 => 1,
523 => 1,
524 => 1,
528 => 1,
530 => 1,
548 => 1,
563 => 1,
567 => 1,
525 => 1,
529 => 1,
531 => 1,
549 => 1,
564 => 1,
568 => 1,
569 => 1,
570 => 1,
575 => 1,
577 => 1,
571 => 1,
576 => 1,
578 => 1,
],
'warnings' => [
7 => 1,
Expand Down Expand Up @@ -155,51 +155,51 @@
130 => 1,
131 => 1,
139 => 1,
142 => 1,
146 => 1,
150 => 1,
154 => 1,
157 => 1,
161 => 1,
169 => 1,
174 => 1,
140 => 1,
143 => 1,
147 => 1,
151 => 1,
155 => 1,
158 => 1,
162 => 1,
170 => 1,
175 => 1,
176 => 1,
177 => 1,
191 => 1,
178 => 1,
192 => 1,
195 => 1,
193 => 1,
196 => 1,
199 => 1,
197 => 1,
200 => 1,
201 => 1,
204 => 1,
202 => 1,
205 => 1,
206 => 1,
207 => 1,
208 => 1,
212 => 1,
221 => 1,
223 => 1,
225 => 1,
228 => 1,
209 => 1,
213 => 1,
222 => 1,
224 => 1,
226 => 1,
229 => 1,
230 => 1,
235 => 1,
231 => 1,
236 => 1,
237 => 1,
245 => 1,
238 => 1,
246 => 1,
247 => 1,
265 => 1,
269 => 1,
273 => 1,
322 => 1,
332 => 1,
392 => 1,
394 => 1,
248 => 1,
266 => 1,
270 => 1,
274 => 1,
323 => 1,
333 => 1,
393 => 1,
395 => 1,
398 => 1,
396 => 1,
399 => 1,
400 => 1,
401 => 1,
Expand All @@ -210,28 +210,29 @@
406 => 1,
407 => 1,
408 => 1,
416 => 1,
409 => 1,
417 => 1,
418 => 1,
419 => 1,
421 => 1,
423 => 1,
420 => 1,
422 => 1,
424 => 1,
425 => 1,
428 => 1,
448 => 1,
453 => 1,
426 => 1,
429 => 1,
449 => 1,
454 => 1,
455 => 1,
456 => 1,
505 => 1,
457 => 1,
506 => 1,
533 => 1,
536 => 1,
543 => 1,
553 => 1,
559 => 1,
582 => 1,
507 => 1,
534 => 1,
537 => 1,
544 => 1,
554 => 1,
560 => 1,
583 => 1,
],
'messages' => [
7 => [
Expand Down Expand Up @@ -306,19 +307,22 @@
139 => [
'get_children() is uncached and performs a no limit query. Please use get_posts or WP_Query instead. Please see: https://docs.wpvip.com/technical-references/caching/uncached-functions/',
],
150 => [
140 => [
'get_children() is uncached and performs a no limit query. Please use get_posts or WP_Query instead. Please see: https://docs.wpvip.com/technical-references/caching/uncached-functions/',
],
151 => [
'url_to_postid() is uncached, please use wpcom_vip_url_to_postid() instead.',
],
191 => [
192 => [
'Scripts should be registered/enqueued via `wp_enqueue_script`. This can improve the site\'s performance due to script concatenation.',
],
192 => [
193 => [
'Scripts should be registered/enqueued via `wp_enqueue_script`. This can improve the site\'s performance due to script concatenation.',
],
195 => [
196 => [
'Stylesheets should be registered/enqueued via `wp_enqueue_style`. This can improve the site\'s performance due to styles concatenation.',
],
196 => [
197 => [
'Stylesheets should be registered/enqueued via `wp_enqueue_style`. This can improve the site\'s performance due to styles concatenation.',
],
],
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,10 @@
namespace WordPressVIPMinimum\Sniffs\Functions;

use PHP_CodeSniffer\Util\Tokens;
use PHPCSUtils\Utils\Arrays;
use PHPCSUtils\Utils\GetTokensAsString;
use PHPCSUtils\Utils\PassedParameters;
use PHPCSUtils\Utils\TextStrings;
use WordPressCS\WordPress\AbstractFunctionRestrictionsSniff;

/**
Expand Down Expand Up @@ -254,10 +258,9 @@ public function getGroups() {
'setcookie',
],
],
// @todo Introduce a sniff specific to get_posts() that checks for suppress_filters=>false being supplied.
'get_posts' => [
'type' => 'warning',
'message' => '%s() is uncached unless the "suppress_filters" parameter is set to false. If the suppress_filter parameter is set to false this can be safely ignored. More Info: https://docs.wpvip.com/technical-references/caching/uncached-functions/.',
'message' => '%s() is uncached unless the "suppress_filters" parameter is set to false. If the parameter is set to false in a way this sniff cannot detect, such as via a variable, this can be safely ignored. More Info: https://docs.wpvip.com/technical-references/caching/uncached-functions/.',
'functions' => [
'get_posts',
'wp_get_recent_posts',
Expand Down Expand Up @@ -326,4 +329,81 @@ public function is_targetted_token( $stackPtr ) {
return $this->tokens[ $prevPrev ]['code'] === T_VARIABLE
&& isset( $this->groups[ $this->tokens[ $stackPtr ]['content'] ]['object_var'][ $this->tokens[ $prevPrev ]['content'] ] );
}

/**
* Process a matched token.
*
* This differs to the parent class method that it overrides, by not flagging calls to
* `get_posts()` and `wp_get_recent_posts()` which set `suppress_filters` to `false`.
* `get_children()` is still flagged, as it also performs a no-LIMIT query by default.
*
* @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.
*
* @return void
*/
public function process_matched_token( $stackPtr, $group_name, $matched_content ) {
if ( $group_name === 'get_posts'
&& $matched_content !== 'get_children'
&& $this->sets_suppress_filters_to_false( $stackPtr )
) {
return;
}

parent::process_matched_token( $stackPtr, $group_name, $matched_content );
}

/**
* Check whether a function call passes an array of arguments which sets `suppress_filters` to `false`.
*
* @param int $stackPtr The position of the function call name in the stack.
*
* @return bool
*/
private function sets_suppress_filters_to_false( $stackPtr ) {
$args_param = PassedParameters::getParameter( $this->phpcsFile, $stackPtr, 1, 'args' );
if ( $args_param === false ) {
return false;
}

$array_ptr = $this->phpcsFile->findNext( Tokens::$emptyTokens, $args_param['start'], $args_param['end'] + 1, true );
if ( $array_ptr === false ) {
return false;
}

// The array has to be the whole argument.
$open_close = Arrays::getOpenClose( $this->phpcsFile, $array_ptr );
if ( $open_close === false
|| $open_close['closer'] !== $this->phpcsFile->findPrevious( Tokens::$emptyTokens, $args_param['end'], $args_param['start'], true )
) {
return false;
}

$is_false = false;
foreach ( PassedParameters::getParameters( $this->phpcsFile, $array_ptr ) as $item ) {
$arrow = Arrays::getDoubleArrowPtr( $this->phpcsFile, $item['start'], $item['end'] );
if ( $arrow === false ) {
$first = $this->phpcsFile->findNext( Tokens::$emptyTokens, $item['start'], $item['end'] + 1, true );
if ( $first !== false && $this->tokens[ $first ]['code'] === T_ELLIPSIS ) {
// An unpacked array can override an earlier key.
$is_false = false;
}
continue;
}

$key = TextStrings::stripQuotes( GetTokensAsString::noEmpties( $this->phpcsFile, $item['start'], $arrow - 1 ) );
if ( $key === 'suppress_filters' ) {
// WP_Query only checks the value is falsy, so a lone `false` or `0` both count.
$value = $this->phpcsFile->findNext( Tokens::$emptyTokens, $arrow + 1, $item['end'] + 1, true );
$is_false = $value !== false
&& $this->phpcsFile->findNext( Tokens::$emptyTokens, $value + 1, $item['end'] + 1, true ) === false
&& ( $this->tokens[ $value ]['code'] === T_FALSE
|| ( $this->tokens[ $value ]['code'] === T_LNUMBER && $this->tokens[ $value ]['content'] === '0' ) );
}
}

return $is_false;
}
}
Loading
Loading