Git hooks are shell scripts stored in .git/hooks/ that execute automatically at specific points in the Git workflow — pre-commit runs before a commit is recorded, commit-msg validates the commit message format, and pre-push runs before refs are pushed to a remote. Running WordPress Coding Standards (WPCS) checks in a pre-commit hook catches coding standard violations locally, before they enter the repository, eliminating the round-trip delay of a CI failure that blocks a pull request. WPCS is installed via Composer: composer require --dev squizlabs/php_codesniffer wp-coding-standards/wpcs dealerdirect/phpcodesniffer-composer-installer; the dealerdirect installer automatically registers the WPCS sniff paths with PHPCS so no manual --config-set installed_paths step is needed. The pre-commit hook should lint only staged PHP files — passing all project files through PHPCS on every commit wastes time. git diff --cached --name-only --diff-filter=ACM returns only the filenames that are added, copied, or modified in the staging area; filtering by .php extension narrows to PHP files only. Exiting with a non-zero code from a hook aborts the Git operation — exit 1 from pre-commit cancels the commit and displays the PHPCS output, letting the developer fix violations immediately. Sharing hooks across a team requires distributing the hook scripts outside .git/hooks/, since .git/ is not tracked. The idiomatic approach is to store hooks in a tracked .githooks/ directory and configure Git to use it with git config core.hooksPath .githooks, which can be automated in a Composer post-install script. The --no-verify flag bypasses all hooks on a single commit — its use should be logged and reviewed. The git bisect post shows how automated tests integrate with Git to diagnose regressions — pre-commit hooks and bisect together form a complete quality gate at both the write and debug stages of the development workflow.
Problem: WordPress Coding Standards violations reach the remote repository because developers run PHPCS manually and inconsistently, causing CI failures after push and requiring fixup commits that pollute the project history.
Solution: Install WPCS via Composer, add a pre-commit hook that runs PHPCS only on staged PHP files and aborts the commit on violations, store the hook in a tracked .githooks/ directory, and register it automatically with a Composer post-install script.
# Install WPCS and PHPCS via Composer
composer require --dev \
squizlabs/php_codesniffer \
wp-coding-standards/wpcs \
dealerdirect/phpcodesniffer-composer-installer
# Verify the WPCS standard is registered
./vendor/bin/phpcs -i
# Expected: WordPress, WordPress-Core, WordPress-Docs, WordPress-Extra
#!/usr/bin/env bash
# .githooks/pre-commit
set -euo pipefail
PHPCS="./vendor/bin/phpcs"
STANDARD="WordPress-Extra"
IGNORE="vendor/*,node_modules/*"
# Collect staged PHP files (Added, Copied, Modified)
STAGED=$(git diff --cached --name-only --diff-filter=ACM | grep '\.php$' || true)
if [[ -z "$STAGED" ]]; then
exit 0
fi
echo "Running PHPCS (${STANDARD}) on staged PHP files..."
if ! "$PHPCS" --standard="$STANDARD" \
--ignore="$IGNORE" \
--colors \
--report=full \
$STAGED; then
echo ""
echo "PHPCS found violations. Commit aborted."
echo "Fix the issues above, or use 'git commit --no-verify' to bypass (use sparingly)."
exit 1
fi
echo "PHPCS: all staged files pass."
exit 0
{
"scripts": {
"post-install-cmd": [
"git config core.hooksPath .githooks",
"chmod +x .githooks/pre-commit"
],
"post-update-cmd": [
"git config core.hooksPath .githooks",
"chmod +x .githooks/pre-commit"
]
}
}
NOTE: core.hooksPath is a per-clone Git configuration setting — each developer must run composer install (or git config core.hooksPath .githooks manually) after cloning. Add a README note or a Makefile target that reminds new contributors to run composer install before making their first commit.