CI / Coding Standards (pull_request) Successful in 14s
CI / No Debug Code (pull_request) Successful in 3s
CI / Tests (PHP 8.1) (pull_request) Successful in 34s
CI / Tests (PHP 8.3) (pull_request) Successful in 43s
CI / Tests (PHP 8.5) (pull_request) Successful in 45s
CI / Tests (PHP 8.2) (pull_request) Successful in 1m0s
CI / Static Analysis (pull_request) Successful in 1m2s
CI / Build Plugin Zip (pull_request) Skipped
Co-authored-by: opencode/muse-spark-1.3-contributor-free
48 lines
3.3 KiB
Markdown
48 lines
3.3 KiB
Markdown
# AGENTS.md
|
|
|
|
## Commands
|
|
|
|
```bash
|
|
composer install
|
|
composer test # PHPUnit — run after every code change
|
|
composer lint # PHPStan (level 10, `src/` only)
|
|
composer cs # PHPCS (WordPress standard + exclusions in phpcs.xml.dist)
|
|
composer cs:fix # auto-fix coding standards
|
|
composer build # -> dist/unsupervised-schedular-<version>.zip
|
|
|
|
./vendor/bin/phpunit tests/Unit/Offering/OfferingRepositoryTest.php
|
|
./vendor/bin/phpunit --filter testInsertReturnsId
|
|
```
|
|
|
|
CI (`.gitea/workflows/ci.yml`): `phpcs`, `phpstan`, `test` (PHP 8.1/8.2/8.3/8.5), `no-debug`. Write only PHP 8.1-compatible syntax. No `var_dump|var_export|print_r|error_log|dd|dump(` in `src/` — CI greps and fails.
|
|
|
|
## Architecture
|
|
|
|
- WordPress plugin, no front-end build (vanilla JS/CSS in `assets/`). PSR-4 `Unsupervised\Schedular\` -> `src/`.
|
|
- **Package-by-domain:** `src/<Domain>/` (Auth, Availability, Booking, GroupClass, Guardian, Offering, Payment, Policy, Registration) owns its repos, services, endpoints, pages. Cross-cutting wiring lives directly in `src/`: `Plugin`, `Installer`, `Schema`, `AdminMenu`, `RestRegistrar`, `ShortcodeRegistrar`, `BlockRegistrar`, `Val`.
|
|
- Entry: `unsupervised-schedular.php` -> `Plugin::boot()` (wires all dependencies). **Slug is `schedular`, not `scheduler`** — filename, text domain (`unsupervised-schedular`), option `us_schedular_version`, table prefix `us_`. Never "fix" the spelling.
|
|
- REST: `/wp-json/us-scheduler/v1/`, `permission_callback` uses capability checks, never role names.
|
|
- DB: custom `us_*` tables via `dbDelta`; `Schema::tables()` is the source of truth. **All `$wpdb` access inside repository classes only.**
|
|
- `src/Val.php` coerces untyped WP input (`Val::int()`, `Val::string()`, `...OrNull`, etc.). For PHPCS, `Val::int/float/bool/...` count as unslashing passthrough only — still wrap with a real sanitizer: `absint( Val::int( $_GET['id'] ?? 0 ) )`.
|
|
|
|
## Schema changes (gotcha)
|
|
|
|
- `Plugin::boot()` only re-runs `Installer`/migrations when stored `us_schedular_version !== USC_VERSION`. **Bump both the `Version:` header and `USC_VERSION` in `unsupervised-schedular.php` or the change never reaches existing sites.**
|
|
- `dbDelta` does not reliably relax column NULL-ability. Follow the existing pattern in `Plugin::boot()`: repository repair method + own `us_*` option flag (e.g. `us_questions_offering_nullable`), not the version gate.
|
|
|
|
## Tests
|
|
|
|
- Brain Monkey + Mockery, no live WP. All test classes extend `tests/Unit/TestCase.php` (handles `Monkey\setUp/tearDown`, stubs translations/escaping/`checked`/`selected`).
|
|
- Mirror layout: `tests/Unit/<Domain>/` mirrors `src/<Domain>/`.
|
|
- `Functions\when('fn')->alias(fn() => ...)` (never `returnUsing()`); `->justReturn($v)` for constants.
|
|
- Use `when()` not `expect()` for argument-dependent routing.
|
|
- No `\Mockery::type()` inside plain arrays passed to `with()` — use `\Mockery::on()` or `\Mockery::any()`.
|
|
- `$wpdb` mock needs `$mock->prefix = 'wp_'` as a property.
|
|
|
|
## Adding a feature
|
|
|
|
1. Spec first: `docs/features/<feature-name>.md` (data model, API, classes, test paths).
|
|
2. Code in `src/<Domain>/`; templates in `templates/` if needed.
|
|
3. Tests in `tests/Unit/<Domain>/`.
|
|
4. `composer test` must pass (also `composer lint` + `composer cs` before finishing).
|