Guidance for AI coding agents working on the Perform WordPress plugin.
- Plugin:
Perform - Current public line:
1.5.1 - Active release branch in this workspace:
release/1.6.0 - Stack:
- PHP (WordPress plugin, PSR-4 autoload
Perform\\->src/) - JS/CSS via
@wordpress/scripts+ webpack output inassets/dist - Freemius SDK via Composer
- PHP (WordPress plugin, PSR-4 autoload
- Do not rename existing option/meta keys used by released versions.
- Preserve backward compatibility with legacy settings sections:
perform_commonperform_sslperform_cdnperform_woocommerceperform_advanced
perform_settingsis the standard canonical settings store for Perform.- Add/maintain an automatic migration routine that migrates legacy settings into
perform_settingswhenperform_settingsdoes not exist. - Keep runtime reads tolerant of both consolidated and legacy settings during migration windows.
- Do not change public hook names unless absolutely required; if required, add compatibility shims.
- Bootstrap:
perform.php - Core plugin wiring:
src/Plugin.php - Admin (settings UI + ajax save):
src/Admin/** - Frontend/shared hooks:
src/Includes/** - Feature modules:
src/Modules/**- Module registry:
src/Modules/Registry.php - Module loader:
src/Modules/Loader.php - Module contract:
src/Modules/ModuleInterface.php
- Module registry:
- Assets source:
assets/src/** - Built assets:
assets/dist/** - Uninstall logic:
uninstall.php
- New modules must implement
Perform\Modules\ModuleInterface. - Register modules only through
src/Modules/Registry.php. - Loader enforces module interface and lifecycle:
should_load(): boolregister(): void
- If a module needs settings injection, extend
AbstractModuleand useget_setting().
- Frontend-only behavior must be scoped carefully:
- avoid running on admin, ajax, cron, rest, cli unless intended
- Redirect logic:
- never run unguarded in constructor/register; attach to request hook
- avoid redirect loops and skip if
headers_sent()
- Output-buffer based rewrites are expensive:
- avoid in non-HTML contexts
- keep regex operations minimal and guarded
- All settings persistence must enforce:
- capability checks
- nonce validation
- per-field sanitization
- Do not enqueue heavy admin assets globally.
- Scope admin scripts/styles to plugin screens only.
- Avoid repeated expensive lookups in hot paths; cache per-request where practical.
- Keep module registration lightweight; no expensive work during bootstrap.
- Prefer WordPress Design System components for plugin UI wherever possible.
- Build settings/admin UI using React with
@wordpress/components,@wordpress/element, and related WordPress packages. - Avoid custom UI primitives when equivalent WP Design System components exist.
- Node runtime:
- Use Node.js 24.x (
.nvmrcand.node-versionare authoritative for this release line)
- Use Node.js 24.x (
- JS/CSS dev build:
npm run start
- JS/CSS prod build:
npm run build
- JS/CSS lint:
npm run lint
- PHP code style:
composer check-cs
- PHP lint:
composer lint
- PHPStan:
composer phpstan
- PHPUnit:
composer test
- Playwright smoke tests:
npm run test:e2e:ci
- Minimum for PHP changes:
php -lon changed PHP filescomposer lintwhen feasible
- For module/settings changes:
- verify module still loads via
Registry+Loader - verify option compatibility with existing keys
- verify module still loads via
- For admin UI/settings changes:
- verify save flow still works via
perform_save_settingsajax - verify the settings page script path matches built artifact names
- verify save flow still works via
- For tooling/CI changes:
- preserve the Node 24 Active LTS policy unless the release plan changes
- keep GitHub Actions on maintained action versions
- run or document any unrun Composer, npm, PHPUnit, and Playwright validation gates
- GitHub workflows include:
CodeStyle(PHPCS)Lint(parallel-lint)Run PHPStanSecurity- release/pre-release packaging and deployment
- Keep changes aligned with existing workflow assumptions; avoid introducing new required secrets/tools without updating workflows.
- Keep release-safe changes on
release/*branches. - Do not silently change plugin version constants/headers unless part of an explicit release task.
- If behavior changes in public-facing optimization modules, prefer additive compatibility switches.
- Follow WPCS conventions configured in
phpcs.xml.dist. - Escape output on render, sanitize input on save.
- Prefer
__(),esc_html__(), etc. with text domainperform.
- Make small, logical commits.
- Commit message style:
- imperative, scoped, and outcome-oriented
- example:
Harden SSL and CDN module runtime scope
- Do not include unrelated formatting-only churn in functional commits.
- Default to preserving runtime behavior for existing installs.
- Prefer compatibility over cleanup if both cannot be done safely in one patch.
- Document assumptions in PR/commit notes.