#!/usr/bin/env bash # Install phpcbf/phpcs + WordPress Coding Standards + PHPCSExtra globally # Focus: phpcbf-first (auto-fixing). Safe to re-run. Non-destructive. set -euo pipefail log() { printf "\033[1;32m==>\033[0m %s\n" "$*"; } warn() { printf "\033[1;33m[warn]\033[0m %s\n" "$*"; } die() { printf "\033[1;31m[err]\033[0m %s\n" "$*" >&2; exit 1; } # --- 0) Requirements --------------------------------------------------------- command -v php >/dev/null 2>&1 || die "PHP not found. Install PHP and re-run." command -v composer >/dev/null 2>&1 || die "Composer not found. Install from https://getcomposer.org" # --- 1) Resolve Composer home & vendor/bin ----------------------------------- COMPOSER_HOME="$(composer global config home 2>/dev/null || true)" [ -n "${COMPOSER_HOME:-}" ] || die "Could not determine Composer home (composer global config home)." VENDOR_BIN="$COMPOSER_HOME/vendor/bin" PHPCS_BIN="$VENDOR_BIN/phpcs" PHPCBF_BIN="$VENDOR_BIN/phpcbf" log "Composer home: $COMPOSER_HOME" log "Vendor bin: $VENDOR_BIN" # --- 2) Ensure vendor/bin is on PATH now and persistently -------------------- ensure_path() { case "${SHELL:-}" in */zsh) PROFILE="$HOME/.zshrc" ;; */fish) PROFILE="$HOME/.config/fish/config.fish" ;; *) PROFILE="$HOME/.bashrc" ;; esac if ! echo ":$PATH:" | grep -q ":$VENDOR_BIN:"; then if [[ "$PROFILE" = *fish* ]]; then mkdir -p "$(dirname "$PROFILE")" grep -q "$VENDOR_BIN" "$PROFILE" 2>/dev/null || echo "set -Ux PATH $VENDOR_BIN \$PATH" >> "$PROFILE" warn "Added vendor/bin to Fish PATH. Restart shell or run: exec fish" else grep -q "$VENDOR_BIN" "$PROFILE" 2>/dev/null || echo "export PATH=\"$VENDOR_BIN:\$PATH\"" >> "$PROFILE" export PATH="$VENDOR_BIN:$PATH" warn "Added vendor/bin to PATH. Restart shell or run: export PATH=\"$VENDOR_BIN:\$PATH\"" fi fi } ensure_path # --- 3) Install PHPCS (phpcs/phpcbf) + WPCS + PHPCSExtra --------------------- log "Installing/updating PHP_CodeSniffer (phpcbf/phpcs), WPCS, and PHPCSExtra…" # Clean up any old/bad plugin names silently composer global remove dealerdirect/phpcodesniffer-plugin >/dev/null 2>&1 || true composer global require \ squizlabs/php_codesniffer:* \ wp-coding-standards/wpcs:* \ phpcsstandards/phpcsextra:^1.2 \ phpcsstandards/phpcsutils:^1.0 \ --no-interaction # --- 4) Register standards in installed_paths (WPCS + PHPCSExtra) ------------ WPCS_PATH="$COMPOSER_HOME/vendor/wp-coding-standards/wpcs" EXTRA_PATH="$COMPOSER_HOME/vendor/phpcsstandards/phpcsextra" [ -d "$WPCS_PATH" ] || die "WPCS not found at $WPCS_PATH (Composer install failed?)." [ -d "$EXTRA_PATH" ] || die "PHPCSExtra not found at $EXTRA_PATH (Composer install failed?)." merge_installed_paths() { local existing targets all dedup existing="$("$PHPCS_BIN" --config-show installed_paths 2>/dev/null | awk -F': ' 'NF>1{print $2}')" targets="$WPCS_PATH,$EXTRA_PATH" if [ -n "${existing:-}" ] && [ "$existing" != "." ] && [ "$existing" != "null" ]; then all="$existing,$targets" else all="$targets" fi # Deduplicate, keep order of first occurrence dedup="$(echo "$all" | tr ',' '\n' | awk 'NF' | awk '!seen[$0]++' | paste -sd',' -)" "$PHPCS_BIN" --config-set installed_paths "$dedup" >/dev/null } merge_installed_paths # Set default standard to WordPress (so phpcbf runs without flags) "$PHPCS_BIN" --config-set default_standard WordPress >/dev/null || true # --- 5) Add a convenience wrapper: wpcbf ------------------------------------ USER_BIN="${HOME}/.local/bin" mkdir -p "$USER_BIN" WPCBF="$USER_BIN/wpcbf" cat > "$WPCBF" <<'WRAP' #!/usr/bin/env bash set -euo pipefail # wpcbf: WordPress-first auto-fixer (phpcbf wrapper) # Usage: # wpcbf # fix current dir # wpcbf file.php # fix a file # wpcbf src tests # fix multiple paths ARGS=("$@") if [ ${#ARGS[@]} -eq 0 ]; then ARGS=("."); fi exec phpcbf \ --standard=WordPress \ --extensions=php,php5,phtml \ --report=summary \ --parallel="$(getconf _NPROCESSORS_ONLN 2>/dev/null || echo 4)" \ "${ARGS[@]}" WRAP chmod +x "$WPCBF" # Ensure ~/.local/bin is on PATH too if ! echo ":$PATH:" | grep -q ":$USER_BIN:"; then case "${SHELL:-}" in */fish) PROFILE="$HOME/.config/fish/config.fish" mkdir -p "$(dirname "$PROFILE")" grep -q "$USER_BIN" "$PROFILE" 2>/dev/null || echo "set -Ux PATH $USER_BIN \$PATH" >> "$PROFILE" warn "Added $USER_BIN to Fish PATH. Restart shell or run: exec fish" ;; *) PROFILE="${PROFILE:-$HOME/.bashrc}" grep -q "$USER_BIN" "$PROFILE" 2>/dev/null || echo "export PATH=\"$USER_BIN:\$PATH\"" >> "$PROFILE" export PATH="$USER_BIN:$PATH" warn "Added $USER_BIN to PATH. Restart shell or run: export PATH=\"$USER_BIN:\$PATH\"" ;; esac fi # --- 6) Sanity checks -------------------------------------------------------- log "Sanity check:" "$PHPCBF_BIN" --version || true "$PHPCS_BIN" -i || true "$PHPCS_BIN" --config-show default_standard | sed 's/^/ /' cat <<'NOTE' Done. You now have: • phpcbf installed globally (via PHP_CodeSniffer) • WordPress Coding Standards + PHPCSExtra registered globally • DEFAULT STANDARD set to: WordPress • 'wpcbf' helper command for quick fixing Quick start: wpcbf . phpcs --config-show phpcs -i If your editor reports "spawn phpcbf ENOENT": export PATH="$COMPOSER_HOME/vendor/bin:$HOME/.local/bin:$PATH" # Then point your editor’s "phpcbf executablePath" to: # $COMPOSER_HOME/vendor/bin/phpcbf NOTE log "All set for phpcbf-first WordPress fixing."