├── CHANGELOG.md ├── LICENSE ├── README.md ├── WordPress-Core └── ruleset.xml ├── WordPress-Docs └── ruleset.xml ├── WordPress-Extra └── ruleset.xml ├── WordPress ├── AbstractArrayAssignmentRestrictionsSniff.php ├── AbstractClassRestrictionsSniff.php ├── AbstractFunctionParameterSniff.php ├── AbstractFunctionRestrictionsSniff.php ├── Docs │ ├── Arrays │ │ ├── ArrayIndentationStandard.xml │ │ ├── ArrayKeySpacingRestrictionsStandard.xml │ │ └── MultipleStatementAlignmentStandard.xml │ ├── CodeAnalysis │ │ └── EscapedNotTranslatedStandard.xml │ ├── DB │ │ └── PreparedSQLStandard.xml │ ├── DateTime │ │ ├── CurrentTimeTimestampStandard.xml │ │ └── RestrictedFunctionsStandard.xml │ ├── NamingConventions │ │ ├── PrefixAllGlobalsStandard.xml │ │ ├── ValidFunctionNameStandard.xml │ │ ├── ValidHookNameStandard.xml │ │ ├── ValidPostTypeSlugStandard.xml │ │ └── ValidVariableNameStandard.xml │ ├── PHP │ │ ├── DontExtractStandard.xml │ │ ├── IniSetStandard.xml │ │ ├── StrictInArrayStandard.xml │ │ └── YodaConditionsStandard.xml │ ├── Security │ │ └── SafeRedirectStandard.xml │ ├── WP │ │ ├── CapabilitiesStandard.xml │ │ ├── CapitalPDangitStandard.xml │ │ ├── ClassNameCaseStandard.xml │ │ ├── CronIntervalStandard.xml │ │ ├── DeprecatedClassesStandard.xml │ │ ├── DeprecatedFunctionsStandard.xml │ │ ├── DeprecatedParameterValuesStandard.xml │ │ ├── DeprecatedParametersStandard.xml │ │ ├── EnqueuedResourceParametersStandard.xml │ │ ├── EnqueuedResourcesStandard.xml │ │ ├── GetMetaSingleStandard.xml │ │ └── PostsPerPageStandard.xml │ └── WhiteSpace │ │ ├── CastStructureSpacingStandard.xml │ │ ├── ControlStructureSpacingStandard.xml │ │ ├── ObjectOperatorSpacingStandard.xml │ │ └── OperatorSpacingStandard.xml ├── Helpers │ ├── ArrayWalkingFunctionsHelper.php │ ├── ConstantsHelper.php │ ├── ContextHelper.php │ ├── DeprecationHelper.php │ ├── EscapingFunctionsTrait.php │ ├── FormattingFunctionsHelper.php │ ├── IsUnitTestTrait.php │ ├── ListHelper.php │ ├── MinimumWPVersionTrait.php │ ├── PrintingFunctionsTrait.php │ ├── RulesetPropertyHelper.php │ ├── SanitizationHelperTrait.php │ ├── SnakeCaseHelper.php │ ├── UnslashingFunctionsHelper.php │ ├── ValidationHelper.php │ ├── VariableHelper.php │ ├── WPDBTrait.php │ ├── WPGlobalVariablesHelper.php │ └── WPHookHelper.php ├── Sniff.php ├── Sniffs │ ├── Arrays │ │ ├── ArrayDeclarationSpacingSniff.php │ │ ├── ArrayIndentationSniff.php │ │ ├── ArrayKeySpacingRestrictionsSniff.php │ │ └── MultipleStatementAlignmentSniff.php │ ├── CodeAnalysis │ │ ├── AssignmentInTernaryConditionSniff.php │ │ └── EscapedNotTranslatedSniff.php │ ├── DB │ │ ├── DirectDatabaseQuerySniff.php │ │ ├── PreparedSQLPlaceholdersSniff.php │ │ ├── PreparedSQLSniff.php │ │ ├── RestrictedClassesSniff.php │ │ ├── RestrictedFunctionsSniff.php │ │ └── SlowDBQuerySniff.php │ ├── DateTime │ │ ├── CurrentTimeTimestampSniff.php │ │ └── RestrictedFunctionsSniff.php │ ├── Files │ │ └── FileNameSniff.php │ ├── NamingConventions │ │ ├── PrefixAllGlobalsSniff.php │ │ ├── ValidFunctionNameSniff.php │ │ ├── ValidHookNameSniff.php │ │ ├── ValidPostTypeSlugSniff.php │ │ └── ValidVariableNameSniff.php │ ├── PHP │ │ ├── DevelopmentFunctionsSniff.php │ │ ├── DiscouragedPHPFunctionsSniff.php │ │ ├── DontExtractSniff.php │ │ ├── IniSetSniff.php │ │ ├── NoSilencedErrorsSniff.php │ │ ├── POSIXFunctionsSniff.php │ │ ├── PregQuoteDelimiterSniff.php │ │ ├── RestrictedPHPFunctionsSniff.php │ │ ├── StrictInArraySniff.php │ │ ├── TypeCastsSniff.php │ │ └── YodaConditionsSniff.php │ ├── Security │ │ ├── EscapeOutputSniff.php │ │ ├── NonceVerificationSniff.php │ │ ├── PluginMenuSlugSniff.php │ │ ├── SafeRedirectSniff.php │ │ └── ValidatedSanitizedInputSniff.php │ ├── Utils │ │ └── I18nTextDomainFixerSniff.php │ ├── WP │ │ ├── AlternativeFunctionsSniff.php │ │ ├── CapabilitiesSniff.php │ │ ├── CapitalPDangitSniff.php │ │ ├── ClassNameCaseSniff.php │ │ ├── CronIntervalSniff.php │ │ ├── DeprecatedClassesSniff.php │ │ ├── DeprecatedFunctionsSniff.php │ │ ├── DeprecatedParameterValuesSniff.php │ │ ├── DeprecatedParametersSniff.php │ │ ├── DiscouragedConstantsSniff.php │ │ ├── DiscouragedFunctionsSniff.php │ │ ├── EnqueuedResourceParametersSniff.php │ │ ├── EnqueuedResourcesSniff.php │ │ ├── GetMetaSingleSniff.php │ │ ├── GlobalVariablesOverrideSniff.php │ │ ├── I18nSniff.php │ │ └── PostsPerPageSniff.php │ └── WhiteSpace │ │ ├── CastStructureSpacingSniff.php │ │ ├── ControlStructureSpacingSniff.php │ │ ├── ObjectOperatorSpacingSniff.php │ │ └── OperatorSpacingSniff.php └── ruleset.xml ├── composer.json └── phpcs.xml.dist.sample /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2009 John Godley and contributors. 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /WordPress-Docs/ruleset.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | WordPress Coding Standards for Inline Documentation and Comments 5 | 6 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | -------------------------------------------------------------------------------- /WordPress/AbstractFunctionParameterSniff.php: -------------------------------------------------------------------------------- 1 | target_functions ) ) { 49 | return array(); 50 | } 51 | 52 | return array( 53 | $this->group_name => array( 54 | 'functions' => array_keys( $this->target_functions ), 55 | ), 56 | ); 57 | } 58 | 59 | /** 60 | * Process a matched token. 61 | * 62 | * @param int $stackPtr The position of the current token in the stack. 63 | * @param string $group_name The name of the group which was matched. 64 | * @param string $matched_content The token content (function name) which was matched 65 | * in lowercase. 66 | * 67 | * @return int|void Integer stack pointer to skip forward or void to continue 68 | * normal file processing. 69 | */ 70 | public function process_matched_token( $stackPtr, $group_name, $matched_content ) { 71 | 72 | $parameters = PassedParameters::getParameters( $this->phpcsFile, $stackPtr ); 73 | 74 | if ( empty( $parameters ) ) { 75 | return $this->process_no_parameters( $stackPtr, $group_name, $matched_content ); 76 | } else { 77 | return $this->process_parameters( $stackPtr, $group_name, $matched_content, $parameters ); 78 | } 79 | } 80 | 81 | /** 82 | * Verify if the current token is a function call. Behaves like the parent method, except that 83 | * it returns false if there is no opening parenthesis after the function name (likely a 84 | * function import) or if it is a first class callable. 85 | * 86 | * @param int $stackPtr The position of the current token in the stack. 87 | * 88 | * @return bool 89 | */ 90 | public function is_targetted_token( $stackPtr ) { 91 | if ( ! parent::is_targetted_token( $stackPtr ) ) { 92 | return false; 93 | } 94 | 95 | $next = $this->phpcsFile->findNext( Tokens::$emptyTokens, ( $stackPtr + 1 ), null, true ); 96 | 97 | if ( \T_OPEN_PARENTHESIS !== $this->tokens[ $next ]['code'] ) { 98 | // Not a function call (likely a function import). 99 | return false; 100 | } 101 | 102 | if ( isset( $this->tokens[ $next ]['parenthesis_closer'] ) === false ) { 103 | // Syntax error or live coding: missing closing parenthesis. 104 | return false; 105 | } 106 | 107 | // First class callable. 108 | $firstNonEmpty = $this->phpcsFile->findNext( Tokens::$emptyTokens, ( $next + 1 ), null, true ); 109 | if ( \T_ELLIPSIS === $this->tokens[ $firstNonEmpty ]['code'] ) { 110 | $secondNonEmpty = $this->phpcsFile->findNext( Tokens::$emptyTokens, ( $firstNonEmpty + 1 ), null, true ); 111 | if ( \T_CLOSE_PARENTHESIS === $this->tokens[ $secondNonEmpty ]['code'] ) { 112 | return false; 113 | } 114 | } 115 | 116 | return true; 117 | } 118 | 119 | /** 120 | * Process the parameters of a matched function. 121 | * 122 | * This method has to be made concrete in child classes. 123 | * 124 | * @param int $stackPtr The position of the current token in the stack. 125 | * @param string $group_name The name of the group which was matched. 126 | * @param string $matched_content The token content (function name) which was matched 127 | * in lowercase. 128 | * @param array $parameters Array with information about the parameters. 129 | * 130 | * @return int|void Integer stack pointer to skip forward or void to continue 131 | * normal file processing. 132 | */ 133 | abstract public function process_parameters( $stackPtr, $group_name, $matched_content, $parameters ); 134 | 135 | /** 136 | * Process the function if no parameters were found. 137 | * 138 | * Defaults to doing nothing. Can be overloaded in child classes to handle functions 139 | * were parameters are expected, but none found. 140 | * 141 | * @param int $stackPtr The position of the current token in the stack. 142 | * @param string $group_name The name of the group which was matched. 143 | * @param string $matched_content The token content (function name) which was matched 144 | * in lowercase. 145 | * 146 | * @return int|void Integer stack pointer to skip forward or void to continue 147 | * normal file processing. 148 | */ 149 | public function process_no_parameters( $stackPtr, $group_name, $matched_content ) {} 150 | } 151 | -------------------------------------------------------------------------------- /WordPress/Docs/Arrays/ArrayIndentationStandard.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 10 | 11 | 12 | 13 | 22, 16 | ); 17 | ]]> 18 | 19 | 20 | 22, 23 | ); 24 | ]]> 25 | 26 | 27 | 28 | 31 | 32 | 33 | 34 | 22, 37 | 'comment_count' => array( 38 | 'value' => 25, 39 | 'compare' => '>=', 40 | ), 41 | 'post_type' => array( 42 | 'post', 43 | 'page', 44 | ), 45 | ); 46 | ]]> 47 | 48 | 49 | 22, 52 | 'comment_count' => array( 53 | 'value' => 25, 54 | 'compare' => '>=', 55 | ), 56 | 'post_type' => array( 57 | 'post', 58 | 'page', 59 | ), 60 | ); 61 | ]]> 62 | 63 | 64 | 65 | 69 | 70 | 71 | 72 | 'start of phrase' 75 | . 'concatenated additional phrase' 76 | . 'more text', 77 | ); 78 | ]]> 79 | 80 | 81 | 'start of phrase' 84 | . 'concatenated additional phrase' 85 | . 'more text', 86 | ); 87 | ]]> 88 | 89 | 90 | 91 | 92 | 102 | 103 | 104 | << 107 | start of phrase 108 | concatenated additional phrase 109 | more text 110 | EOD 111 | , 112 | ); 113 | ]]> 114 | 115 | 116 | 117 | -------------------------------------------------------------------------------- /WordPress/Docs/Arrays/ArrayKeySpacingRestrictionsStandard.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 10 | 11 | 12 | 13 | [ $post_id ]; 15 | $post_title = $post[ 'concatenated' . $title ]; 16 | $post = $posts[ HOME_PAGE ]; 17 | $post = $posts[123]; 18 | $post_title = $post['post_title']; 19 | ]]> 20 | 21 | 22 | [$post_id]; 24 | $post_title = $post['concatenated' . $title ]; 25 | $post = $posts[HOME_PAGE]; 26 | $post = $posts[ 123 ]; 27 | $post_title = $post[ 'post_title' ]; 28 | ]]> 29 | 30 | 31 | 32 | -------------------------------------------------------------------------------- /WordPress/Docs/Arrays/MultipleStatementAlignmentStandard.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 10 | 11 | 12 | 13 | => 22 ); 15 | $bar = array( 'year' => $current_year ); 16 | ]]> 17 | 18 | 19 | =>22 ); 21 | $bar = array( 'year'=> $current_year ); 22 | ]]> 23 | 24 | 25 | 26 | 29 | 30 | 31 | 32 | => 22, 35 | 'year' => $current_year, 36 | 'monthnum' => $current_month, 37 | ); 38 | ]]> 39 | 40 | 41 | => 22, 44 | 'year' => $current_year, 45 | 'monthnum' => $current_month, 46 | ); 47 | ]]> 48 | 49 | 50 | 51 | -------------------------------------------------------------------------------- /WordPress/Docs/CodeAnalysis/EscapedNotTranslatedStandard.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 11 | 12 | 13 | 14 | esc_html__( 'text', 'domain' ); 16 | ]]> 17 | 18 | 19 | esc_html( 'text', 'domain' ); 21 | ]]> 22 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /WordPress/Docs/DB/PreparedSQLStandard.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | prepare() to escape and quote the contents of variables. This prevents SQL injection. 9 | Use placeholders for all variables used in the query. You should not use variable interpolation or concatenation. 10 | ]]> 11 | 12 | 13 | 14 | prepare( 16 | 'SELECT * from table 17 | WHERE field = %s', 18 | $_GET['foo'] 19 | ); 20 | ]]> 21 | 22 | 23 | query( 25 | "SELECT * from table 26 | WHERE field = {$_GET['foo']}" 27 | ); 28 | ]]> 29 | 30 | 31 | 32 | 33 | 34 | prepare( 36 | 'SELECT * from table 37 | WHERE field = %s', 38 | $value 39 | ); 40 | ]]> 41 | 42 | 43 | get_results( 45 | "SELECT * from table 46 | WHERE field = " . $value 47 | ); 48 | ]]> 49 | 50 | 51 | 52 | -------------------------------------------------------------------------------- /WordPress/Docs/DateTime/CurrentTimeTimestampStandard.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 10 | 11 | 12 | 13 | time(); 15 | ]]> 16 | 17 | 18 | current_time( 'timestamp', true ); 20 | ]]> 21 | 22 | 23 | 24 | 25 | 'Y-m-d' ); 27 | ]]> 28 | 29 | 30 | current_time( 'U', false ); 32 | ]]> 33 | 34 | 35 | 36 | -------------------------------------------------------------------------------- /WordPress/Docs/DateTime/RestrictedFunctionsStandard.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 10 | 11 | 12 | 15 | 16 | 17 | 18 | DateTime(); 20 | $date->setTimezone( 21 | new DateTimeZone( 'Europe/Amsterdam' ) 22 | ); 23 | ]]> 24 | 25 | 26 | date_default_timezone_set( 'Europe/Amsterdam' ); 28 | ]]> 29 | 30 | 31 | 32 | 35 | 36 | 37 | 38 | gmdate( 40 | 'Y-m-d\TH:i:s', 41 | strtotime( $plugin['last_updated'] ) 42 | ); 43 | ]]> 44 | 45 | 46 | date( 48 | 'Y-m-d\TH:i:s', 49 | strtotime( $plugin['last_updated'] ) 50 | ); 51 | ]]> 52 | 53 | 54 | 55 | -------------------------------------------------------------------------------- /WordPress/Docs/NamingConventions/PrefixAllGlobalsStandard.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 16 | 17 | 18 | 19 | 'ECPT_VERSION', '1.0' ); 21 | 22 | $ecpt_admin = new ECPT_Admin_Page(); 23 | 24 | class ECPT_Admin_Page {} 25 | 26 | apply_filter( 27 | 'ecpt_modify_content', 28 | $ecpt_content 29 | ); 30 | ]]> 31 | 32 | 33 | 'PLUGIN_VERSION', '1.0' ); 35 | 36 | $admin = new Admin_Page(); 37 | 38 | class Admin_Page {} 39 | 40 | apply_filter( 41 | 'modify_content', 42 | $content 43 | ); 44 | ]]> 45 | 46 | 47 | 48 | 49 | ECPT_Plugin\Admin; 51 | 52 | // Constants declared using `const` will 53 | // be namespaced and therefore prefixed. 54 | const VERSION = 1.0; 55 | 56 | // A class declared in a (prefixed) namespace 57 | // is automatically prefixed. 58 | class Admin_Page {} 59 | 60 | // Variables in a namespaced file are not 61 | // namespaced, so still need prefixing. 62 | $ecpt_admin = new Admin_Page(); 63 | 64 | // Hook names are not subject to namespacing. 65 | apply_filter( 66 | 'ecpt_modify_content', 67 | $ecpt_content 68 | ); 69 | ]]> 70 | 71 | 72 | Admin; 74 | 75 | // As the namespace is not prefixed, this 76 | // is still bad. 77 | const VERSION = 1.0; 78 | 79 | // As the namespace is not prefixed, this 80 | // is still bad. 81 | class Admin_Page {} 82 | ]]> 83 | 84 | 85 | 86 | 89 | 90 | 91 | 92 | mycoolplugin_save_post() {} 94 | ]]> 95 | 96 | 97 | wp_save_post() {} 99 | ]]> 100 | 101 | 102 | 103 | 106 | 107 | 108 | 109 | MyPluginIsCool {} 111 | ]]> 112 | 113 | 114 | My {} 116 | ]]> 117 | 118 | 119 | 120 | -------------------------------------------------------------------------------- /WordPress/Docs/NamingConventions/ValidFunctionNameStandard.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 10 | 11 | 12 | 13 | prefix_function_name() {} 15 | ]]> 16 | 17 | 18 | Prefix_Function_NAME() {} 20 | ]]> 21 | 22 | 23 | 24 | 25 | method_name() {} 28 | } 29 | ]]> 30 | 31 | 32 | methodName() {} 35 | } 36 | ]]> 37 | 38 | 39 | 40 | -------------------------------------------------------------------------------- /WordPress/Docs/NamingConventions/ValidHookNameStandard.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 10 | 11 | 12 | 13 | 'prefix_hook_name', $var ); 15 | ]]> 16 | 17 | 18 | 'Prefix_Hook_NAME', $var ); 20 | ]]> 21 | 22 | 23 | 24 | 25 | 'prefix_hook_name', $var ); 27 | ]]> 28 | 29 | 30 | 'prefix\hook-name', $var ); 32 | ]]> 33 | 34 | 35 | 36 | -------------------------------------------------------------------------------- /WordPress/Docs/NamingConventions/ValidPostTypeSlugStandard.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 10 | 11 | 12 | 13 | 'my_short_slug', 16 | array() 17 | ); 18 | ]]> 19 | 20 | 21 | 'my_own_post_type_too_long', 24 | array() 25 | ); 26 | ]]> 27 | 28 | 29 | 30 | 33 | 34 | 35 | 36 | 'my_post_type_slug', 39 | array() 40 | ); 41 | ]]> 42 | 43 | 44 | 'my/post/type/slug', 47 | array() 48 | ); 49 | ]]> 50 | 51 | 52 | 53 | 56 | 57 | 58 | 59 | 'my_post_active', 62 | array() 63 | ); 64 | ]]> 65 | 66 | 67 | "my_post_{$status}", 70 | array() 71 | ); 72 | ]]> 73 | 74 | 75 | 76 | 79 | 80 | 81 | 82 | 'prefixed_author', 85 | array() 86 | ); 87 | ]]> 88 | 89 | 90 | 'author', 93 | array() 94 | ); 95 | ]]> 96 | 97 | 98 | 99 | 102 | 103 | 104 | 105 | 'prefixed_author', 108 | array() 109 | ); 110 | ]]> 111 | 112 | 113 | 'wp_author', 116 | array() 117 | ); 118 | ]]> 119 | 120 | 121 | 122 | -------------------------------------------------------------------------------- /WordPress/Docs/NamingConventions/ValidVariableNameStandard.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 10 | 11 | 12 | 13 | $prefix_variable_name = 'value'; 15 | 16 | echo $prefix_variable_name; 17 | ]]> 18 | 19 | 20 | $Prefix_Variable_NAME = 'value'; 22 | 23 | echo $Prefix_Variable_NAME; 24 | ]]> 25 | 26 | 27 | 28 | 29 | $property_name = 'value'; 32 | } 33 | ]]> 34 | 35 | 36 | $propertyName = 'value'; 39 | } 40 | ]]> 41 | 42 | 43 | 44 | -------------------------------------------------------------------------------- /WordPress/Docs/PHP/DontExtractStandard.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 10 | 11 | 12 | 13 | 'My title', 16 | 'content' => 'My content', 17 | 'ID' => 123 18 | ); 19 | echo $post_data['title']; 20 | ]]> 21 | 22 | 23 | 'My title', 26 | 'content' => 'My content', 27 | 'ID' => 123 28 | ); 29 | 30 | extract( $var_array ); 31 | echo $title; 32 | ]]> 33 | 34 | 35 | 36 | -------------------------------------------------------------------------------- /WordPress/Docs/PHP/IniSetStandard.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 10 | 11 | 12 | 13 | 16 | 17 | 18 | 'short_open_tag', 'off' ); 20 | ]]> 21 | 22 | 23 | 24 | 27 | 28 | 29 | 30 | wp_raise_memory_limit(); 32 | ]]> 33 | 34 | 35 | 'memory_limit', '256M' ); 37 | ]]> 38 | 39 | 40 | 41 | -------------------------------------------------------------------------------- /WordPress/Docs/PHP/StrictInArrayStandard.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 12 | 13 | 14 | 15 | true ) ) {} 18 | ]]> 19 | 20 | 21 | ) ) {} 24 | ]]> 25 | 26 | 27 | 28 | 29 | 30 | true ); 32 | ]]> 33 | 34 | 35 | ); 37 | ]]> 38 | 39 | 40 | 41 | 42 | 43 | true ); 45 | ]]> 46 | 47 | 48 | ); 50 | ]]> 51 | 52 | 53 | 54 | -------------------------------------------------------------------------------- /WordPress/Docs/PHP/YodaConditionsStandard.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 10 | 11 | 12 | 13 | true === $the_force ) { 15 | $victorious = you_will( $be ); 16 | } 17 | ]]> 18 | 19 | 20 | $the_force === false ) { 22 | $victorious = you_will_not( $be ); 23 | } 24 | ]]> 25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /WordPress/Docs/Security/SafeRedirectStandard.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 10 | 11 | 12 | 13 | wp_safe_redirect( $location ); 15 | ]]> 16 | 17 | 18 | wp_redirect( $location ); 20 | ]]> 21 | 22 | 23 | 24 | -------------------------------------------------------------------------------- /WordPress/Docs/WP/CapabilitiesStandard.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 10 | 11 | 12 | 13 | 'manage_sites' ) ) { } 15 | ]]> 16 | 17 | 18 | 'manage_site', $user->ID ); 20 | ]]> 21 | 22 | 23 | 24 | 27 | 28 | 29 | 30 | 'manage_options', 35 | 'options_page_slug', 36 | 'project_options_page_cb' 37 | ); 38 | ]]> 39 | 40 | 41 | 'author', 46 | 'options_page_slug', 47 | 'project_options_page_cb' 48 | ); 49 | ]]> 50 | 51 | 52 | 53 | 56 | 57 | 58 | 59 | 'read' ) ) { } 61 | ]]> 62 | 63 | 64 | 'level_6' ) ) { } 66 | ]]> 67 | 68 | 69 | 70 | -------------------------------------------------------------------------------- /WordPress/Docs/WP/CapitalPDangitStandard.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 12 | 13 | 14 | 15 | WordPress_Example { 17 | 18 | /** 19 | * This function is about WordPress. 20 | */ 21 | public function explain() { 22 | echo 'This is an explanation 23 | about WordPress.'; 24 | } 25 | } 26 | ]]> 27 | 28 | 29 | Wordpress_Example { 31 | 32 | /** 33 | * This function is about Wordpress. 34 | */ 35 | public function explain() { 36 | echo 'This is an explanation 37 | about wordpress.'; 38 | } 39 | } 40 | ]]> 41 | 42 | 43 | 44 | -------------------------------------------------------------------------------- /WordPress/Docs/WP/ClassNameCaseStandard.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 10 | 11 | 12 | 13 | 16 | 17 | 18 | 21 | 22 | 23 | 24 | -------------------------------------------------------------------------------- /WordPress/Docs/WP/CronIntervalStandard.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 10 | 11 | 12 | 13 | HOUR_IN_SECONDS, 17 | 'display' => __( 'Every hour' ) 18 | ); 19 | return $schedules; 20 | } 21 | 22 | add_filter( 23 | 'cron_schedules', 24 | 'adjust_schedules' 25 | ); 26 | ]]> 27 | 28 | 29 | 9 * 60, 33 | 'display' => __( 'Every 9 minutes' ) 34 | ); 35 | return $schedules; 36 | } 37 | 38 | add_filter( 39 | 'cron_schedules', 40 | 'adjust_schedules' 41 | ); 42 | ]]> 43 | 44 | 45 | 46 | -------------------------------------------------------------------------------- /WordPress/Docs/WP/DeprecatedClassesStandard.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 10 | 11 | 12 | 13 | WP_User_Query(); 15 | ]]> 16 | 17 | 18 | WP_User_Search(); // Deprecated WP 3.1. 20 | ]]> 21 | 22 | 23 | 24 | -------------------------------------------------------------------------------- /WordPress/Docs/WP/DeprecatedFunctionsStandard.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 10 | 11 | 12 | 13 | get_sites(); 15 | ]]> 16 | 17 | 18 | wp_get_sites(); // Deprecated WP 4.6. 20 | ]]> 21 | 22 | 23 | 24 | -------------------------------------------------------------------------------- /WordPress/Docs/WP/DeprecatedParameterValuesStandard.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 10 | 11 | 12 | 13 | 'url' ); 15 | ]]> 16 | 17 | 18 | 'home' ); // Deprecated WP 2.2.0. 20 | ]]> 21 | 22 | 23 | 24 | -------------------------------------------------------------------------------- /WordPress/Docs/WP/DeprecatedParametersStandard.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | after the deprecated parameter, only ever pass the default value. 10 | ]]> 11 | 12 | 13 | 14 | 18 | 19 | 20 | $string ); 23 | ]]> 24 | 25 | 26 | 27 | 28 | '', 'yes' ); 31 | ]]> 32 | 33 | 34 | 'oops', 'yes' ); 37 | ]]> 38 | 39 | 40 | 41 | -------------------------------------------------------------------------------- /WordPress/Docs/WP/EnqueuedResourceParametersStandard.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 10 | 11 | 12 | 13 | '1.0.0' 19 | ); 20 | ]]> 21 | 22 | 23 | 30 | 31 | 32 | 33 | 36 | 37 | 38 | 39 | '1.0.0', 45 | true 46 | ); 47 | ]]> 48 | 49 | 50 | false, 56 | true 57 | ); 58 | ]]> 59 | 60 | 61 | 62 | 68 | 69 | 70 | 71 | true 78 | ); 79 | ]]> 80 | 81 | 82 | 90 | 91 | 92 | 93 | -------------------------------------------------------------------------------- /WordPress/Docs/WP/EnqueuedResourcesStandard.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 10 | 11 | 12 | 13 | wp_enqueue_script( 15 | 'someScript-js', 16 | $path_to_file, 17 | array( 'jquery' ), 18 | '1.0.0', 19 | true 20 | ); 21 | ]]> 22 | 23 | 24 | ', 27 | esc_url( $path_to_file ) 28 | ); 29 | ]]> 30 | 31 | 32 | 33 | 36 | 37 | 38 | 39 | wp_enqueue_style( 41 | 'style-name', 42 | $path_to_file, 43 | array(), 44 | '1.0.0' 45 | ); 46 | ]]> 47 | 48 | 49 | ', 52 | esc_url( $path_to_file ) 53 | ); 54 | ]]> 55 | 56 | 57 | 58 | -------------------------------------------------------------------------------- /WordPress/Docs/WP/GetMetaSingleStandard.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 18 | 19 | 20 | 21 | 'admin_color', 25 | true 26 | ); 27 | $post_meta = get_metadata( 'post', $post_id ); 28 | ]]> 29 | 30 | 31 | 'admin_color' 35 | ); 36 | ]]> 37 | 38 | 39 | 40 | -------------------------------------------------------------------------------- /WordPress/Docs/WP/PostsPerPageStandard.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 12 | 13 | 14 | 15 | -1, 18 | ); 19 | $args = array( 20 | 'posts_per_page' => 100, 21 | ); 22 | $args = array( 23 | 'posts_per_page' => '10', 24 | ); 25 | 26 | $query_args['posts_per_page'] = 100; 27 | 28 | _query_posts( 'nopaging=1&posts_per_page=50' ); 29 | ]]> 30 | 31 | 32 | 101, 35 | ); 36 | 37 | $query_args['posts_per_page'] = 200; 38 | 39 | _query_posts( 'nopaging=1&posts_per_page=999' ); 40 | ]]> 41 | 42 | 43 | 44 | 45 | -1, 48 | ); 49 | $args = array( 50 | 'numberposts' => 100, 51 | ); 52 | $args = array( 53 | 'numberposts' => '10', 54 | ); 55 | 56 | $query_args['numberposts'] = '-1'; 57 | 58 | _query_posts( 'numberposts=50' ); 59 | ]]> 60 | 61 | 62 | 101, 65 | ); 66 | 67 | $query_args['numberposts'] = '200'; 68 | 69 | _query_posts( 'numberposts=999' ); 70 | ]]> 71 | 72 | 73 | 74 | -------------------------------------------------------------------------------- /WordPress/Docs/WhiteSpace/CastStructureSpacingStandard.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 11 | 12 | 13 | 14 | (int) '420'; 16 | 17 | // No space between spread operator and cast. 18 | $a = function_call( ...(array) $mixed ); 19 | ]]> 20 | 21 | 22 | =(int) '420'; 24 | ]]> 25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /WordPress/Docs/WhiteSpace/ControlStructureSpacingStandard.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 10 | 11 | 12 | 13 | ( have_posts() ) {} 15 | 16 | // For multi-line conditions, 17 | // a new line is also accepted. 18 | if ( true === $condition 19 | && $count > 10 20 | ) {} 21 | ]]> 22 | 23 | 24 | (have_posts()){} 27 | 28 | // Too much space. 29 | while ( have_posts() ) {} 30 | ]]> 31 | 32 | 33 | 34 | 37 | 38 | 39 | 40 | { 42 | // Do something. 43 | } catch ( 44 | ExceptionA | ExceptionB $e 45 | ) { 46 | } 47 | ]]> 48 | 49 | 50 | { 53 | // Do something. 54 | } catch ( Exception $e ) 55 | ( 56 | } 57 | ]]> 58 | 59 | 60 | 61 | 62 | { 64 | // Do something. 65 | } 66 | ]]> 67 | 68 | 69 | { 71 | // Do something. 72 | } 73 | ]]> 74 | 75 | 76 | 77 | 80 | 81 | 82 | 83 | : 85 | // Do something. 86 | endforeach; 87 | ]]> 88 | 89 | 90 | : 92 | // Do something. 93 | endforeach; 94 | ]]> 95 | 96 | 97 | 98 | 101 | 102 | 103 | 104 | 111 | 112 | 113 | 118 | 119 | 120 | } 121 | ]]> 122 | 123 | 124 | 125 | 129 | 130 | 131 | 132 | 137 | 138 | 139 | 142 | 143 | echo $a; 144 | 145 | 146 | } 147 | ]]> 148 | 149 | 150 | 151 | -------------------------------------------------------------------------------- /WordPress/Docs/WhiteSpace/ObjectOperatorSpacingStandard.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | , ?->, ::) should not have any spaces around them, though new lines are allowed except for use with the `::class` constant. 9 | ]]> 10 | 11 | 12 | 13 | ->bar(); 15 | ]]> 16 | 17 | 18 | ?-> bar(); 20 | ]]> 21 | 22 | 23 | 24 | -------------------------------------------------------------------------------- /WordPress/Docs/WhiteSpace/OperatorSpacingStandard.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 11 | 12 | 13 | 14 | === $b && $b === $c ) {} 16 | if ( ! $var ) {} 17 | ]]> 18 | 19 | 20 | && $b === $c ) {} 23 | if ( ! $var ) {} 24 | 25 | // Too little space. 26 | if ( $a===$b &&$b ===$c ) {} 27 | if ( !$var ) {} 28 | ]]> 29 | 30 | 31 | 32 | 33 | 35 | && $b === $c 36 | ) {} 37 | ]]> 38 | 39 | 40 | 42 | && $b === $c 43 | ) {} 44 | ]]> 45 | 46 | 47 | 48 | 49 | = 'foo'; 51 | $all = 'foobar'; 52 | ]]> 53 | 54 | 55 | = 'foo'; 57 | $all ='foobar'; 58 | ]]> 59 | 60 | 61 | 62 | -------------------------------------------------------------------------------- /WordPress/Helpers/ArrayWalkingFunctionsHelper.php: -------------------------------------------------------------------------------- 1 | 41 | */ 42 | private static $arrayWalkingFunctions = array( 43 | 'array_map' => array( 44 | 'position' => 1, 45 | 'name' => 'callback', 46 | ), 47 | 'map_deep' => array( 48 | 'position' => 2, 49 | 'name' => 'callback', 50 | ), 51 | ); 52 | 53 | /** 54 | * Retrieve a list of the supported "array walking" functions. 55 | * 56 | * @since 3.0.0 57 | * 58 | * @return array 59 | */ 60 | public static function get_functions() { 61 | return \array_fill_keys( \array_keys( self::$arrayWalkingFunctions ), true ); 62 | } 63 | 64 | /** 65 | * Check if a particular function is an "array walking" function. 66 | * 67 | * @since 3.0.0 68 | * 69 | * @param string $functionName The name of the function to check. 70 | * 71 | * @return bool 72 | */ 73 | public static function is_array_walking_function( $functionName ) { 74 | return isset( self::$arrayWalkingFunctions[ strtolower( $functionName ) ] ); 75 | } 76 | 77 | /** 78 | * Retrieve the parameter information for the callback parameter for an array walking function. 79 | * 80 | * @since 3.0.0 81 | * 82 | * @param \PHP_CodeSniffer\Files\File $phpcsFile The file where this token was found. 83 | * @param int $stackPtr The position of function call name token. 84 | * 85 | * @return array|false Array with information on the callback parameter. 86 | * Or `FALSE` if the parameter is not found. 87 | * See the PHPCSUtils PassedParameters::getParameters() documentation 88 | * for the format of the returned (single-dimensional) array. 89 | */ 90 | public static function get_callback_parameter( File $phpcsFile, $stackPtr ) { 91 | $tokens = $phpcsFile->getTokens(); 92 | if ( isset( $tokens[ $stackPtr ] ) === false ) { 93 | return false; 94 | } 95 | 96 | $functionName = strtolower( $tokens[ $stackPtr ]['content'] ); 97 | if ( isset( self::$arrayWalkingFunctions[ $functionName ] ) === false ) { 98 | return false; 99 | } 100 | 101 | return PassedParameters::getParameter( 102 | $phpcsFile, 103 | $stackPtr, 104 | self::$arrayWalkingFunctions[ $functionName ]['position'], 105 | self::$arrayWalkingFunctions[ $functionName ]['name'] 106 | ); 107 | } 108 | } 109 | -------------------------------------------------------------------------------- /WordPress/Helpers/ConstantsHelper.php: -------------------------------------------------------------------------------- 1 | getTokens(); 51 | 52 | // Check for the existence of the token. 53 | if ( ! isset( $tokens[ $stackPtr ] ) ) { 54 | return false; 55 | } 56 | 57 | // Is this one of the tokens this function handles ? 58 | if ( \T_STRING !== $tokens[ $stackPtr ]['code'] ) { 59 | return false; 60 | } 61 | 62 | $next = $phpcsFile->findNext( Tokens::$emptyTokens, ( $stackPtr + 1 ), null, true ); 63 | if ( false !== $next 64 | && ( \T_OPEN_PARENTHESIS === $tokens[ $next ]['code'] 65 | || \T_DOUBLE_COLON === $tokens[ $next ]['code'] ) 66 | ) { 67 | // Function call or declaration. 68 | return false; 69 | } 70 | 71 | // Array of tokens which if found preceding the $stackPtr indicate that a T_STRING is not a global constant. 72 | $tokens_to_ignore = array( 73 | \T_NAMESPACE => true, 74 | \T_USE => true, 75 | \T_EXTENDS => true, 76 | \T_IMPLEMENTS => true, 77 | \T_NEW => true, 78 | \T_FUNCTION => true, 79 | \T_INSTANCEOF => true, 80 | \T_INSTEADOF => true, 81 | \T_GOTO => true, 82 | ); 83 | $tokens_to_ignore += Tokens::$ooScopeTokens; 84 | $tokens_to_ignore += Collections::objectOperators(); 85 | $tokens_to_ignore += Tokens::$scopeModifiers; 86 | 87 | $prev = $phpcsFile->findPrevious( Tokens::$emptyTokens, ( $stackPtr - 1 ), null, true ); 88 | if ( isset( $tokens_to_ignore[ $tokens[ $prev ]['code'] ] ) ) { 89 | // Not the use of a constant. 90 | return false; 91 | } 92 | 93 | if ( ContextHelper::is_token_namespaced( $phpcsFile, $stackPtr ) === true ) { 94 | // Namespaced constant of the same name. 95 | return false; 96 | } 97 | 98 | if ( \T_CONST === $tokens[ $prev ]['code'] 99 | && Scopes::isOOConstant( $phpcsFile, $prev ) 100 | ) { 101 | // Class constant declaration of the same name. 102 | return false; 103 | } 104 | 105 | /* 106 | * Deal with a number of variations of use statements. 107 | */ 108 | for ( $i = $stackPtr; $i > 0; $i-- ) { 109 | if ( $tokens[ $i ]['line'] !== $tokens[ $stackPtr ]['line'] ) { 110 | break; 111 | } 112 | } 113 | 114 | $firstOnLine = $phpcsFile->findNext( Tokens::$emptyTokens, ( $i + 1 ), null, true ); 115 | if ( false !== $firstOnLine && \T_USE === $tokens[ $firstOnLine ]['code'] ) { 116 | $nextOnLine = $phpcsFile->findNext( Tokens::$emptyTokens, ( $firstOnLine + 1 ), null, true ); 117 | if ( false !== $nextOnLine ) { 118 | if ( \T_STRING === $tokens[ $nextOnLine ]['code'] 119 | && 'const' === $tokens[ $nextOnLine ]['content'] 120 | ) { 121 | $hasNsSep = $phpcsFile->findNext( \T_NS_SEPARATOR, ( $nextOnLine + 1 ), $stackPtr ); 122 | if ( false !== $hasNsSep ) { 123 | // Namespaced const (group) use statement. 124 | return false; 125 | } 126 | } else { 127 | // Not a const use statement. 128 | return false; 129 | } 130 | } 131 | } 132 | 133 | return true; 134 | } 135 | } 136 | -------------------------------------------------------------------------------- /WordPress/Helpers/DeprecationHelper.php: -------------------------------------------------------------------------------- 1 | getTokens(); 48 | if ( isset( $tokens[ $stackPtr ] ) === false ) { 49 | return false; 50 | } 51 | 52 | $ignore = Tokens::$methodPrefixes; 53 | $ignore[ \T_WHITESPACE ] = \T_WHITESPACE; 54 | 55 | for ( $comment_end = ( $stackPtr - 1 ); $comment_end >= 0; $comment_end-- ) { 56 | if ( isset( $ignore[ $tokens[ $comment_end ]['code'] ] ) === true ) { 57 | continue; 58 | } 59 | 60 | if ( \T_ATTRIBUTE_END === $tokens[ $comment_end ]['code'] 61 | && isset( $tokens[ $comment_end ]['attribute_opener'] ) === true 62 | ) { 63 | $comment_end = $tokens[ $comment_end ]['attribute_opener']; 64 | continue; 65 | } 66 | 67 | break; 68 | } 69 | 70 | if ( \T_DOC_COMMENT_CLOSE_TAG !== $tokens[ $comment_end ]['code'] ) { 71 | // Function doesn't have a doc comment or is using the wrong type of comment. 72 | return false; 73 | } 74 | 75 | $comment_start = $tokens[ $comment_end ]['comment_opener']; 76 | foreach ( $tokens[ $comment_start ]['comment_tags'] as $tag ) { 77 | if ( '@deprecated' === $tokens[ $tag ]['content'] ) { 78 | return true; 79 | } 80 | } 81 | 82 | return false; 83 | } 84 | } 85 | -------------------------------------------------------------------------------- /WordPress/Helpers/FormattingFunctionsHelper.php: -------------------------------------------------------------------------------- 1 | 35 | */ 36 | private static $formattingFunctions = array( 37 | 'antispambot' => true, 38 | 'array_fill' => true, 39 | 'ent2ncr' => true, 40 | 'implode' => true, 41 | 'join' => true, 42 | 'nl2br' => true, 43 | 'sprintf' => true, 44 | 'vsprintf' => true, 45 | 'wp_sprintf' => true, 46 | ); 47 | 48 | /** 49 | * Check if a particular function is regarded as a formatting function. 50 | * 51 | * @since 3.0.0 52 | * 53 | * @param string $functionName The name of the function to check. 54 | * 55 | * @return bool 56 | */ 57 | public static function is_formatting_function( $functionName ) { 58 | return isset( self::$formattingFunctions[ strtolower( $functionName ) ] ); 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /WordPress/Helpers/ListHelper.php: -------------------------------------------------------------------------------- 1 | getTokens(); 56 | 57 | // Is this one of the tokens this function handles ? 58 | if ( isset( $tokens[ $stackPtr ], Collections::listOpenTokensBC()[ $tokens[ $stackPtr ]['code'] ] ) === false ) { 59 | return array(); 60 | } 61 | 62 | if ( isset( Collections::shortArrayListOpenTokensBC()[ $tokens[ $stackPtr ]['code'] ] ) 63 | && Lists::isShortList( $phpcsFile, $stackPtr ) === false 64 | ) { 65 | return array(); 66 | } 67 | 68 | try { 69 | $assignments = Lists::getAssignments( $phpcsFile, $stackPtr ); 70 | } catch ( RuntimeException $e ) { 71 | // Parse error/live coding. 72 | return array(); 73 | } 74 | 75 | $var_pointers = array(); 76 | 77 | foreach ( $assignments as $assign ) { 78 | if ( true === $assign['is_empty'] ) { 79 | continue; 80 | } 81 | 82 | if ( true === $assign['is_nested_list'] ) { 83 | /* 84 | * Recurse into the nested list and get the variables. 85 | * No need to `catch` any errors as only lists can be nested in lists. 86 | */ 87 | $var_pointers += self::get_list_variables( $phpcsFile, $assign['assignment_token'] ); 88 | continue; 89 | } 90 | 91 | /* 92 | * Ok, so this must be a "normal" assignment in the list. 93 | * Set the variable pointer both as the key as well as the value, so we can use array join 94 | * for nested lists (above). 95 | */ 96 | $var_pointers[ $assign['assignment_token'] ] = $assign['assignment_token']; 97 | } 98 | 99 | return $var_pointers; 100 | } 101 | } 102 | -------------------------------------------------------------------------------- /WordPress/Helpers/MinimumWPVersionTrait.php: -------------------------------------------------------------------------------- 1 | 49 | * 50 | * 51 | * 52 | * 53 | * 54 | * Alternatively, the value can be passed in one go for all sniffs using it via 55 | * the command line or by setting a `` value in a custom phpcs.xml ruleset. 56 | * 57 | * CL: `phpcs --runtime-set minimum_wp_version 5.7` 58 | * Ruleset: `` 59 | * 60 | * @since 0.14.0 Previously the individual sniffs each contained this property. 61 | * @since 3.0.0 - Moved from the Sniff class to this dedicated Trait. 62 | * - The property has been renamed from `$minimum_supported_version` to `$minimum_wp_version`. 63 | * - The CLI option has been renamed from `minimum_supported_wp_version` to `minimum_wp_version`. 64 | * 65 | * @var string WordPress version. 66 | */ 67 | public $minimum_wp_version; 68 | 69 | /** 70 | * Default minimum supported WordPress version. 71 | * 72 | * By default, the minimum_wp_version presumes that a project will support the current 73 | * WP version and up to three releases before. 74 | * 75 | * {@internal This should be a constant, but constants in traits are not supported 76 | * until PHP 8.2.}} 77 | * 78 | * @since 3.0.0 79 | * 80 | * @var string WordPress version. 81 | */ 82 | private $default_minimum_wp_version = '6.2'; 83 | 84 | /** 85 | * Overrule the minimum supported WordPress version with a command-line/config value. 86 | * 87 | * Handle setting the minimum supported WP version in one go for all sniffs which 88 | * expect it via the command line or via a `` variable in a ruleset. 89 | * The config variable overrules the default `$minimum_wp_version` and/or a 90 | * `$minimum_wp_version` set for individual sniffs through the ruleset. 91 | * 92 | * @since 0.14.0 93 | * @since 3.0.0 - Moved from the Sniff class to this dedicated Trait. 94 | * - Renamed from `get_wp_version_from_cl()` to `set_minimum_wp_version()`. 95 | * 96 | * @return void 97 | */ 98 | final protected function set_minimum_wp_version() { 99 | $minimum_wp_version = ''; 100 | 101 | // Use a ruleset provided value if available. 102 | if ( ! empty( $this->minimum_wp_version ) ) { 103 | $minimum_wp_version = $this->minimum_wp_version; 104 | } 105 | 106 | // A CLI provided value overrules a ruleset provided value. 107 | $cli_supported_version = Helper::getConfigData( 'minimum_wp_version' ); 108 | if ( ! empty( $cli_supported_version ) ) { 109 | $minimum_wp_version = $cli_supported_version; 110 | } 111 | 112 | // If no valid value was provided, use the default. 113 | if ( filter_var( $minimum_wp_version, \FILTER_VALIDATE_FLOAT ) === false ) { 114 | $minimum_wp_version = $this->default_minimum_wp_version; 115 | } 116 | 117 | $this->minimum_wp_version = $minimum_wp_version; 118 | } 119 | 120 | /** 121 | * Compares two version numbers. 122 | * 123 | * @since 3.0.0 124 | * 125 | * @param string $version1 First version number. 126 | * @param string $version2 Second version number. 127 | * @param string $operator Comparison operator. 128 | * 129 | * @return bool 130 | */ 131 | final protected function wp_version_compare( $version1, $version2, $operator ) { 132 | $version1 = $this->normalize_version_number( $version1 ); 133 | $version2 = $this->normalize_version_number( $version2 ); 134 | 135 | return version_compare( $version1, $version2, $operator ); 136 | } 137 | 138 | /** 139 | * Normalize a version number. 140 | * 141 | * Ensures that a version number is comparable via the PHP version_compare() function 142 | * by making sure it complies with the minimum "PHP-standardized" version number requirements. 143 | * 144 | * Presumes the input is a numeric version number string. The behaviour with other input is undefined. 145 | * 146 | * @since 3.0.0 147 | * 148 | * @param string $version Version number. 149 | * 150 | * @return string 151 | */ 152 | private function normalize_version_number( $version ) { 153 | if ( preg_match( '`^\d+\.\d+$`', $version ) ) { 154 | $version .= '.0'; 155 | } 156 | 157 | return $version; 158 | } 159 | } 160 | -------------------------------------------------------------------------------- /WordPress/Helpers/PrintingFunctionsTrait.php: -------------------------------------------------------------------------------- 1 | 46 | */ 47 | private $printingFunctions = array( 48 | '_deprecated_argument' => true, 49 | '_deprecated_constructor' => true, 50 | '_deprecated_file' => true, 51 | '_deprecated_function' => true, 52 | '_deprecated_hook' => true, 53 | '_doing_it_wrong' => true, 54 | '_e' => true, 55 | '_ex' => true, 56 | 'printf' => true, 57 | 'trigger_error' => true, 58 | 'user_error' => true, 59 | 'vprintf' => true, 60 | 'wp_die' => true, 61 | 'wp_dropdown_pages' => true, 62 | ); 63 | 64 | /** 65 | * Cache of previously added custom functions. 66 | * 67 | * Prevents having to do the same merges over and over again. 68 | * 69 | * @since 0.4.0 70 | * @since 0.11.0 - Changed from public static to protected non-static. 71 | * - Changed the format from simple bool to array. 72 | * @since 3.0.0 - Moved from the EscapeOutput Sniff class to this trait. 73 | * - Visibility changed from protected to private. 74 | * 75 | * @var string[] 76 | */ 77 | private $addedCustomPrintingFunctions = array(); 78 | 79 | /** 80 | * Combined list of WP/PHP native and custom printing functions. 81 | * 82 | * @since 3.0.0 83 | * 84 | * @var array 85 | */ 86 | private $allPrintingFunctions = array(); 87 | 88 | /** 89 | * Retrieve a list of all known printing functions. 90 | * 91 | * @since 3.0.0 92 | * 93 | * @return array 94 | */ 95 | final public function get_printing_functions() { 96 | if ( array() === $this->allPrintingFunctions 97 | || $this->customPrintingFunctions !== $this->addedCustomPrintingFunctions 98 | ) { 99 | $this->allPrintingFunctions = RulesetPropertyHelper::merge_custom_array( 100 | $this->customPrintingFunctions, 101 | $this->printingFunctions 102 | ); 103 | 104 | $this->addedCustomPrintingFunctions = $this->customPrintingFunctions; 105 | } 106 | 107 | return $this->allPrintingFunctions; 108 | } 109 | 110 | /** 111 | * Check if a particular function is regarded as a printing function. 112 | * 113 | * @since 3.0.0 114 | * 115 | * @param string $functionName The name of the function to check. 116 | * 117 | * @return bool 118 | */ 119 | final public function is_printing_function( $functionName ) { 120 | return isset( $this->get_printing_functions()[ strtolower( $functionName ) ] ); 121 | } 122 | } 123 | -------------------------------------------------------------------------------- /WordPress/Helpers/RulesetPropertyHelper.php: -------------------------------------------------------------------------------- 1 | true` format. 34 | * * Any custom items will be given the value `false` to be able to 35 | * distinguish them from pre-set (base array) values. 36 | * * Will filter previously added custom items out from the base array 37 | * before merging/returning to allow for resetting to the base array. 38 | * 39 | * {@internal Function is static as it doesn't use any of the properties or others 40 | * methods anyway.} 41 | * 42 | * @since 0.11.0 43 | * @since 2.0.0 No longer supports custom array properties which were incorrectly 44 | * passed as a string. 45 | * @since 3.0.0 Moved from the Sniff class to this class. 46 | * 47 | * @param array $custom Custom list as provided via a ruleset. 48 | * @param array $base Optional. Base list. Defaults to an empty array. 49 | * Expects `value => true` format when `$flip` is true. 50 | * @param bool $flip Optional. Whether or not to flip the custom list. 51 | * Defaults to true. 52 | * @return array 53 | */ 54 | public static function merge_custom_array( $custom, array $base = array(), $flip = true ) { 55 | if ( true === $flip ) { 56 | $base = array_filter( $base ); 57 | } 58 | 59 | if ( empty( $custom ) || ! \is_array( $custom ) ) { 60 | return $base; 61 | } 62 | 63 | if ( true === $flip ) { 64 | $custom = array_fill_keys( $custom, false ); 65 | } 66 | 67 | if ( empty( $base ) ) { 68 | return $custom; 69 | } 70 | 71 | return array_merge( $base, $custom ); 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /WordPress/Helpers/SnakeCaseHelper.php: -------------------------------------------------------------------------------- 1 | 29 | */ 30 | private static $unslashingFunctions = array( 31 | 'stripslashes_deep' => true, 32 | 'stripslashes_from_strings_only' => true, 33 | 'wp_unslash' => true, 34 | ); 35 | 36 | /** 37 | * Retrieve a list of the unslashing functions. 38 | * 39 | * @since 3.0.0 40 | * 41 | * @return array 42 | */ 43 | public static function get_functions() { 44 | return self::$unslashingFunctions; 45 | } 46 | 47 | /** 48 | * Check if a particular function is regarded as a unslashing function. 49 | * 50 | * @since 3.0.0 51 | * 52 | * @param string $functionName The name of the function to check. 53 | * 54 | * @return bool 55 | */ 56 | public static function is_unslashing_function( $functionName ) { 57 | return isset( self::$unslashingFunctions[ strtolower( $functionName ) ] ); 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /WordPress/Helpers/WPDBTrait.php: -------------------------------------------------------------------------------- 1 | getTokens(); 52 | if ( isset( $tokens[ $stackPtr ] ) === false ) { 53 | return false; 54 | } 55 | 56 | // Check for wpdb. 57 | if ( ( \T_VARIABLE === $tokens[ $stackPtr ]['code'] && '$wpdb' !== $tokens[ $stackPtr ]['content'] ) 58 | || ( \T_STRING === $tokens[ $stackPtr ]['code'] && 'wpdb' !== strtolower( $tokens[ $stackPtr ]['content'] ) ) 59 | ) { 60 | return false; 61 | } 62 | 63 | // Check that this is a method call. 64 | $is_object_call = $phpcsFile->findNext( Tokens::$emptyTokens, ( $stackPtr + 1 ), null, true ); 65 | if ( false === $is_object_call 66 | || isset( Collections::objectOperators()[ $tokens[ $is_object_call ]['code'] ] ) === false 67 | ) { 68 | return false; 69 | } 70 | 71 | $methodPtr = $phpcsFile->findNext( Tokens::$emptyTokens, ( $is_object_call + 1 ), null, true, null, true ); 72 | if ( false === $methodPtr ) { 73 | return false; 74 | } 75 | 76 | if ( \T_STRING === $tokens[ $methodPtr ]['code'] && property_exists( $this, 'methodPtr' ) ) { 77 | $this->methodPtr = $methodPtr; 78 | } 79 | 80 | // Find the opening parenthesis. 81 | $opening_paren = $phpcsFile->findNext( Tokens::$emptyTokens, ( $methodPtr + 1 ), null, true, null, true ); 82 | 83 | if ( false === $opening_paren ) { 84 | return false; 85 | } 86 | 87 | if ( property_exists( $this, 'i' ) ) { 88 | $this->i = $opening_paren; 89 | } 90 | 91 | if ( \T_OPEN_PARENTHESIS !== $tokens[ $opening_paren ]['code'] 92 | || ! isset( $tokens[ $opening_paren ]['parenthesis_closer'] ) 93 | ) { 94 | return false; 95 | } 96 | 97 | // Check that this is one of the methods that we are interested in. 98 | if ( ! isset( $target_methods[ strtolower( $tokens[ $methodPtr ]['content'] ) ] ) ) { 99 | return false; 100 | } 101 | 102 | // Find the end of the first parameter. 103 | $end = BCFile::findEndOfStatement( $phpcsFile, $opening_paren + 1 ); 104 | 105 | if ( \T_COMMA !== $tokens[ $end ]['code'] ) { 106 | ++$end; 107 | } 108 | 109 | if ( property_exists( $this, 'end' ) ) { 110 | $this->end = $end; 111 | } 112 | 113 | return true; 114 | } 115 | } 116 | -------------------------------------------------------------------------------- /WordPress/Helpers/WPHookHelper.php: -------------------------------------------------------------------------------- 1 | > Function name as key, array with target 34 | * parameter position and name(s) as value. 35 | */ 36 | private static $hookInvokeFunctions = array( 37 | 'do_action' => array( 38 | 'position' => 1, 39 | 'name' => 'hook_name', 40 | ), 41 | 'do_action_ref_array' => array( 42 | 'position' => 1, 43 | 'name' => 'hook_name', 44 | ), 45 | 'do_action_deprecated' => array( 46 | 'position' => 1, 47 | 'name' => 'hook_name', 48 | ), 49 | 'apply_filters' => array( 50 | 'position' => 1, 51 | 'name' => 'hook_name', 52 | ), 53 | 'apply_filters_ref_array' => array( 54 | 'position' => 1, 55 | 'name' => 'hook_name', 56 | ), 57 | 'apply_filters_deprecated' => array( 58 | 'position' => 1, 59 | 'name' => 'hook_name', 60 | ), 61 | ); 62 | 63 | /** 64 | * Retrieve a list of the WordPress functions which invoke hooks. 65 | * 66 | * @since 3.0.0 67 | * 68 | * @param bool $include_deprecated Whether to include the names of functions 69 | * which are used to invoke deprecated hooks. 70 | * Defaults to `true`. 71 | * 72 | * @return array Array with the function names as keys. The value is irrelevant. 73 | */ 74 | public static function get_functions( $include_deprecated = true ) { 75 | $hooks = array_fill_keys( array_keys( self::$hookInvokeFunctions ), true ); 76 | if ( false === $include_deprecated ) { 77 | unset( 78 | $hooks['do_action_deprecated'], 79 | $hooks['apply_filters_deprecated'] 80 | ); 81 | } 82 | 83 | return $hooks; 84 | } 85 | 86 | /** 87 | * Retrieve the parameter information for the hook name parameter from a stack of parameters 88 | * passed to one of the WP hook functions. 89 | * 90 | * @since 3.0.0 91 | * 92 | * @param string $function_name The name of the WP hook function which the parameters were passed to. 93 | * @param array $parameters The output of a previous call to PassedParameters::getParameters(). 94 | * 95 | * @return array|false Array with information on the parameter at the specified offset, 96 | * or with the specified name. 97 | * Or `FALSE` if the specified parameter is not found. 98 | * See the PHPCSUtils PassedParameters::getParameters() documentation 99 | * for the format of the returned (single-dimensional) array. 100 | */ 101 | public static function get_hook_name_param( $function_name, array $parameters ) { 102 | $function_lc = strtolower( $function_name ); 103 | if ( isset( self::$hookInvokeFunctions[ $function_lc ] ) === false ) { 104 | return false; 105 | } 106 | 107 | return PassedParameters::getParameterFromStack( 108 | $parameters, 109 | self::$hookInvokeFunctions[ $function_lc ]['position'], 110 | self::$hookInvokeFunctions[ $function_lc ]['name'] 111 | ); 112 | } 113 | } 114 | -------------------------------------------------------------------------------- /WordPress/Sniff.php: -------------------------------------------------------------------------------- 1 | phpcsFile = $phpcsFile; 56 | $this->tokens = $phpcsFile->getTokens(); 57 | 58 | return $this->process_token( $stackPtr ); 59 | } 60 | 61 | /** 62 | * Processes a sniff when one of its tokens is encountered. 63 | * 64 | * @since 0.11.0 65 | * 66 | * @param int $stackPtr The position of the current token in the stack. 67 | * 68 | * @return int|void Integer stack pointer to skip forward or void to continue 69 | * normal file processing. 70 | */ 71 | abstract public function process_token( $stackPtr ); 72 | } 73 | -------------------------------------------------------------------------------- /WordPress/Sniffs/Arrays/ArrayKeySpacingRestrictionsSniff.php: -------------------------------------------------------------------------------- 1 | tokens[ $stackPtr ]; 49 | if ( ! isset( $token['bracket_closer'] ) ) { 50 | return; 51 | } 52 | 53 | /* 54 | * Handle square brackets without a key (array assignments) first. 55 | */ 56 | $first_non_ws = $this->phpcsFile->findNext( \T_WHITESPACE, ( $stackPtr + 1 ), null, true ); 57 | if ( $first_non_ws === $token['bracket_closer'] ) { 58 | $error = 'There should be %1$s between the square brackets for an array assignment without an explicit key. Found: %2$s'; 59 | SpacesFixer::checkAndFix( 60 | $this->phpcsFile, 61 | $stackPtr, 62 | $token['bracket_closer'], 63 | 0, 64 | $error, 65 | 'SpacesBetweenBrackets' 66 | ); 67 | 68 | return; 69 | } 70 | 71 | /* 72 | * Handle the spaces around explicit array keys. 73 | */ 74 | $needs_spaces = true; 75 | 76 | // Skip over a potential plus/minus sign for integers. 77 | $first_effective = $first_non_ws; 78 | if ( \T_MINUS === $this->tokens[ $first_effective ]['code'] || \T_PLUS === $this->tokens[ $first_effective ]['code'] ) { 79 | $first_effective = $this->phpcsFile->findNext( \T_WHITESPACE, ( $first_effective + 1 ), null, true ); 80 | } 81 | 82 | $next_non_ws = $this->phpcsFile->findNext( \T_WHITESPACE, ( $first_effective + 1 ), null, true ); 83 | if ( ( \T_CONSTANT_ENCAPSED_STRING === $this->tokens[ $first_effective ]['code'] 84 | || \T_LNUMBER === $this->tokens[ $first_effective ]['code'] ) 85 | && $next_non_ws === $token['bracket_closer'] 86 | ) { 87 | $needs_spaces = false; 88 | } 89 | 90 | $has_space_after_opener = ( \T_WHITESPACE === $this->tokens[ ( $stackPtr + 1 ) ]['code'] ); 91 | $has_space_before_close = ( \T_WHITESPACE === $this->tokens[ ( $token['bracket_closer'] - 1 ) ]['code'] ); 92 | 93 | // The array key should be surrounded by spaces unless the key only consists of a string or an integer. 94 | if ( true === $needs_spaces 95 | && ( false === $has_space_after_opener || false === $has_space_before_close ) 96 | ) { 97 | $error = 'Array keys must be surrounded by spaces unless they contain a string or an integer.'; 98 | $fix = $this->phpcsFile->addFixableError( $error, $stackPtr, 'NoSpacesAroundArrayKeys' ); 99 | if ( true === $fix ) { 100 | $this->phpcsFile->fixer->beginChangeset(); 101 | 102 | if ( false === $has_space_after_opener ) { 103 | $this->phpcsFile->fixer->addContent( $stackPtr, ' ' ); 104 | } 105 | 106 | if ( false === $has_space_before_close ) { 107 | $this->phpcsFile->fixer->addContentBefore( $token['bracket_closer'], ' ' ); 108 | } 109 | 110 | $this->phpcsFile->fixer->endChangeset(); 111 | } 112 | } elseif ( false === $needs_spaces && ( $has_space_after_opener || $has_space_before_close ) ) { 113 | $error = 'Array keys must NOT be surrounded by spaces if they only contain a string or an integer.'; 114 | $fix = $this->phpcsFile->addFixableError( $error, $stackPtr, 'SpacesAroundArrayKeys' ); 115 | if ( true === $fix ) { 116 | if ( $has_space_after_opener ) { 117 | $this->phpcsFile->fixer->beginChangeset(); 118 | 119 | for ( $i = ( $stackPtr + 1 ); $i < $token['bracket_closer']; $i++ ) { 120 | if ( \T_WHITESPACE !== $this->tokens[ $i ]['code'] ) { 121 | break; 122 | } 123 | 124 | $this->phpcsFile->fixer->replaceToken( $i, '' ); 125 | } 126 | 127 | $this->phpcsFile->fixer->endChangeset(); 128 | } 129 | 130 | if ( $has_space_before_close ) { 131 | $this->phpcsFile->fixer->beginChangeset(); 132 | 133 | for ( $i = ( $token['bracket_closer'] - 1 ); $i > $stackPtr; $i-- ) { 134 | if ( \T_WHITESPACE !== $this->tokens[ $i ]['code'] ) { 135 | break; 136 | } 137 | 138 | $this->phpcsFile->fixer->replaceToken( $i, '' ); 139 | } 140 | 141 | $this->phpcsFile->fixer->endChangeset(); 142 | } 143 | } 144 | } 145 | 146 | // If spaces are needed, check that there is only one space. 147 | if ( true === $needs_spaces ) { 148 | if ( $has_space_after_opener ) { 149 | $error = 'There should be exactly %1$s before the array key. Found: %2$s'; 150 | SpacesFixer::checkAndFix( 151 | $this->phpcsFile, 152 | $stackPtr, 153 | $first_non_ws, 154 | 1, 155 | $error, 156 | 'TooMuchSpaceBeforeKey' 157 | ); 158 | } 159 | 160 | if ( $has_space_before_close ) { 161 | $last_non_ws = $this->phpcsFile->findPrevious( \T_WHITESPACE, ( $token['bracket_closer'] - 1 ), null, true ); 162 | $error = 'There should be exactly %1$s after the array key. Found: %2$s'; 163 | SpacesFixer::checkAndFix( 164 | $this->phpcsFile, 165 | $last_non_ws, 166 | $token['bracket_closer'], 167 | 1, 168 | $error, 169 | 'TooMuchSpaceAfterKey' 170 | ); 171 | } 172 | } 173 | } 174 | } 175 | -------------------------------------------------------------------------------- /WordPress/Sniffs/CodeAnalysis/AssignmentInTernaryConditionSniff.php: -------------------------------------------------------------------------------- 1 | assignment_tokens = Tokens::$assignmentTokens; 62 | unset( $this->assignment_tokens[ \T_DOUBLE_ARROW ] ); 63 | 64 | $starters = Tokens::$booleanOperators; 65 | $starters[ \T_SEMICOLON ] = \T_SEMICOLON; 66 | $starters[ \T_OPEN_PARENTHESIS ] = \T_OPEN_PARENTHESIS; 67 | $starters[ \T_INLINE_ELSE ] = \T_INLINE_ELSE; 68 | 69 | $this->condition_start_tokens = $starters; 70 | 71 | return array( 72 | \T_INLINE_THEN, 73 | ); 74 | } 75 | 76 | /** 77 | * Processes this test, when one of its tokens is encountered. 78 | * 79 | * @since 0.14.0 80 | * 81 | * @param int $stackPtr The position of the current token in the stack. 82 | * 83 | * @return void 84 | */ 85 | public function process_token( $stackPtr ) { 86 | 87 | $token = $this->tokens[ $stackPtr ]; 88 | 89 | // Check if the condition for the ternary is bracketed. 90 | $prev = $this->phpcsFile->findPrevious( Tokens::$emptyTokens, ( $stackPtr - 1 ), null, true ); 91 | if ( \T_CLOSE_PARENTHESIS === $this->tokens[ $prev ]['code'] ) { 92 | if ( ! isset( $this->tokens[ $prev ]['parenthesis_opener'] ) ) { 93 | return; 94 | } 95 | 96 | $opener = $this->tokens[ $prev ]['parenthesis_opener']; 97 | $closer = $prev; 98 | } elseif ( isset( $token['nested_parenthesis'] ) ) { 99 | $opener = Parentheses::getLastOpener( $this->phpcsFile, $stackPtr ); 100 | $closer = Parentheses::getLastCloser( $this->phpcsFile, $stackPtr ); 101 | 102 | $next_statement_closer = BCFile::findEndOfStatement( $this->phpcsFile, $stackPtr, array( \T_COLON, \T_CLOSE_PARENTHESIS, \T_CLOSE_SQUARE_BRACKET ) ); 103 | if ( false !== $next_statement_closer && $next_statement_closer < $closer ) { 104 | // Parentheses are unrelated to the ternary. 105 | return; 106 | } 107 | 108 | $prev_statement_closer = BCFile::findStartOfStatement( $this->phpcsFile, $stackPtr, array( \T_COLON, \T_OPEN_PARENTHESIS, \T_OPEN_SQUARE_BRACKET ) ); 109 | if ( false !== $prev_statement_closer && $opener < $prev_statement_closer ) { 110 | // Parentheses are unrelated to the ternary. 111 | return; 112 | } 113 | 114 | if ( $closer > $stackPtr ) { 115 | $closer = $stackPtr; 116 | } 117 | } else { 118 | // No parenthesis found, can't determine where the conditional part of the ternary starts. 119 | return; 120 | } 121 | 122 | $startPos = $opener; 123 | 124 | do { 125 | $hasAssignment = $this->phpcsFile->findNext( $this->assignment_tokens, ( $startPos + 1 ), $closer ); 126 | if ( false === $hasAssignment ) { 127 | return; 128 | } 129 | 130 | // Examine whether the left side is a variable. 131 | $hasVariable = false; 132 | $conditionStart = $startPos; 133 | $altConditionStart = $this->phpcsFile->findPrevious( 134 | $this->condition_start_tokens, 135 | ( $hasAssignment - 1 ), 136 | $startPos 137 | ); 138 | if ( false !== $altConditionStart ) { 139 | $conditionStart = $altConditionStart; 140 | } 141 | 142 | for ( $i = $hasAssignment; $i > $conditionStart; $i-- ) { 143 | if ( isset( Tokens::$emptyTokens[ $this->tokens[ $i ]['code'] ] ) ) { 144 | continue; 145 | } 146 | 147 | // If this is a variable or array, we've seen all we need to see. 148 | if ( \T_VARIABLE === $this->tokens[ $i ]['code'] 149 | || \T_CLOSE_SQUARE_BRACKET === $this->tokens[ $i ]['code'] 150 | ) { 151 | $hasVariable = true; 152 | break; 153 | } 154 | 155 | // If this is a function call or something, we are OK. 156 | if ( \T_CLOSE_PARENTHESIS === $this->tokens[ $i ]['code'] ) { 157 | break; 158 | } 159 | } 160 | 161 | if ( true === $hasVariable ) { 162 | $this->phpcsFile->addWarning( 163 | 'Variable assignment found within a condition. Did you mean to do a comparison?', 164 | $hasAssignment, 165 | 'FoundInTernaryCondition' 166 | ); 167 | } 168 | 169 | $startPos = $hasAssignment; 170 | 171 | } while ( $startPos < $closer ); 172 | } 173 | } 174 | -------------------------------------------------------------------------------- /WordPress/Sniffs/CodeAnalysis/EscapedNotTranslatedSniff.php: -------------------------------------------------------------------------------- 1 | Key is the name of the function being matched, value the alternative to use. 45 | */ 46 | protected $target_functions = array( 47 | 'esc_html' => 'esc_html__', 48 | 'esc_attr' => 'esc_attr__', 49 | ); 50 | 51 | /** 52 | * Process the parameters of a matched function. 53 | * 54 | * @since 2.2.0 55 | * 56 | * @param int $stackPtr The position of the current token in the stack. 57 | * @param string $group_name The name of the group which was matched. 58 | * @param string $matched_content The token content (function name) which was matched 59 | * in lowercase. 60 | * @param array $parameters Array with information about the parameters. 61 | * 62 | * @return void 63 | */ 64 | public function process_parameters( $stackPtr, $group_name, $matched_content, $parameters ) { 65 | if ( \count( $parameters ) === 1 ) { 66 | return; 67 | } 68 | 69 | /* 70 | * We already know that there will be a valid open+close parenthesis, otherwise the sniff 71 | * would have bowed out long before. 72 | */ 73 | $opener = $this->phpcsFile->findNext( Tokens::$emptyTokens, ( $stackPtr + 1 ), null, true ); 74 | $closer = $this->tokens[ $opener ]['parenthesis_closer']; 75 | 76 | $data = array( 77 | $matched_content, 78 | $this->target_functions[ $matched_content ], 79 | GetTokensAsString::compact( $this->phpcsFile, $stackPtr, $closer, true ), 80 | ); 81 | 82 | $this->phpcsFile->addWarning( 83 | '%s() expects only a $text parameter. Did you mean to use %s() ? Found: %s', 84 | $stackPtr, 85 | 'Found', 86 | $data 87 | ); 88 | } 89 | } 90 | -------------------------------------------------------------------------------- /WordPress/Sniffs/DB/RestrictedClassesSniff.php: -------------------------------------------------------------------------------- 1 | array( 33 | * 'lambda' => array( 34 | * 'type' => 'error' | 'warning', 35 | * 'message' => 'Avoid direct calls to the database.', 36 | * 'classes' => array( 'PDO', '\Namespace\Classname' ), 37 | * ) 38 | * ) 39 | * 40 | * @return array 41 | */ 42 | public function getGroups() { 43 | return array( 44 | 45 | 'mysql' => array( 46 | 'type' => 'error', 47 | 'message' => 'Accessing the database directly should be avoided. Please use the $wpdb object and associated functions instead. Found: %s.', 48 | 'classes' => array( 49 | 'mysqli', 50 | 'PDO', 51 | 'PDOStatement', 52 | ), 53 | ), 54 | 55 | ); 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /WordPress/Sniffs/DB/RestrictedFunctionsSniff.php: -------------------------------------------------------------------------------- 1 | array( 33 | * 'lambda' => array( 34 | * 'type' => 'error' | 'warning', 35 | * 'message' => 'Use anonymous functions instead please!', 36 | * 'functions' => array( 'file_get_contents', 'create_function' ), 37 | * ) 38 | * ) 39 | * 40 | * @return array 41 | */ 42 | public function getGroups() { 43 | return array( 44 | 45 | 'mysql' => array( 46 | 'type' => 'error', 47 | 'message' => 'Accessing the database directly should be avoided. Please use the $wpdb object and associated functions instead. Found: %s.', 48 | 'functions' => array( 49 | 'mysql_*', 50 | 'mysqli_*', 51 | 'mysqlnd_ms_*', 52 | 'mysqlnd_qc_*', 53 | 'mysqlnd_uh_*', 54 | 'mysqlnd_memcache_*', 55 | 'maxdb_*', 56 | ), 57 | 'allow' => array( 58 | 'mysql_to_rfc3339' => true, 59 | ), 60 | ), 61 | ); 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /WordPress/Sniffs/DB/SlowDBQuerySniff.php: -------------------------------------------------------------------------------- 1 | array( 33 | 'type' => 'warning', 34 | 'message' => 'Detected usage of %s, possible slow query.', 35 | 'keys' => array( 36 | 'tax_query', 37 | 'meta_query', 38 | 'meta_key', 39 | 'meta_value', 40 | ), 41 | ), 42 | ); 43 | } 44 | 45 | /** 46 | * Callback to process each confirmed key, to check value. 47 | * 48 | * @param string $key Array index / key. 49 | * @param mixed $val Assigned value. 50 | * @param int $line Token line. 51 | * @param array $group Group definition. 52 | * 53 | * @return bool Always returns TRUE as the value is irrelevant. 54 | */ 55 | public function callback( $key, $val, $line, $group ) { 56 | return true; 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /WordPress/Sniffs/DateTime/CurrentTimeTimestampSniff.php: -------------------------------------------------------------------------------- 1 | Key is function name, value irrelevant. 48 | */ 49 | protected $target_functions = array( 50 | 'current_time' => true, 51 | ); 52 | 53 | /** 54 | * Process the parameters of a matched function. 55 | * 56 | * @since 2.2.0 57 | * 58 | * @param int $stackPtr The position of the current token in the stack. 59 | * @param string $group_name The name of the group which was matched. 60 | * @param string $matched_content The token content (function name) which was matched 61 | * in lowercase. 62 | * @param array $parameters Array with information about the parameters. 63 | * 64 | * @return void 65 | */ 66 | public function process_parameters( $stackPtr, $group_name, $matched_content, $parameters ) { 67 | /* 68 | * We already know there will be valid open & close parentheses as otherwise the parameter 69 | * retrieval function call would have returned an empty array, so no additional checks needed. 70 | */ 71 | $open_parens = $this->phpcsFile->findNext( \T_OPEN_PARENTHESIS, $stackPtr ); 72 | $close_parens = $this->tokens[ $open_parens ]['parenthesis_closer']; 73 | 74 | /* 75 | * Check whether the first parameter is a timestamp format. 76 | */ 77 | $type_param = PassedParameters::getParameterFromStack( $parameters, 1, 'type' ); 78 | if ( false === $type_param ) { 79 | // Type parameter not found. Bow out. 80 | return; 81 | } 82 | 83 | $content_type = ''; 84 | for ( $i = $type_param['start']; $i <= $type_param['end']; $i++ ) { 85 | if ( isset( Tokens::$emptyTokens[ $this->tokens[ $i ]['code'] ] ) ) { 86 | continue; 87 | } 88 | 89 | if ( isset( Tokens::$textStringTokens[ $this->tokens[ $i ]['code'] ] ) ) { 90 | $content_type = trim( TextStrings::stripQuotes( $this->tokens[ $i ]['content'] ) ); 91 | if ( 'U' !== $content_type && 'timestamp' !== $content_type ) { 92 | // Most likely valid use of current_time(). 93 | return; 94 | } 95 | 96 | continue; 97 | } 98 | 99 | if ( isset( Tokens::$heredocTokens[ $this->tokens[ $i ]['code'] ] ) ) { 100 | continue; 101 | } 102 | 103 | /* 104 | * If we're still here, we've encountered an unexpected token, like a variable or 105 | * function call. Bow out as we can't determine the runtime value. 106 | */ 107 | return; 108 | } 109 | 110 | $gmt_true = false; 111 | 112 | /* 113 | * Check whether the second parameter, $gmt, is a set to `true` or `1`. 114 | */ 115 | $gmt_param = PassedParameters::getParameterFromStack( $parameters, 2, 'gmt' ); 116 | if ( is_array( $gmt_param ) ) { 117 | $content_gmt = ''; 118 | if ( 'true' === $gmt_param['clean'] || '1' === $gmt_param['clean'] ) { 119 | $content_gmt = $gmt_param['clean']; 120 | $gmt_true = true; 121 | } 122 | } 123 | 124 | /* 125 | * Non-UTC timestamp requested. 126 | */ 127 | if ( false === $gmt_true ) { 128 | $this->phpcsFile->addWarning( 129 | 'Calling current_time() with a $type of "timestamp" or "U" is strongly discouraged as it will not return a Unix (UTC) timestamp. Please consider using a non-timestamp format or otherwise refactoring this code.', 130 | $stackPtr, 131 | 'Requested' 132 | ); 133 | 134 | return; 135 | } 136 | 137 | /* 138 | * UTC timestamp requested. Should use time() instead. 139 | */ 140 | $has_comment = $this->phpcsFile->findNext( Tokens::$commentTokens, ( $stackPtr + 1 ), ( $close_parens + 1 ) ); 141 | $error = 'Don\'t use current_time() for retrieving a Unix (UTC) timestamp. Use time() instead. Found: %s'; 142 | $error_code = 'RequestedUTC'; 143 | 144 | $code_snippet = "current_time( '" . $content_type . "'"; 145 | if ( isset( $content_gmt ) ) { 146 | $code_snippet .= ', ' . $content_gmt; 147 | } 148 | $code_snippet .= ' )'; 149 | 150 | if ( false !== $has_comment ) { 151 | // If there are comments, we don't auto-fix as it would remove those comments. 152 | $this->phpcsFile->addError( $error, $stackPtr, $error_code, array( $code_snippet ) ); 153 | return; 154 | } 155 | 156 | $fix = $this->phpcsFile->addFixableError( $error, $stackPtr, $error_code, array( $code_snippet ) ); 157 | if ( true === $fix ) { 158 | $this->phpcsFile->fixer->beginChangeset(); 159 | 160 | for ( $i = ( $stackPtr + 1 ); $i < $close_parens; $i++ ) { 161 | $this->phpcsFile->fixer->replaceToken( $i, '' ); 162 | } 163 | 164 | $this->phpcsFile->fixer->replaceToken( $stackPtr, 'time(' ); 165 | $this->phpcsFile->fixer->endChangeset(); 166 | } 167 | } 168 | } 169 | -------------------------------------------------------------------------------- /WordPress/Sniffs/DateTime/RestrictedFunctionsSniff.php: -------------------------------------------------------------------------------- 1 | array( 35 | 'type' => 'error', 36 | 'message' => 'Using %s() and similar isn\'t allowed, instead use WP internal timezone support.', 37 | 'functions' => array( 38 | 'date_default_timezone_set', 39 | ), 40 | ), 41 | 42 | /* 43 | * Use gmdate(), not date(). 44 | * Don't rely on the current PHP time zone as it might have been changed by third party code. 45 | * 46 | * @link https://make.wordpress.org/core/2019/09/23/date-time-improvements-wp-5-3/ 47 | * @link https://core.trac.wordpress.org/ticket/46438 48 | * @link https://github.com/WordPress/WordPress-Coding-Standards/issues/1713 49 | */ 50 | 'date' => array( 51 | 'type' => 'error', 52 | 'message' => '%s() is affected by runtime timezone changes which can cause date/time to be incorrectly displayed. Use gmdate() instead.', 53 | 'functions' => array( 54 | 'date', 55 | ), 56 | ), 57 | ); 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /WordPress/Sniffs/PHP/DevelopmentFunctionsSniff.php: -------------------------------------------------------------------------------- 1 | array( 26 | * 'lambda' => array( 27 | * 'type' => 'error' | 'warning', 28 | * 'message' => 'Use anonymous functions instead please!', 29 | * 'functions' => array( 'file_get_contents', 'create_function' ), 30 | * ) 31 | * ) 32 | * 33 | * @return array 34 | */ 35 | public function getGroups() { 36 | return array( 37 | 'error_log' => array( 38 | 'type' => 'warning', 39 | 'message' => '%s() found. Debug code should not normally be used in production.', 40 | 'functions' => array( 41 | 'error_log', 42 | 'var_dump', 43 | 'var_export', 44 | 'print_r', 45 | 'trigger_error', 46 | 'set_error_handler', 47 | 'debug_backtrace', 48 | 'debug_print_backtrace', 49 | 'wp_debug_backtrace_summary', 50 | ), 51 | ), 52 | 53 | 'prevent_path_disclosure' => array( 54 | 'type' => 'warning', 55 | 'message' => '%s() can lead to full path disclosure.', 56 | 'functions' => array( 57 | 'error_reporting', 58 | 'phpinfo', 59 | ), 60 | ), 61 | ); 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /WordPress/Sniffs/PHP/DiscouragedPHPFunctionsSniff.php: -------------------------------------------------------------------------------- 1 | array( 27 | * 'lambda' => array( 28 | * 'type' => 'error' | 'warning', 29 | * 'message' => 'Use anonymous functions instead please!', 30 | * 'functions' => array( 'file_get_contents', 'create_function' ), 31 | * ) 32 | * ) 33 | * 34 | * @return array 35 | */ 36 | public function getGroups() { 37 | return array( 38 | 'serialize' => array( 39 | 'type' => 'warning', 40 | 'message' => '%s() found. Serialized data has known vulnerability problems with Object Injection. JSON is generally a better approach for serializing data. See https://www.owasp.org/index.php/PHP_Object_Injection', 41 | 'functions' => array( 42 | 'serialize', 43 | 'unserialize', 44 | ), 45 | ), 46 | 47 | 'urlencode' => array( 48 | 'type' => 'warning', 49 | 'message' => '%s() should only be used when dealing with legacy applications rawurlencode() should now be used instead. See https://www.php.net/function.rawurlencode and http://www.faqs.org/rfcs/rfc3986.html', 50 | 'functions' => array( 51 | 'urlencode', 52 | ), 53 | ), 54 | 55 | 'runtime_configuration' => array( 56 | 'type' => 'warning', 57 | 'message' => '%s() found. Changing configuration values at runtime is strongly discouraged.', 58 | 'functions' => array( 59 | 'error_reporting', 60 | 'ini_restore', 61 | 'apache_setenv', 62 | 'putenv', 63 | 'set_include_path', 64 | 'restore_include_path', 65 | // This alias was DEPRECATED in PHP 5.3.0, and REMOVED as of PHP 7.0.0. 66 | 'magic_quotes_runtime', 67 | // Warning This function was DEPRECATED in PHP 5.3.0, and REMOVED as of PHP 7.0.0. 68 | 'set_magic_quotes_runtime', 69 | // Warning This function was removed from most SAPIs in PHP 5.3.0, and was removed from PHP-FPM in PHP 7.0.0. 70 | 'dl', 71 | ), 72 | ), 73 | 74 | 'system_calls' => array( 75 | 'type' => 'warning', 76 | 'message' => '%s() found. PHP system calls are often disabled by server admins.', 77 | 'functions' => array( 78 | 'exec', 79 | 'passthru', 80 | 'proc_open', 81 | 'shell_exec', 82 | 'system', 83 | 'popen', 84 | ), 85 | ), 86 | 87 | 'obfuscation' => array( 88 | 'type' => 'warning', 89 | 'message' => '%s() can be used to obfuscate code which is strongly discouraged. Please verify that the function is used for benign reasons.', 90 | 'functions' => array( 91 | 'base64_decode', 92 | 'base64_encode', 93 | 'convert_uudecode', 94 | 'convert_uuencode', 95 | 'str_rot13', 96 | ), 97 | ), 98 | ); 99 | } 100 | } 101 | -------------------------------------------------------------------------------- /WordPress/Sniffs/PHP/DontExtractSniff.php: -------------------------------------------------------------------------------- 1 | array( 30 | * 'lambda' => array( 31 | * 'type' => 'error' | 'warning', 32 | * 'message' => 'Use anonymous functions instead please!', 33 | * 'functions' => array( 'file_get_contents', 'create_function' ), 34 | * ) 35 | * ) 36 | * 37 | * @return array 38 | */ 39 | public function getGroups() { 40 | return array( 41 | 42 | 'extract' => array( 43 | 'type' => 'error', 44 | 'message' => '%s() usage is highly discouraged, due to the complexity and unintended issues it might cause.', 45 | 'functions' => array( 46 | 'extract', 47 | ), 48 | ), 49 | 50 | ); 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /WordPress/Sniffs/PHP/POSIXFunctionsSniff.php: -------------------------------------------------------------------------------- 1 | array( 32 | * 'lambda' => array( 33 | * 'type' => 'error' | 'warning', 34 | * 'message' => 'Use anonymous functions instead please!', 35 | * 'functions' => array( 'file_get_contents', 'create_function' ), 36 | * ) 37 | * ) 38 | * 39 | * @return array 40 | */ 41 | public function getGroups() { 42 | return array( 43 | 'ereg' => array( 44 | 'type' => 'error', 45 | 'message' => '%s() has been deprecated since PHP 5.3 and removed in PHP 7.0, please use preg_match() instead.', 46 | 'functions' => array( 47 | 'ereg', 48 | 'eregi', 49 | 'sql_regcase', 50 | ), 51 | ), 52 | 53 | 'ereg_replace' => array( 54 | 'type' => 'error', 55 | 'message' => '%s() has been deprecated since PHP 5.3 and removed in PHP 7.0, please use preg_replace() instead.', 56 | 'functions' => array( 57 | 'ereg_replace', 58 | 'eregi_replace', 59 | ), 60 | ), 61 | 62 | 'split' => array( 63 | 'type' => 'error', 64 | 'message' => '%s() has been deprecated since PHP 5.3 and removed in PHP 7.0, please use explode(), str_split() or preg_split() instead.', 65 | 'functions' => array( 66 | 'split', 67 | 'spliti', 68 | ), 69 | ), 70 | 71 | ); 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /WordPress/Sniffs/PHP/PregQuoteDelimiterSniff.php: -------------------------------------------------------------------------------- 1 | Key is function name, value irrelevant. 39 | */ 40 | protected $target_functions = array( 41 | 'preg_quote' => true, 42 | ); 43 | 44 | /** 45 | * Process the parameters of a matched function. 46 | * 47 | * @since 1.0.0 48 | * 49 | * @param int $stackPtr The position of the current token in the stack. 50 | * @param string $group_name The name of the group which was matched. 51 | * @param string $matched_content The token content (function name) which was matched 52 | * in lowercase. 53 | * @param array $parameters Array with information about the parameters. 54 | * 55 | * @return void 56 | */ 57 | public function process_parameters( $stackPtr, $group_name, $matched_content, $parameters ) { 58 | 59 | $delimiter = PassedParameters::getParameterFromStack( $parameters, 2, 'delimiter' ); 60 | if ( false !== $delimiter ) { 61 | return; 62 | } 63 | 64 | $this->phpcsFile->addWarning( 65 | 'Passing the $delimiter parameter to preg_quote() is strongly recommended.', 66 | $stackPtr, 67 | 'Missing' 68 | ); 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /WordPress/Sniffs/PHP/RestrictedPHPFunctionsSniff.php: -------------------------------------------------------------------------------- 1 | array( 25 | * 'lambda' => array( 26 | * 'type' => 'error' | 'warning', 27 | * 'message' => 'Use anonymous functions instead please!', 28 | * 'functions' => array( 'file_get_contents', 'create_function' ), 29 | * ) 30 | * ) 31 | * 32 | * @return array 33 | */ 34 | public function getGroups() { 35 | return array( 36 | 'create_function' => array( 37 | 'type' => 'error', 38 | 'message' => '%s() is deprecated as of PHP 7.2 and removed in PHP 8.0. Please use declared named or anonymous functions instead.', 39 | 'functions' => array( 40 | 'create_function', 41 | ), 42 | ), 43 | ); 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /WordPress/Sniffs/PHP/StrictInArraySniff.php: -------------------------------------------------------------------------------- 1 | Key is the function name. 52 | */ 53 | protected $target_functions = array( 54 | 'in_array' => array( 55 | 'param_position' => 3, 56 | 'param_name' => 'strict', 57 | 'always_needed' => true, 58 | ), 59 | 'array_search' => array( 60 | 'param_position' => 3, 61 | 'param_name' => 'strict', 62 | 'always_needed' => true, 63 | ), 64 | 'array_keys' => array( 65 | 'param_position' => 3, 66 | 'param_name' => 'strict', 67 | 'always_needed' => false, 68 | ), 69 | ); 70 | 71 | /** 72 | * Process the parameters of a matched function. 73 | * 74 | * @since 0.11.0 75 | * 76 | * @param int $stackPtr The position of the current token in the stack. 77 | * @param string $group_name The name of the group which was matched. 78 | * @param string $matched_content The token content (function name) which was matched 79 | * in lowercase. 80 | * @param array $parameters Array with information about the parameters. 81 | * 82 | * @return void 83 | */ 84 | public function process_parameters( $stackPtr, $group_name, $matched_content, $parameters ) { 85 | $param_info = $this->target_functions[ $matched_content ]; 86 | 87 | /* 88 | * Check if the strict check is actually needed. 89 | * 90 | * Important! This check only applies to array_keys() in the current form of the sniff 91 | * and has been written to be specific to that function. 92 | * If more functions would be added with 'always_needed' set to `false`, 93 | * this code will need to be adjusted to handle those. 94 | */ 95 | if ( false === $param_info['always_needed'] ) { 96 | $has_filter_value = PassedParameters::getParameterFromStack( $parameters, 2, 'filter_value' ); 97 | if ( false === $has_filter_value ) { 98 | return; 99 | } 100 | } 101 | 102 | $found_parameter = PassedParameters::getParameterFromStack( $parameters, $param_info['param_position'], $param_info['param_name'] ); 103 | if ( false === $found_parameter || 'true' !== strtolower( $found_parameter['clean'] ) ) { 104 | $errorcode = 'MissingTrueStrict'; 105 | 106 | /* 107 | * Use a different error code when `false` is found to allow for excluding 108 | * the warning as this will be a conscious choice made by the dev. 109 | */ 110 | if ( is_array( $found_parameter ) && 'false' === strtolower( $found_parameter['clean'] ) ) { 111 | $errorcode = 'FoundNonStrictFalse'; 112 | } 113 | 114 | $this->phpcsFile->addWarning( 115 | 'Not using strict comparison for %s; supply true for $%s argument.', 116 | ( isset( $found_parameter['start'] ) ? $found_parameter['start'] : $stackPtr ), 117 | $errorcode, 118 | array( $matched_content, $param_info['param_name'] ) 119 | ); 120 | } 121 | } 122 | } 123 | -------------------------------------------------------------------------------- /WordPress/Sniffs/PHP/TypeCastsSniff.php: -------------------------------------------------------------------------------- 1 | tokens[ $stackPtr ]['code']; 53 | $typecast = str_replace( ' ', '', $this->tokens[ $stackPtr ]['content'] ); 54 | $typecast_lc = strtolower( $typecast ); 55 | 56 | switch ( $token_code ) { 57 | case \T_DOUBLE_CAST: 58 | if ( '(float)' !== $typecast_lc ) { 59 | $fix = $this->phpcsFile->addFixableError( 60 | 'Normalized type keywords must be used; expected "(float)" but found "%s"', 61 | $stackPtr, 62 | 'DoubleRealFound', 63 | array( $typecast ) 64 | ); 65 | 66 | if ( true === $fix ) { 67 | $this->phpcsFile->fixer->replaceToken( $stackPtr, '(float)' ); 68 | } 69 | } 70 | break; 71 | 72 | case \T_UNSET_CAST: 73 | $this->phpcsFile->addError( 74 | 'Using the "(unset)" cast is forbidden as the type cast is removed in PHP 8.0. Use the "unset()" language construct instead.', 75 | $stackPtr, 76 | 'UnsetFound' 77 | ); 78 | break; 79 | 80 | case \T_BINARY_CAST: 81 | $this->phpcsFile->addWarning( 82 | 'Using binary casting is strongly discouraged. Found: "%s"', 83 | $stackPtr, 84 | 'BinaryFound', 85 | array( $typecast ) 86 | ); 87 | break; 88 | } 89 | } 90 | } 91 | -------------------------------------------------------------------------------- /WordPress/Sniffs/PHP/YodaConditionsSniff.php: -------------------------------------------------------------------------------- 1 | condition_start_tokens = $starters; 54 | 55 | return array( 56 | \T_IS_EQUAL, 57 | \T_IS_NOT_EQUAL, 58 | \T_IS_IDENTICAL, 59 | \T_IS_NOT_IDENTICAL, 60 | ); 61 | } 62 | 63 | /** 64 | * Processes this test, when one of its tokens is encountered. 65 | * 66 | * @param int $stackPtr The position of the current token in the stack. 67 | * 68 | * @return void 69 | */ 70 | public function process_token( $stackPtr ) { 71 | 72 | $start = $this->phpcsFile->findPrevious( $this->condition_start_tokens, $stackPtr, null, false, null, true ); 73 | 74 | $needs_yoda = false; 75 | 76 | // Note: going backwards! 77 | for ( $i = $stackPtr; $i > $start; $i-- ) { 78 | 79 | // Ignore whitespace. 80 | if ( isset( Tokens::$emptyTokens[ $this->tokens[ $i ]['code'] ] ) ) { 81 | continue; 82 | } 83 | 84 | // If this is a variable or array assignment, we've seen all we need to see. 85 | if ( \T_VARIABLE === $this->tokens[ $i ]['code'] 86 | || \T_CLOSE_SQUARE_BRACKET === $this->tokens[ $i ]['code'] 87 | ) { 88 | $needs_yoda = true; 89 | break; 90 | } 91 | 92 | // If this is a function call or something, we are OK. 93 | if ( \T_CLOSE_PARENTHESIS === $this->tokens[ $i ]['code'] ) { 94 | return; 95 | } 96 | } 97 | 98 | if ( ! $needs_yoda ) { 99 | return; 100 | } 101 | 102 | // Check if this is a var to var comparison, e.g.: if ( $var1 == $var2 ). 103 | $next_non_empty = $this->phpcsFile->findNext( Tokens::$emptyTokens, ( $stackPtr + 1 ), null, true ); 104 | 105 | if ( isset( Tokens::$castTokens[ $this->tokens[ $next_non_empty ]['code'] ] ) ) { 106 | $next_non_empty = $this->phpcsFile->findNext( Tokens::$emptyTokens, ( $next_non_empty + 1 ), null, true ); 107 | } 108 | 109 | if ( isset( Collections::ooHierarchyKeywords()[ $this->tokens[ $next_non_empty ]['code'] ] ) === true ) { 110 | $next_non_empty = $this->phpcsFile->findNext( 111 | ( Tokens::$emptyTokens + array( \T_DOUBLE_COLON => \T_DOUBLE_COLON ) ), 112 | ( $next_non_empty + 1 ), 113 | null, 114 | true 115 | ); 116 | } 117 | 118 | if ( \T_VARIABLE === $this->tokens[ $next_non_empty ]['code'] ) { 119 | return; 120 | } 121 | 122 | $this->phpcsFile->addError( 'Use Yoda Condition checks, you must.', $stackPtr, 'NotYoda' ); 123 | } 124 | } 125 | -------------------------------------------------------------------------------- /WordPress/Sniffs/Security/PluginMenuSlugSniff.php: -------------------------------------------------------------------------------- 1 | > Key is the name of the functions being targeted. 48 | * Value is an array with parameter positions as the 49 | * keys and parameter names as the values 50 | */ 51 | protected $target_functions = array( 52 | 'add_comments_page' => array( 53 | 4 => 'menu_slug', 54 | ), 55 | 'add_dashboard_page' => array( 56 | 4 => 'menu_slug', 57 | ), 58 | 'add_links_page' => array( 59 | 4 => 'menu_slug', 60 | ), 61 | 'add_management_page' => array( 62 | 4 => 'menu_slug', 63 | ), 64 | 'add_media_page' => array( 65 | 4 => 'menu_slug', 66 | ), 67 | 'add_menu_page' => array( 68 | 4 => 'menu_slug', 69 | ), 70 | 'add_object_page' => array( 71 | 4 => 'menu_slug', 72 | ), 73 | 'add_options_page' => array( 74 | 4 => 'menu_slug', 75 | ), 76 | 'add_pages_page' => array( 77 | 4 => 'menu_slug', 78 | ), 79 | 'add_plugins_page' => array( 80 | 4 => 'menu_slug', 81 | ), 82 | 'add_posts_page' => array( 83 | 4 => 'menu_slug', 84 | ), 85 | 'add_submenu_page' => array( 86 | 1 => 'parent_slug', 87 | 5 => 'menu_slug', 88 | ), 89 | 'add_theme_page' => array( 90 | 4 => 'menu_slug', 91 | ), 92 | 'add_users_page' => array( 93 | 4 => 'menu_slug', 94 | ), 95 | 'add_utility_page' => array( 96 | 4 => 'menu_slug', 97 | ), 98 | ); 99 | 100 | /** 101 | * Process the parameters of a matched function. 102 | * 103 | * @since 0.11.0 104 | * 105 | * @param int $stackPtr The position of the current token in the stack. 106 | * @param string $group_name The name of the group which was matched. 107 | * @param string $matched_content The token content (function name) which was matched 108 | * in lowercase. 109 | * @param array $parameters Array with information about the parameters. 110 | * 111 | * @return void 112 | */ 113 | public function process_parameters( $stackPtr, $group_name, $matched_content, $parameters ) { 114 | foreach ( $this->target_functions[ $matched_content ] as $position => $param_name ) { 115 | $found_param = PassedParameters::getParameterFromStack( $parameters, $position, $param_name ); 116 | if ( false === $found_param ) { 117 | continue; 118 | } 119 | 120 | $file_constant = $this->phpcsFile->findNext( \T_FILE, $found_param['start'], ( $found_param['end'] + 1 ) ); 121 | if ( false !== $file_constant ) { 122 | $this->phpcsFile->addWarning( 'Using __FILE__ for menu slugs risks exposing filesystem structure.', $file_constant, 'Using__FILE__' ); 123 | } 124 | } 125 | } 126 | } 127 | -------------------------------------------------------------------------------- /WordPress/Sniffs/Security/SafeRedirectSniff.php: -------------------------------------------------------------------------------- 1 | array( 25 | * 'lambda' => array( 26 | * 'type' => 'error' | 'warning', 27 | * 'message' => 'Use anonymous functions instead please!', 28 | * 'functions' => array( 'file_get_contents', 'create_function' ), 29 | * ) 30 | * ) 31 | * 32 | * @return array 33 | */ 34 | public function getGroups() { 35 | return array( 36 | 'wp_redirect' => array( 37 | 'type' => 'warning', 38 | 'message' => '%s() found. Using wp_safe_redirect(), along with the "allowed_redirect_hosts" filter if needed, can help avoid any chances of malicious redirects within code. It is also important to remember to call exit() after a redirect so that no other unwanted code is executed.', 39 | 'functions' => array( 40 | 'wp_redirect', 41 | ), 42 | ), 43 | ); 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /WordPress/Sniffs/WP/DeprecatedClassesSniff.php: -------------------------------------------------------------------------------- 1 | value 29 | * in a custom ruleset. 30 | * 31 | * @uses \WordPressCS\WordPress\Helpers\MinimumWPVersionTrait::$minimum_wp_version 32 | */ 33 | final class DeprecatedClassesSniff extends AbstractClassRestrictionsSniff { 34 | 35 | use MinimumWPVersionTrait; 36 | 37 | /** 38 | * List of deprecated classes with alternative when available. 39 | * 40 | * To be updated after every major release. 41 | * 42 | * Version numbers should be fully qualified. 43 | * 44 | * {@internal To be updated after every major release. Last updated for WordPress 6.5-RC3.} 45 | * 46 | * @var array 47 | */ 48 | private $deprecated_classes = array( 49 | 50 | // WP 3.1.0. 51 | 'WP_User_Search' => array( 52 | 'alt' => 'WP_User_Query', 53 | 'version' => '3.1.0', 54 | ), 55 | 56 | // WP 3.7.0. 57 | 'WP_HTTP_Fsockopen' => array( 58 | 'alt' => 'WP_HTTP::request()', 59 | 'version' => '3.7.0', 60 | ), 61 | 62 | // WP 4.9.0. 63 | 'WP_Customize_New_Menu_Section' => array( 64 | 'version' => '4.9.0', 65 | ), 66 | 'WP_Customize_New_Menu_Control' => array( 67 | 'version' => '4.9.0', 68 | ), 69 | 70 | // WP 5.3.0. 71 | 'WP_Privacy_Data_Export_Requests_Table' => array( 72 | 'alt' => 'WP_Privacy_Data_Export_Requests_List_Table', 73 | 'version' => '5.3.0', 74 | ), 75 | 'WP_Privacy_Data_Removal_Requests_Table' => array( 76 | 'alt' => 'WP_Privacy_Data_Removal_Requests_List_Table', 77 | 'version' => '5.3.0', 78 | ), 79 | 'Services_JSON' => array( 80 | 'alt' => 'The PHP native JSON extension', 81 | 'version' => '5.3.0', 82 | ), 83 | 'Services_JSON_Error' => array( 84 | 'alt' => 'The PHP native JSON extension', 85 | 'version' => '5.3.0', 86 | ), 87 | 88 | // WP 6.4.0. 89 | 'WP_Http_Curl' => array( 90 | 'alt' => 'WP_Http', 91 | 'version' => '6.4.0', 92 | ), 93 | 'WP_Http_Streams' => array( 94 | 'alt' => 'WP_Http', 95 | 'version' => '6.4.0', 96 | ), 97 | ); 98 | 99 | /** 100 | * Groups of classes to restrict. 101 | * 102 | * @return array 103 | */ 104 | public function getGroups() { 105 | // Make sure all array keys are lowercase. 106 | $this->deprecated_classes = array_change_key_case( $this->deprecated_classes, \CASE_LOWER ); 107 | 108 | return array( 109 | 'deprecated_classes' => array( 110 | 'classes' => array_keys( $this->deprecated_classes ), 111 | ), 112 | ); 113 | } 114 | 115 | /** 116 | * Process a matched token. 117 | * 118 | * @param int $stackPtr The position of the current token in the stack. 119 | * @param string $group_name The name of the group which was matched. Will 120 | * always be 'deprecated_classes'. 121 | * @param string $matched_content The token content (class name) which was matched 122 | * in its original case. 123 | * 124 | * @return void 125 | */ 126 | public function process_matched_token( $stackPtr, $group_name, $matched_content ) { 127 | 128 | $this->set_minimum_wp_version(); 129 | 130 | $class_name = ltrim( strtolower( $matched_content ), '\\' ); 131 | 132 | $message = 'The %s class has been deprecated since WordPress version %s.'; 133 | $data = array( 134 | ltrim( $matched_content, '\\' ), 135 | $this->deprecated_classes[ $class_name ]['version'], 136 | ); 137 | 138 | if ( ! empty( $this->deprecated_classes[ $class_name ]['alt'] ) ) { 139 | $message .= ' Use %s instead.'; 140 | $data[] = $this->deprecated_classes[ $class_name ]['alt']; 141 | } 142 | 143 | MessageHelper::addMessage( 144 | $this->phpcsFile, 145 | $message, 146 | $stackPtr, 147 | ( $this->wp_version_compare( $this->deprecated_classes[ $class_name ]['version'], $this->minimum_wp_version, '<' ) ), 148 | MessageHelper::stringToErrorcode( $class_name . 'Found' ), 149 | $data 150 | ); 151 | } 152 | } 153 | -------------------------------------------------------------------------------- /WordPress/Sniffs/WP/DiscouragedConstantsSniff.php: -------------------------------------------------------------------------------- 1 | 'get_stylesheet_directory()', 35 | 'TEMPLATEPATH' => 'get_template_directory()', 36 | 'PLUGINDIR' => 'WP_PLUGIN_DIR', 37 | 'MUPLUGINDIR' => 'WPMU_PLUGIN_DIR', 38 | 'HEADER_IMAGE' => 'add_theme_support( \'custom-header\' )', 39 | 'NO_HEADER_TEXT' => 'add_theme_support( \'custom-header\' )', 40 | 'HEADER_TEXTCOLOR' => 'add_theme_support( \'custom-header\' )', 41 | 'HEADER_IMAGE_WIDTH' => 'add_theme_support( \'custom-header\' )', 42 | 'HEADER_IMAGE_HEIGHT' => 'add_theme_support( \'custom-header\' )', 43 | 'BACKGROUND_COLOR' => 'add_theme_support( \'custom-background\' )', 44 | 'BACKGROUND_IMAGE' => 'add_theme_support( \'custom-background\' )', 45 | ); 46 | 47 | /** 48 | * Array of functions to check. 49 | * 50 | * @since 0.14.0 51 | * @since 3.0.0 The format of the value has changed from an integer parameter 52 | * position to an array with the parameter position and name. 53 | * 54 | * @var array> Function name as key, array with target 55 | * parameter and name as value. 56 | */ 57 | protected $target_functions = array( 58 | 'define' => array( 59 | 'position' => 1, 60 | 'name' => 'constant_name', 61 | ), 62 | ); 63 | 64 | /** 65 | * Processes this test, when one of its tokens is encountered. 66 | * 67 | * @since 0.14.0 68 | * 69 | * @param int $stackPtr The position of the current token in the stack. 70 | * 71 | * @return int|void Integer stack pointer to skip forward or void to continue 72 | * normal file processing. 73 | */ 74 | public function process_token( $stackPtr ) { 75 | if ( isset( $this->target_functions[ strtolower( $this->tokens[ $stackPtr ]['content'] ) ] ) ) { 76 | // Disallow excluding function groups for this sniff. 77 | $this->exclude = array(); 78 | 79 | return parent::process_token( $stackPtr ); 80 | 81 | } else { 82 | return $this->process_arbitrary_tstring( $stackPtr ); 83 | } 84 | } 85 | 86 | /** 87 | * Process an arbitrary T_STRING token to determine whether it is one of the target constants. 88 | * 89 | * @since 0.14.0 90 | * 91 | * @param int $stackPtr The position of the current token in the stack. 92 | * 93 | * @return void 94 | */ 95 | public function process_arbitrary_tstring( $stackPtr ) { 96 | $content = $this->tokens[ $stackPtr ]['content']; 97 | 98 | if ( ! isset( $this->discouraged_constants[ $content ] ) ) { 99 | return; 100 | } 101 | 102 | if ( ConstantsHelper::is_use_of_global_constant( $this->phpcsFile, $stackPtr ) === false ) { 103 | return; 104 | } 105 | 106 | $this->phpcsFile->addWarning( 107 | 'Found usage of constant "%s". Use %s instead.', 108 | $stackPtr, 109 | MessageHelper::stringToErrorcode( $content . 'UsageFound' ), 110 | array( 111 | $content, 112 | $this->discouraged_constants[ $content ], 113 | ) 114 | ); 115 | } 116 | 117 | /** 118 | * Process the parameters of a matched `define` function call. 119 | * 120 | * @since 0.14.0 121 | * 122 | * @param int $stackPtr The position of the current token in the stack. 123 | * @param string $group_name The name of the group which was matched. 124 | * @param string $matched_content The token content (function name) which was matched 125 | * in lowercase. 126 | * @param array $parameters Array with information about the parameters. 127 | * 128 | * @return void 129 | */ 130 | public function process_parameters( $stackPtr, $group_name, $matched_content, $parameters ) { 131 | $target_param = $this->target_functions[ $matched_content ]; 132 | 133 | // Was the target parameter passed ? 134 | $found_param = PassedParameters::getParameterFromStack( $parameters, $target_param['position'], $target_param['name'] ); 135 | if ( false === $found_param ) { 136 | return; 137 | } 138 | 139 | $clean_content = TextStrings::stripQuotes( $found_param['clean'] ); 140 | 141 | if ( isset( $this->discouraged_constants[ $clean_content ] ) ) { 142 | $first_non_empty = $this->phpcsFile->findNext( 143 | Tokens::$emptyTokens, 144 | $found_param['start'], 145 | ( $found_param['end'] + 1 ), 146 | true 147 | ); 148 | 149 | $this->phpcsFile->addWarning( 150 | 'Found declaration of constant "%s". Use %s instead.', 151 | $first_non_empty, 152 | MessageHelper::stringToErrorcode( $clean_content . 'DeclarationFound' ), 153 | array( 154 | $clean_content, 155 | $this->discouraged_constants[ $clean_content ], 156 | ) 157 | ); 158 | } 159 | } 160 | } 161 | -------------------------------------------------------------------------------- /WordPress/Sniffs/WP/DiscouragedFunctionsSniff.php: -------------------------------------------------------------------------------- 1 | array( 26 | * 'lambda' => array( 27 | * 'type' => 'error' | 'warning', 28 | * 'message' => 'Use anonymous functions instead please!', 29 | * 'functions' => array( 'file_get_contents', 'create_function' ), 30 | * ) 31 | * ) 32 | * 33 | * @return array 34 | */ 35 | public function getGroups() { 36 | return array( 37 | 'query_posts' => array( 38 | 'type' => 'warning', 39 | 'message' => '%s() is discouraged. Use WP_Query instead.', 40 | 'functions' => array( 41 | 'query_posts', 42 | ), 43 | ), 44 | 45 | 'wp_reset_query' => array( 46 | 'type' => 'warning', 47 | 'message' => '%s() is discouraged. Use wp_reset_postdata() instead.', 48 | 'functions' => array( 49 | 'wp_reset_query', 50 | ), 51 | ), 52 | ); 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /WordPress/Sniffs/WP/EnqueuedResourcesSniff.php: -------------------------------------------------------------------------------- 1 | tokens[ $stackPtr ]['content']; 53 | if ( \T_INLINE_HTML !== $this->tokens[ $stackPtr ]['code'] ) { 54 | try { 55 | $end_ptr = TextStrings::getEndOfCompleteTextString( $this->phpcsFile, $stackPtr ); 56 | $content = TextStrings::getCompleteTextString( $this->phpcsFile, $stackPtr ); 57 | } catch ( RuntimeException $e ) { 58 | // Parse error/live coding. 59 | return; 60 | } 61 | } 62 | 63 | if ( preg_match_all( '# rel=\\\\?[\'"]?stylesheet\\\\?[\'"]?#', $content, $matches, \PREG_OFFSET_CAPTURE ) > 0 ) { 64 | foreach ( $matches[0] as $match ) { 65 | $this->phpcsFile->addError( 66 | 'Stylesheets must be registered/enqueued via wp_enqueue_style()', 67 | $this->find_token_in_multiline_string( $stackPtr, $content, $match[1] ), 68 | 'NonEnqueuedStylesheet' 69 | ); 70 | } 71 | } 72 | 73 | if ( preg_match_all( '#]*(?<=src=)#', $content, $matches, \PREG_OFFSET_CAPTURE ) > 0 ) { 74 | foreach ( $matches[0] as $match ) { 75 | $this->phpcsFile->addError( 76 | 'Scripts must be registered/enqueued via wp_enqueue_script()', 77 | $this->find_token_in_multiline_string( $stackPtr, $content, $match[1] ), 78 | 'NonEnqueuedScript' 79 | ); 80 | } 81 | } 82 | 83 | return ( $end_ptr + 1 ); 84 | } 85 | 86 | /** 87 | * Find the exact token on which the error should be reported for multi-line strings. 88 | * 89 | * @param int $stackPtr The position of the current token in the stack. 90 | * @param string $content The complete, potentially multi-line, text string. 91 | * @param int $match_offset The offset within the content at which the match was found. 92 | * 93 | * @return int The stack pointer to the token containing the start of the match. 94 | */ 95 | private function find_token_in_multiline_string( $stackPtr, $content, $match_offset ) { 96 | $newline_count = 0; 97 | if ( $match_offset > 0 ) { 98 | $newline_count = substr_count( $content, "\n", 0, $match_offset ); 99 | } 100 | 101 | // Account for heredoc/nowdoc text starting at the token *after* the opener. 102 | if ( isset( Tokens::$heredocTokens[ $this->tokens[ $stackPtr ]['code'] ] ) === true ) { 103 | ++$newline_count; 104 | } 105 | 106 | return ( $stackPtr + $newline_count ); 107 | } 108 | } 109 | -------------------------------------------------------------------------------- /WordPress/Sniffs/WP/GetMetaSingleSniff.php: -------------------------------------------------------------------------------- 1 | >> Key is function name, value is 64 | * an array containing information 65 | * about the name and position of 66 | * the relevant parameters. 67 | */ 68 | protected $target_functions = array( 69 | 'get_comment_meta' => array( 70 | 'condition' => array( 71 | 'param_name' => 'key', 72 | 'position' => 2, 73 | ), 74 | 'recommended' => array( 75 | 'param_name' => 'single', 76 | 'position' => 3, 77 | ), 78 | ), 79 | 'get_metadata' => array( 80 | 'condition' => array( 81 | 'param_name' => 'meta_key', 82 | 'position' => 3, 83 | ), 84 | 'recommended' => array( 85 | 'param_name' => 'single', 86 | 'position' => 4, 87 | ), 88 | ), 89 | 'get_metadata_default' => array( 90 | 'condition' => array( 91 | 'param_name' => 'meta_key', 92 | 'position' => 3, 93 | ), 94 | 'recommended' => array( 95 | 'param_name' => 'single', 96 | 'position' => 4, 97 | ), 98 | ), 99 | 'get_metadata_raw' => array( 100 | 'condition' => array( 101 | 'param_name' => 'meta_key', 102 | 'position' => 3, 103 | ), 104 | 'recommended' => array( 105 | 'param_name' => 'single', 106 | 'position' => 4, 107 | ), 108 | ), 109 | 'get_post_meta' => array( 110 | 'condition' => array( 111 | 'param_name' => 'key', 112 | 'position' => 2, 113 | ), 114 | 'recommended' => array( 115 | 'param_name' => 'single', 116 | 'position' => 3, 117 | ), 118 | ), 119 | 'get_site_meta' => array( 120 | 'condition' => array( 121 | 'param_name' => 'key', 122 | 'position' => 2, 123 | ), 124 | 'recommended' => array( 125 | 'param_name' => 'single', 126 | 'position' => 3, 127 | ), 128 | ), 129 | 'get_term_meta' => array( 130 | 'condition' => array( 131 | 'param_name' => 'key', 132 | 'position' => 2, 133 | ), 134 | 'recommended' => array( 135 | 'param_name' => 'single', 136 | 'position' => 3, 137 | ), 138 | ), 139 | 'get_user_meta' => array( 140 | 'condition' => array( 141 | 'param_name' => 'key', 142 | 'position' => 2, 143 | ), 144 | 'recommended' => array( 145 | 'param_name' => 'single', 146 | 'position' => 3, 147 | ), 148 | ), 149 | ); 150 | 151 | /** 152 | * Process the parameters of a matched function. 153 | * 154 | * @since 3.2.0 155 | * 156 | * @param int $stackPtr The position of the current token in the stack. 157 | * @param string $group_name The name of the group which was matched. 158 | * @param string $matched_content The token content (function name) which was matched 159 | * in lowercase. 160 | * @param array $parameters Array with information about the parameters. 161 | * 162 | * @return void 163 | */ 164 | public function process_parameters( $stackPtr, $group_name, $matched_content, $parameters ) { 165 | $condition = $this->target_functions[ $matched_content ]['condition']; 166 | $recommended = $this->target_functions[ $matched_content ]['recommended']; 167 | 168 | $meta_key = PassedParameters::getParameterFromStack( $parameters, $condition['position'], $condition['param_name'] ); 169 | if ( ! is_array( $meta_key ) ) { 170 | return; 171 | } 172 | 173 | $single = PassedParameters::getParameterFromStack( $parameters, $recommended['position'], $recommended['param_name'] ); 174 | if ( is_array( $single ) ) { 175 | $this->phpcsFile->recordMetric( $stackPtr, self::METRIC_NAME, 'yes' ); 176 | return; 177 | } 178 | 179 | $this->phpcsFile->recordMetric( $stackPtr, self::METRIC_NAME, 'no' ); 180 | 181 | $tokens = $this->phpcsFile->getTokens(); 182 | $message_data = array( 183 | $condition['param_name'], 184 | $tokens[ $stackPtr ]['content'], 185 | $recommended['param_name'], 186 | ); 187 | 188 | $this->phpcsFile->addWarning( 189 | 'When passing the $%s parameter to %s(), it is recommended to also pass the $%s parameter to explicitly indicate whether a single value or multiple values are expected to be returned.', 190 | $stackPtr, 191 | 'Missing', 192 | $message_data 193 | ); 194 | } 195 | } 196 | -------------------------------------------------------------------------------- /WordPress/Sniffs/WP/PostsPerPageSniff.php: -------------------------------------------------------------------------------- 1 | array( 47 | 'type' => 'warning', 48 | 'message' => 'Detected high pagination limit, `%s` is set to `%s`', 49 | 'keys' => array( 50 | 'posts_per_page', 51 | 'numberposts', 52 | ), 53 | ), 54 | ); 55 | } 56 | 57 | /** 58 | * Callback to process each confirmed key, to check value. 59 | * 60 | * @param string $key Array index / key. 61 | * @param mixed $val Assigned value. 62 | * @param int $line Token line. 63 | * @param array $group Group definition. 64 | * 65 | * @return bool FALSE if no match, TRUE if matches. 66 | */ 67 | public function callback( $key, $val, $line, $group ) { 68 | $stripped_val = TextStrings::stripQuotes( $val ); 69 | 70 | if ( '' === $stripped_val ) { 71 | return false; 72 | } 73 | 74 | if ( $val !== $stripped_val ) { 75 | // The value was a text string. For text strings, we only accept purely numeric values. 76 | if ( preg_match( '`^[0-9]+$`', $stripped_val ) !== 1 ) { 77 | // Not a purely numeric value, so any comparison would be a false comparison. 78 | return false; 79 | } 80 | 81 | // Purely numeric string, treat it as an integer from here on out. 82 | $val = $stripped_val; 83 | } 84 | 85 | $first_char = $val[0]; 86 | if ( '-' === $first_char || '+' === $first_char ) { 87 | $val = ltrim( $val, '-+' ); 88 | } else { 89 | $first_char = ''; 90 | } 91 | 92 | $real_value = Numbers::getDecimalValue( $val ); 93 | if ( false === $real_value ) { 94 | // This wasn't a purely numeric value, so any comparison would be a false comparison. 95 | return false; 96 | } 97 | 98 | $val = $first_char . $real_value; 99 | 100 | return ( (int) $val > (int) $this->posts_per_page ); 101 | } 102 | } 103 | -------------------------------------------------------------------------------- /WordPress/Sniffs/WhiteSpace/CastStructureSpacingSniff.php: -------------------------------------------------------------------------------- 1 | tokens[ ( $stackPtr - 1 ) ]['code'] 50 | && \T_ELLIPSIS !== $this->tokens[ ( $stackPtr - 1 ) ]['code'] 51 | ) { 52 | $error = 'Expected a space before the type cast open parenthesis; none found'; 53 | $fix = $this->phpcsFile->addFixableError( $error, $stackPtr, 'NoSpaceBeforeOpenParenthesis' ); 54 | if ( true === $fix ) { 55 | $this->phpcsFile->fixer->addContentBefore( $stackPtr, ' ' ); 56 | } 57 | } 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /WordPress/Sniffs/WhiteSpace/ObjectOperatorSpacingSniff.php: -------------------------------------------------------------------------------- 1 | getTokens(); 40 | $property_adjusted = false; 41 | 42 | // Check for `::class` and don't ignore new lines in that case. 43 | if ( true === $this->ignoreNewlines 44 | && \T_DOUBLE_COLON === $tokens[ $stackPtr ]['code'] 45 | ) { 46 | $next_non_empty = $phpcsFile->findNext( Tokens::$emptyTokens, ( $stackPtr + 1 ), null, true ); 47 | if ( \T_STRING === $tokens[ $next_non_empty ]['code'] 48 | && 'class' === strtolower( $tokens[ $next_non_empty ]['content'] ) 49 | ) { 50 | $property_adjusted = true; 51 | $this->ignoreNewlines = false; 52 | } 53 | } 54 | 55 | $return = parent::process( $phpcsFile, $stackPtr ); 56 | 57 | if ( true === $property_adjusted ) { 58 | $this->ignoreNewlines = true; 59 | } 60 | 61 | return $return; 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /WordPress/Sniffs/WhiteSpace/OperatorSpacingSniff.php: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | WordPress Coding Standards 5 | 6 | 10 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "wp-coding-standards/wpcs", 3 | "type": "phpcodesniffer-standard", 4 | "description": "PHP_CodeSniffer rules (sniffs) to enforce WordPress coding conventions", 5 | "keywords": [ 6 | "phpcs", 7 | "standards", 8 | "static analysis", 9 | "WordPress" 10 | ], 11 | "license": "MIT", 12 | "authors": [ 13 | { 14 | "name": "Contributors", 15 | "homepage": "https://github.com/WordPress/WordPress-Coding-Standards/graphs/contributors" 16 | } 17 | ], 18 | "require": { 19 | "php": ">=5.4", 20 | "ext-filter": "*", 21 | "ext-libxml": "*", 22 | "ext-tokenizer": "*", 23 | "ext-xmlreader": "*", 24 | "squizlabs/php_codesniffer": "^3.9.0", 25 | "phpcsstandards/phpcsutils": "^1.0.10", 26 | "phpcsstandards/phpcsextra": "^1.2.1" 27 | }, 28 | "require-dev": { 29 | "phpcompatibility/php-compatibility": "^9.0", 30 | "phpunit/phpunit": "^4.0 || ^5.0 || ^6.0 || ^7.0 || ^8.0 || ^9.0", 31 | "phpcsstandards/phpcsdevtools": "^1.2.0", 32 | "php-parallel-lint/php-parallel-lint": "^1.3.2", 33 | "php-parallel-lint/php-console-highlighter": "^1.0.0" 34 | }, 35 | "suggest": { 36 | "ext-iconv": "For improved results", 37 | "ext-mbstring": "For improved results" 38 | }, 39 | "config": { 40 | "allow-plugins": { 41 | "dealerdirect/phpcodesniffer-composer-installer": true 42 | }, 43 | "lock": false 44 | }, 45 | "scripts": { 46 | "lint": [ 47 | "@php ./vendor/php-parallel-lint/php-parallel-lint/parallel-lint . -e php --show-deprecated --exclude vendor --exclude .git" 48 | ], 49 | "check-cs": [ 50 | "@php ./vendor/squizlabs/php_codesniffer/bin/phpcs" 51 | ], 52 | "fix-cs": [ 53 | "@php ./vendor/squizlabs/php_codesniffer/bin/phpcbf" 54 | ], 55 | "run-tests": [ 56 | "@php ./vendor/phpunit/phpunit/phpunit --filter WordPress ./vendor/squizlabs/php_codesniffer/tests/AllTests.php --no-coverage" 57 | ], 58 | "coverage": [ 59 | "@php ./vendor/phpunit/phpunit/phpunit --filter WordPress ./vendor/squizlabs/php_codesniffer/tests/AllTests.php" 60 | ], 61 | "check-complete": [ 62 | "@php ./vendor/phpcsstandards/phpcsdevtools/bin/phpcs-check-feature-completeness -q ./WordPress" 63 | ], 64 | "check-complete-strict": [ 65 | "@php ./vendor/phpcsstandards/phpcsdevtools/bin/phpcs-check-feature-completeness ./WordPress" 66 | ], 67 | "check-all": [ 68 | "@lint", 69 | "@check-cs", 70 | "@run-tests", 71 | "@check-complete-strict" 72 | ] 73 | }, 74 | "scripts-descriptions": { 75 | "lint": "Lint PHP files against parse errors.", 76 | "check-cs": "Run the PHPCS script against the entire codebase.", 77 | "fix-cs": "Run the PHPCBF script to fix all the autofixable violations on the codebase.", 78 | "run-tests": "Run all the unit tests for the WordPress Coding Standards sniffs without code coverage.", 79 | "coverage": "Run all the unit tests for the WordPress Coding Standards sniffs with code coverage.", 80 | "check-complete": "Check if all the sniffs have tests.", 81 | "check-complete-strict": "Check if all the sniffs have unit tests and XML documentation.", 82 | "check-all": "Run all checks (lint, phpcs, feature completeness) and tests." 83 | }, 84 | "support": { 85 | "issues": "https://github.com/WordPress/WordPress-Coding-Standards/issues", 86 | "wiki": "https://github.com/WordPress/WordPress-Coding-Standards/wiki", 87 | "source": "https://github.com/WordPress/WordPress-Coding-Standards" 88 | } 89 | } 90 | -------------------------------------------------------------------------------- /phpcs.xml.dist.sample: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | A custom set of rules to check for a WPized WordPress project 5 | 6 | 12 | 13 | . 14 | 15 | 16 | /docroot/wp-admin/* 17 | /docroot/wp-includes/* 18 | /docroot/wp-*.php 19 | /docroot/index.php 20 | /docroot/xmlrpc.php 21 | /docroot/wp-content/plugins/* 22 | 23 | 24 | /vendor/* 25 | 26 | 27 | /node_modules/* 28 | 29 | 30 | *.min.js 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 44 | 45 | 46 | 47 | 58 | 59 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 80 | 86 | 87 | 88 | 93 | 94 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 129 | 130 | 146 | 147 | /path/to/Tests/*Test\.php 148 | 149 | 150 | /path/to/Tests/*Test\.php 151 | 152 | 153 | 154 | --------------------------------------------------------------------------------