wp-coding-standards — independently scanned and version-tracked by SaferSkills.
SaferSkills independently audited wp-coding-standards (Agent Skill) and scored it 100/100 (green). The audit ran 55 deterministic rules across Security, Supply Chain, Maintenance, Transparency, and Community; it found 0 high-severity and 0 lower-severity findings. The full rule-by-rule trace and per-finding evidence are below. Free, methodology-open.
Findings & checks · 0 flagged
Every scanned point with the score it earned and what moved between them.
First recorded scan — no prior version to compare against.
The primary manifest — the file an agent reads to learn what this artifact does.
Model note: Setup and config steps are mechanical (haiku). Fixing sniff violations across many files works fine onhaiku. Only reach forsonnet/opuswhen violations involve subtle logic (e.g. escaping inside complex SQL builders).
Configure and enforce the WordPress Coding Standards via PHP_CodeSniffer. WPCS is required for WP.org submission and is the canonical style guide for all WordPress PHP code.
Not for: PHPStan static analysis or type checking — use wp-phpstan-stubs. Security auditing beyond style issues — use wp-plugin-audit.
composer require --dev squizlabs/php_codesniffer wp-coding-standards/wpcs dealerdirect/phpcodesniffer-composer-installerdealerdirect/phpcodesniffer-composer-installer auto-registers WPCS paths so no manual --config-set is needed. Verify:
vendor/bin/phpcs -i
# should list: WordPress, WordPress-Core, WordPress-Docs, WordPress-Extraphpcs.xml.distPlace at project root. This is the canonical config file (.dist allows local phpcs.xml override).
<?xml version="1.0"?>
<ruleset name="My Plugin">
<description>WordPress Coding Standards for My Plugin</description>
<!-- What to scan -->
<file>.</file>
<exclude-pattern>vendor/*</exclude-pattern>
<exclude-pattern>node_modules/*</exclude-pattern>
<exclude-pattern>build/*</exclude-pattern>
<exclude-pattern>*.min.js</exclude-pattern>
<exclude-pattern>*.min.css</exclude-pattern>
<exclude-pattern>tests/bootstrap.php</exclude-pattern>
<!-- PHP version target -->
<config name="testVersion" value="7.4-"/>
<!-- Ruleset -->
<rule ref="WordPress-Extra">
<!-- Suppress if you use short array syntax (WP allows it since WP 5.5) -->
<!-- <exclude name="Generic.Arrays.DisallowShortArraySyntax"/> -->
</rule>
<rule ref="WordPress-Docs"/>
<!-- Text domain for i18n sniffs -->
<rule ref="WordPress.WP.I18n">
<properties>
<property name="text_domain" type="array" value="my-plugin"/>
</properties>
</rule>
<!-- Minimum WP version for deprecated functions -->
<rule ref="WordPress.WP.DeprecatedFunctions">
<properties>
<property name="minimum_supported_version" value="5.9"/>
</properties>
</rule>
<!-- Prefix all globals -->
<rule ref="WordPress.NamingConventions.PrefixAllGlobals">
<properties>
<property name="prefixes" type="array" value="my_plugin,MyPlugin"/>
</properties>
</rule>
<!-- Show sniff codes in output (for targeted suppression) -->
<arg value="ps"/>
<arg name="extensions" value="php"/>
<arg name="colors"/>
</ruleset># Check
vendor/bin/phpcs
# Auto-fix (safe mechanical fixes only — review after)
vendor/bin/phpcbf
# Single file or directory
vendor/bin/phpcs includes/class-my-class.php
# Show full sniff code for each violation (useful for writing suppressions)
vendor/bin/phpcs --report=full -sSuppress only when the sniff is a genuine false positive, not to hide real issues.
// phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- escaped in template
echo $pre_escaped_html;
// phpcs:disable WordPress.DB.DirectDatabaseQuery
$wpdb->query( $wpdb->prepare( "DELETE FROM {$wpdb->prefix}my_table WHERE id = %d", $id ) );
// phpcs:enable WordPress.DB.DirectDatabaseQueryCommon false positives and correct suppression codes:
| Situation | Sniff to ignore |
|---|---|
| Pre-escaped variable via custom escaper | WordPress.Security.EscapeOutput.OutputNotEscaped |
Intentional direct DB query with prepare() | WordPress.DB.DirectDatabaseQuery.DirectQuery |
| Custom DB cache managed explicitly | WordPress.DB.DirectDatabaseQuery.NoCaching |
__FILE__ used in plugin_dir_url() | WordPress.Security.PluginMenuSlug (rare) |
| Slow DB query that is intentional | WordPress.DB.SlowDBQuery.slow_db_query_meta_query |
Missing nonce verification:
// Bad
$value = sanitize_text_field( $_POST['field'] );
// Good
if ( ! isset( $_POST['my_plugin_nonce'] ) || ! wp_verify_nonce( sanitize_key( $_POST['my_plugin_nonce'] ), 'my_action' ) ) {
wp_die( esc_html__( 'Security check failed.', 'my-plugin' ) );
}
$value = sanitize_text_field( wp_unslash( $_POST['field'] ) );Missing `wp_unslash()` before sanitize:
// Bad — sanitize_text_field on slashed data
$val = sanitize_text_field( $_POST['field'] );
// Good
$val = sanitize_text_field( wp_unslash( $_POST['field'] ) );Unescaped output:
echo $title; // Bad
echo esc_html( $title ); // Good
echo wp_kses_post( $html_content ); // Good for HTMLYoda conditions:
if ( $value == true ) {} // Bad
if ( true == $value ) {} // Good (Yoda)
if ( $value ) {} // Also fineIncorrect hook comment spacing:
add_action('init', 'my_fn'); // Bad — no spaces inside parens
add_action( 'init', 'my_fn' ); // GoodMisaligned array `=>` / assignment blocks:
// Bad — WPCS flags Generic.Formatting.MultipleStatementAlignment
$args = array(
'id' => 1,
'post_type' => 'post',
);
// Good — double arrows aligned within the block
$args = array(
'id' => 1,
'post_type' => 'post',
);Always keep => (and consecutive =) aligned within a block — phpcbf fixes this automatically. Never hand-collapse them to single spaces to "tidy" the code; WPCS just re-flags it.
# .github/workflows/phpcs.yml
name: PHPCS
on: [push, pull_request]
jobs:
phpcs:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: shivammathur/setup-php@v2
with:
php-version: '7.4'
tools: composer
- run: composer install --no-interaction --prefer-dist
- run: vendor/bin/phpcsPHPStorm: Settings → PHP → Quality Tools → PHP_CodeSniffer → set path to vendor/bin/phpcs. Enable "Inspections → PHP → PHP Code Sniffer validation".
VS Code: Install shevaua.phpcs extension. Set phpcs.executablePath to ./vendor/bin/phpcs in workspace settings.
WordPress-Extra is a superset of WordPress-Core; always use WordPress-Extra unless you have a specific reason to be less strict.WordPress-Docs is separate — it enforces PHPDoc blocks. Include it for WP.org submissions.WordPress.WP.I18n) catch missing text domains and non-translatable strings — complement to wp-plugin-audit Dimension B.WooCommerce-Core ruleset if available (woocommerce/woocommerce-sniffs).references/ci-phpcs.md — PHPCS in GitHub Actions: minimal workflow, PHP×WP matrix, caching, and failure triagereferences/phpcs-config-examples.md — phpcs.xml.dist configurations: WP.org-ready minimal, WooCommerce extension, and custom sniff exclusion patternsreferences/wpcs-sniffs.md — WordPress Coding Standards sniff reference: ruleset hierarchy, key sniff descriptions, and common // phpcs:ignore patterns~30 seconds. Free. No account. Every finding cites a rule and a line of evidence.