|
| 1 | +# Plugin Check – AI Coding Agent Instructions |
| 2 | + |
| 3 | +This file provides context for AI coding agents (Claude Code, OpenAI Codex, Gemini CLI, GitHub Copilot, etc.) working on the Plugin Check repository. |
| 4 | + |
| 5 | +## Project Overview |
| 6 | + |
| 7 | +**Plugin Check** (also known as PCP – Plugin Check Plugin) is a WordPress.org tool that helps plugin authors ensure their plugins meet the [WordPress.org Plugin Directory requirements](https://developer.wordpress.org/plugins/wordpress-org/detailed-plugin-guidelines/) and follow best practices. |
| 8 | + |
| 9 | +It supports two modes of operation: |
| 10 | +- **WP Admin UI** – accessible via _Tools > Plugin Check_. |
| 11 | +- **WP-CLI** – via `wp plugin check <plugin-slug>`. |
| 12 | + |
| 13 | +## Repository Structure |
| 14 | + |
| 15 | +``` |
| 16 | +plugin-check/ |
| 17 | +├── plugin.php # Main plugin entry point |
| 18 | +├── cli.php # WP-CLI bootstrap (loaded via --require for runtime checks) |
| 19 | +├── includes/ # Core PHP source (PSR-4 autoloaded under WordPress\Plugin_Check\) |
| 20 | +│ ├── Admin/ # WP Admin UI screens and assets registration |
| 21 | +│ ├── Checker/ # Core check interfaces, abstract classes, and all check implementations |
| 22 | +│ │ ├── Checks/ # Individual check classes (static and runtime) |
| 23 | +│ │ ├── Abstract_Check_Runner.php |
| 24 | +│ │ ├── Check_Categories.php |
| 25 | +│ │ ├── Check_Result.php |
| 26 | +│ │ ├── Default_Check_Repository.php # Registers all built-in checks |
| 27 | +│ │ ├── Runtime_Check.php # Interface for runtime checks |
| 28 | +│ │ └── Static_Check.php # Interface for static checks |
| 29 | +│ ├── CLI/ # WP-CLI command classes |
| 30 | +│ ├── Lib/ # Third-party libraries (do not lint) |
| 31 | +│ ├── Scanner/ # Plugin scanner and file utilities |
| 32 | +│ ├── Traits/ # Reusable traits (Stable_Check, Experimental_Check, etc.) |
| 33 | +│ ├── Utilities/ # Helper utilities |
| 34 | +│ └── Vars/ # Static data (e.g., wp-functions-since.json) |
| 35 | +├── tests/ |
| 36 | +│ ├── phpunit/ |
| 37 | +│ │ ├── tests/ # All PHPUnit test classes |
| 38 | +│ │ ├── testdata/ # Example plugins and classes used in tests |
| 39 | +│ │ └── utils/ # Shared test helpers |
| 40 | +│ └── behat/ # End-to-end Behat/WP-CLI tests |
| 41 | +├── docs/ # Technical documentation |
| 42 | +├── assets/ # JS/CSS for the WP Admin UI |
| 43 | +├── phpcs-sniffs/ # Custom PHPCS sniffs bundled with the plugin |
| 44 | +├── phpcs-rulesets/ # PHPCS ruleset definitions |
| 45 | +├── templates/ # PHP templates for the Admin UI |
| 46 | +├── tools/ # Developer scripts (e.g., generate WP function data) |
| 47 | +├── drop-ins/ # WordPress drop-in files used during runtime checks |
| 48 | +└── runtime-content/ # Content used to set up the runtime check environment |
| 49 | +``` |
| 50 | + |
| 51 | +## Coding Standards |
| 52 | + |
| 53 | +All PHP code **must** follow the [WordPress Coding Standards](https://developer.wordpress.org/coding-standards/wordpress-coding-standards/php/): |
| 54 | + |
| 55 | +- **PHP minimum version**: 7.4 |
| 56 | +- **WordPress minimum version**: 6.3 |
| 57 | +- **Namespace**: `WordPress\Plugin_Check\` (PSR-4, mapped to `includes/`) |
| 58 | +- Use tabs for indentation (not spaces). |
| 59 | +- All public methods and classes must have proper PHPDoc blocks (except in test files). |
| 60 | +- Text domain: `plugin-check` (or `default` for core strings). |
| 61 | +- Do **not** add docblocks to unit test methods/classes/files (excluded by PHPCS config). |
| 62 | +- Third-party code lives in `includes/Lib/` and is excluded from linting. |
| 63 | + |
| 64 | +### JavaScript |
| 65 | + |
| 66 | +- Follows [@wordpress/scripts](https://www.npmjs.com/package/@wordpress/scripts) ESLint configuration. |
| 67 | +- Source files are in `assets/js/` and `assets/css/`. |
| 68 | + |
| 69 | +## Architecture: Adding a New Check |
| 70 | + |
| 71 | +Every check must implement either `Static_Check` or `Runtime_Check` (both in `includes/Checker/`). |
| 72 | + |
| 73 | +### Static Check (no code execution) |
| 74 | + |
| 75 | +Extend `Abstract_File_Check` or `Abstract_PHP_CodeSniffer_Check`, or implement `Static_Check` directly: |
| 76 | + |
| 77 | +```php |
| 78 | +use WordPress\Plugin_Check\Checker\Check_Categories; |
| 79 | +use WordPress\Plugin_Check\Checker\Check_Result; |
| 80 | +use WordPress\Plugin_Check\Checker\Static_Check; |
| 81 | +use WordPress\Plugin_Check\Traits\Stable_Check; |
| 82 | + |
| 83 | +class My_Custom_Check implements Static_Check { |
| 84 | + use Stable_Check; |
| 85 | + |
| 86 | + public function get_categories(): array { |
| 87 | + return array( Check_Categories::CATEGORY_PLUGIN_REPO ); |
| 88 | + } |
| 89 | + |
| 90 | + public function run( Check_Result $result ): void { |
| 91 | + // Add errors/warnings to $result. |
| 92 | + } |
| 93 | +} |
| 94 | +``` |
| 95 | + |
| 96 | +### Runtime Check (executes plugin code) |
| 97 | + |
| 98 | +Extend `Abstract_Runtime_Check`. Runtime checks may also need a `Preparation` class. |
| 99 | + |
| 100 | +### Registering a Check |
| 101 | + |
| 102 | +Add the new check class to `Default_Check_Repository::register_default_checks()` in `includes/Checker/Default_Check_Repository.php`. |
| 103 | + |
| 104 | +### Check Stability |
| 105 | + |
| 106 | +- Use the `Stable_Check` trait for checks that run by default. |
| 107 | +- Use the `Experimental_Check` trait for checks only available via `--include-experimental`. |
| 108 | + |
| 109 | +### Check Categories |
| 110 | + |
| 111 | +Use constants from `Check_Categories`: |
| 112 | +- `CATEGORY_GENERAL` – General best practices. |
| 113 | +- `CATEGORY_PLUGIN_REPO` – WordPress.org Plugin Directory requirements. |
| 114 | +- `CATEGORY_SECURITY` – Security-related checks. |
| 115 | +- `CATEGORY_PERFORMANCE` – Performance-related checks. |
| 116 | +- `CATEGORY_ACCESSIBILITY` – Accessibility checks. |
| 117 | + |
| 118 | +## Common Commands |
| 119 | + |
| 120 | +### Setup |
| 121 | + |
| 122 | +```bash |
| 123 | +# Install PHP dependencies |
| 124 | +composer install |
| 125 | + |
| 126 | +# Install Node dependencies |
| 127 | +npm install |
| 128 | +``` |
| 129 | + |
| 130 | +### Development Environment (requires Docker) |
| 131 | + |
| 132 | +```bash |
| 133 | +# Start the development site |
| 134 | +npm run wp-env start |
| 135 | + |
| 136 | +# Start the test stack |
| 137 | +npm run wp-env:start:tests |
| 138 | + |
| 139 | +# Stop each stack |
| 140 | +npm run wp-env stop |
| 141 | +npm run wp-env:stop:tests |
| 142 | +``` |
| 143 | + |
| 144 | +### Linting |
| 145 | + |
| 146 | +```bash |
| 147 | +# PHP linting (PHPCS) |
| 148 | +composer lint |
| 149 | +# or via npm (uses wp-env): |
| 150 | +npm run lint-php |
| 151 | + |
| 152 | +# PHP auto-fix (PHPCBF) |
| 153 | +composer format |
| 154 | +# or via npm: |
| 155 | +npm run format-php |
| 156 | + |
| 157 | +# JavaScript linting |
| 158 | +npm run lint-js |
| 159 | + |
| 160 | +# JavaScript auto-fix |
| 161 | +npm run format-js |
| 162 | + |
| 163 | +# Gherkin/Behat feature files |
| 164 | +npm run lint-gherkin |
| 165 | + |
| 166 | +# PHPStan static analysis |
| 167 | +composer phpstan |
| 168 | +# or via npm: |
| 169 | +npm run phpstan |
| 170 | +``` |
| 171 | + |
| 172 | +### Testing |
| 173 | + |
| 174 | +```bash |
| 175 | +# Run PHPUnit tests (requires test stack running) |
| 176 | +npm run test-php |
| 177 | + |
| 178 | +# Run PHPUnit with coverage |
| 179 | +npm run test-php-coverage |
| 180 | + |
| 181 | +# Run multisite PHPUnit tests |
| 182 | +npm run test-php-multisite |
| 183 | + |
| 184 | +# Run Behat/WP-CLI integration tests |
| 185 | +composer behat |
| 186 | +``` |
| 187 | + |
| 188 | +### Running the plugin locally |
| 189 | + |
| 190 | +Use [WordPress Playground CLI](https://wordpress.github.io/wordpress-playground/developers/local-development/wp-playground-cli) to run WordPress with the plugin auto-mounted: |
| 191 | + |
| 192 | +```bash |
| 193 | +npx @wp-playground/cli@latest server --auto-mount --php=8.1 --login --port=9400 |
| 194 | +``` |
| 195 | + |
| 196 | +This starts WordPress at `http://127.0.0.1:9400` with the plugin already active. No Docker, MySQL, or Apache needed for manual testing — Playground uses SQLite internally. |
| 197 | + |
| 198 | +### WP-CLI Usage (on a local site) |
| 199 | + |
| 200 | +```bash |
| 201 | +# Static checks only |
| 202 | +wp plugin check <plugin-slug> |
| 203 | + |
| 204 | +# Static + runtime checks |
| 205 | +wp plugin check <plugin-slug> --require=./wp-content/plugins/plugin-check/cli.php |
| 206 | + |
| 207 | +# Check from a ZIP URL |
| 208 | +wp plugin check https://example.com/plugin.zip --require=./wp-content/plugins/plugin-check/cli.php |
| 209 | + |
| 210 | +# List available checks |
| 211 | +wp plugin check-list |
| 212 | +``` |
| 213 | + |
| 214 | +## Testing Guidelines |
| 215 | + |
| 216 | +- Every new check **must** have a corresponding PHPUnit test in `tests/phpunit/tests/`. |
| 217 | +- Test data (example plugins/classes) goes in `tests/phpunit/testdata/`. |
| 218 | +- Shared test helpers go in `tests/phpunit/utils/`. |
| 219 | +- Tests are run via GitHub Actions on every PR; passing tests is required to merge. |
| 220 | +- The test bootstrap is at `tests/phpunit/bootstrap.php`. |
| 221 | + |
| 222 | +## Contribution Guidelines |
| 223 | + |
| 224 | +- All contributions must follow the [WordPress Code of Conduct](https://make.wordpress.org/handbook/community-code-of-conduct/). |
| 225 | +- All code is licensed under **GPL-2.0-or-later**. |
| 226 | +- Open issues and PRs on [GitHub](https://github.com/WordPress/plugin-check). |
| 227 | +- See [CONTRIBUTING.md](./CONTRIBUTING.md) for the full guide. |
| 228 | +- See [SECURITY.md](./SECURITY.md) for reporting security issues. |
| 229 | + |
| 230 | +## Key Documentation |
| 231 | + |
| 232 | +- [Technical Overview](./docs/technical-overview.md) |
| 233 | +- [Creating a Static Check](./docs/creating-a-static-check.md) |
| 234 | +- [Creating a Runtime Check](./docs/creating-a-runtime-check.md) |
| 235 | +- [Available Checks](./docs/checks.md) |
| 236 | +- [CLI Commands](./docs/CLI.md) |
| 237 | +- [Running Unit Tests](./docs/running-unit-tests.md) |
| 238 | +- [Releasing a New Version](./docs/releasing.md) |
0 commit comments