lipemat / wp-phpcs
PHP Codesniffer for a WordPress plugin
Package info
Type:phpcodesniffer-standard
pkg:composer/lipemat/wp-phpcs
Fund package maintenance!
Requires
- php: >=7.4.0
- automattic/vipwpcs: ^3.0.1
- dealerdirect/phpcodesniffer-composer-installer: ^1.1.2
- phpcompatibility/phpcompatibility-wp: ^3.0.0
- phpcsstandards/phpcsextra: ^1.0.2
- sirbrillig/phpcs-variable-analysis: ^2.12.0
- squizlabs/php_codesniffer: ^3.13.2
- wp-coding-standards/wpcs: ^3.4.1
Requires (Dev)
- ext-json: *
- cweagans/composer-patches: ^1.7
- roave/security-advisories: dev-latest
Suggests
None
Provides
None
Conflicts
None
Replaces
None
This package is auto-updated.
Last update: 2026-09-03 19:51:00 UTC
README
PHP Codesniffer setup for a WordPress plugin.
Installation
Use composer to install. Although this may be added directly to your plugins composer.json, it is recommended to install somewhere globally to reuse across projects.
If not using as a global library, your local composer.json will need to include the following config.
{
"config": {
"allow-plugins": {
"dealerdirect/phpcodesniffer-composer-installer": true
}
}
}
Install via composer
composer require lipemat/wp-phpcs
Copy the phpcs-sample.xml file to the root of your plugin and rename to phpcs.xml. Adjust the configuration as desired.
Running
The vendor/bin folder includes the scripts to run on either Windows or Unix. You may either add that directory to your PATH or call it verbosely like so:
{project dir}/vendor/bin/phpcs ./
OR
{project dir}/vendor/bin/phpcbf ./
You may also create your own script somewhere on your PATH. Here is an example phpcs.bat for Windows. This assumes you created a folder named wp-phpcs in your root and ran composer require there.
@echo off
C:\wp-phpcs\vendor\bin\phpcs %*
Automating
Once you have scripts added to your path for phpcs and phpcbf, you can use the included git-hooks/pre-commit to run PHP lint and PHPCS automatically before making any commit.
Copy the pre-commit file to your plugin's .git/hooks directory, and the rest is automatic.
Included Sniffs
Lipe Sniffs
This package ships with some optional Lipe namespaced sniffs.
<rule ref="Lipe" />for all our default configurations and sniffs.- @note This configuration is opinionated, you probably just want to include desired sniff namespaces.
<rule ref="Lipe.DB.CalcFoundRows" />for detecting the deprecated uses of MySQLSQL_CALC_FOUND_ROWS.<rule ref="Lipe.PHP.DisallowNullCoalesceInCondition" />for detecting using??in conditions.<rule ref="Lipe.PHP.DisallowNullCoalesceInForLoops" />for detecting using??in for loops.<rule ref="Lipe.Performance.SlowMetaQuery" />for detecting slow meta queries.- Like
WordPress.DB.SlowDBQuery.slow_db_query_meta_querybut supports usingEXISTSandNOT_EXISTSmeta queries.
- Like
<rule ref="Lipe.Performance.SlowOrderBy" />for detecting slowORDER BYclauses in WP_Query.<rule ref="Lipe.Performance.PostNotIn" />for detecting uses ofpost__not_inclauses in WP_Query.<rule ref="Lipe.Performance.SuppressFilters" />for detecting missing uses ofsuppress_filtersclauses in get_posts.
LipePlugin Sniffs
This package ships with some optional LipePlugin namespaced sniffs designed to be used with a distributed plugin or library.
<rule ref="LipePlugin" />for all the default configurations and sniffs.- @note This configuration is opinionated, you probably just want to include desired sniff namespaces.
<rule ref="Lipe.CodeAnalysis.SelfInClassSniff" />force usingstaticinstead ofselfto improve extensibility.- 'ReturnType' - return type of methods.
- 'InstanceOf' - self instance for static calls.
- 'NewInstance' - Constructing via
new self(). - 'ScopeResolution' - Local constants via
self::.
<rule ref="LipePlugin.TypeHints.PrivateInClass" />for distributed packages, which should not useprivateto improve extensibility.<rule ref="LipePlugin.TypeHints.PreventStrictTypes" />for distributed packages, which should not usestrict_typeto improve compatibility.
Performance
These standards are tuned to keep scans fast:
Generic.PHP.Syntaxis excluded. It shells out tophp -lonce per file, making it by far the most expensive sniff (it accounted for ~26% of total scan time in profiling). Syntax errors are already surfaced by the PHP runtime, your IDE, CI, and the includedgit-hooks/pre-commitlint step, so the sniff is redundant.- Enable caching in your project ruleset so unchanged files are skipped between runs:
<arg name="cache" value="./.phpcs.cache" />
phpcs -p(parallel) requires thepcntlextension, which is not available on Windows. This package ships a composer patch (dev/patches/runner-windows-parallel.patch) that adds aproc_open-based fallback to PHPCS'sRunner, so--parallel=Nworks on Windows too. The patch is applied automatically bycweagans/composer-patchesduringcomposer installof this package. The POSIXpcntl_forkpath is left untouched.- Each Windows child re-loads the ruleset, so parallelism only pays off on larger file
counts (rule of thumb: > ~50 files). Combine with
--cachefor the best results. - To identify slow files in a large scan, set
PHPCS_BATCH_TIMING=1before running phpcs. After the run, the slowest 7 batches (with their file lists and wall-clock elapsed times) are printed to STDERR. Override the count withPHPCS_BATCH_TIMING_TOP=N. Diagnostic is off by default and has zero overhead when disabled.
- Each Windows child re-loads the ruleset, so parallelism only pays off on larger file
counts (rule of thumb: > ~50 files). Combine with
Note: narrowing
testVersion(e.g.8.4vs an open-ended8.4-) does not speed up scans.PHPCompatibilityregisters and runs every one of its sniffs against every token regardless oftestVersion; the setting only filters which detected issues get reported. Profiling confirmed the two are equivalent within run-to-run noise.
To profile your own project, run phpcs --report=performance --no-cache to see per-sniff timings.
Other Notes
The phpcs-sample.xml has many things excluded. This is because some things don't really fit in with WordPress standards. You can remove any of <exclude> items to make more strict. Remove them all if you really want to make your code strict.