Non‑negotiable principles that every specification, plan, task, and implementation MUST follow. Words MUST/SHOULD/MAY are to be interpreted per RFC 2119 semantics.
- This constitution governs WordPress plugins, themes, blocks, and headless integrations developed in this repository.
- It constrains the
/speckit.specify,/speckit.plan,/speckit.tasks, and/speckit.implementoutputs. When in doubt, follow this constitution over any generated content. - Out of scope: WordPress Core contributions (different standards) unless explicitly noted.
- Security first: No unauthenticated or un‑authorized write operations. Sanitize on input, validate, and escape on output. All state‑changing actions MUST validate a nonce and capability.
- Performance: Enqueue assets only where needed; avoid global front‑end bloat. Database calls are prepared/parameterized and O(n) per request is avoided.
- Accessibility: Deliver WCAG 2.1 AA. All interactive UI is keyboard‑navigable, labeled, and announces dynamic changes.
- i18n & l10n: All user‑facing strings are translatable; block and script translations are wired.
- Testability: Every feature ships with unit tests and at least one integration/e2e path for the happy‑flow.
- Backward compatibility: Respect semantic versioning and stable public APIs of the plugin/theme. Provide migrations and clean uninstall.
- Observability: Fail loud in logs, fail soft in UX. No fatal errors—guard external calls, feature‑flag risky paths.
- WordPress: Target latest stable; minimum supported: 6.6.
- PHP: 8.1+ (strict types where practical,
declare(strict_types=1)in project PHP entry points). - Node: 20+; Package manager: npm or pnpm (pick one per repo).
- Build:
@wordpress/scriptsfor blocks, webpack/Vite only if justified. - Datastores: WordPress options/table schema, or remote APIs—no ad‑hoc SQL without model/migration.
- Prefer plugin‑first architecture for features; themes contain presentation only. New UI pieces SHOULD be Gutenberg blocks (or block‑powered UIs) with a
block.jsonmanifest. - Follow capability‑based access checks. Never trust
is_admin()for authorization. - REST routes live under
/wp-json/<namespace>/<version>/*with an explicitpermission_callback. - Encapsulate DB access in repositories/services. Never mix rendering with data access.
- Use dependency injection for testability; avoid globals except WordPress‑provided ones.
- PHP: Enforce WordPress Coding Standards (WPCS) via PHPCS. Project ships
phpcs.xmlwithWordPress-Core,WordPress-Extra,WordPress-Docs(and vendor‑specific extensions as needed). Use Composer scripts to run. - JS/TS: Use
@wordpress/eslint-pluginrecommended config + TypeScript where practical. Use Prettier for formatting (no stylistic overrides unless justified). - CSS/Sass: Naming is BEM‑ish or CSS Modules. Use logical properties and prefers‑reduced‑motion fallbacks.
- Docs: PHPDoc/JSDoc required for public APIs/filters/actions. Each hook documents parameters and return types.
- Capabilities: Validate with
current_user_can( 'cap' )(or mapped caps) for admin/REST mutations. - Nonces: Required for all state changes in wp‑admin and front‑end forms/AJAX.
- Sanitization:
sanitize_text_field,sanitize_email,absint,wp_kses( …, allowed_html ), etc., on input. - Escaping:
esc_html,esc_attr,esc_url,wp_kses_poston output. Escaping happens as late as possible. - DB: Use
$wpdb->prepare()for raw SQL, otherwise core APIs. No string interpolation in queries. - REST: Always set
permission_callback. Never__return_truefor write routes. Validate/sanitizeargs. - Files: No
eval, no arbitrary file writes/reads outside uploads. Respect uploads MIME validation.
- Custom tables require a spec and a migration plan using
dbDeltaor a dedicated migration runner. Version schema viaoptionkey. autoloadoptions kept minimal; large data MUST NOT be autoloaded.- Uninstall: Provide
uninstall.phpto remove options/custom tables/transients when safe.
- REST responses are versioned, typed (documented shapes), and stable. Breaking changes require a new version path.
- Use non‑ambiguous HTTP statuses; errors return
WP_Errorwith a code andstatus. - For headless/SSR, document CORS and authentication flows (cookies, Application Passwords, OAuth, or JWT).
- Each block defines
block.json, usesregisterBlockType, hasedit&save(orrender_callbackfor dynamic blocks), and a stablename. - Scripts/styles are enqueued via
block.jsonorwp_enqueue_*with dependency extraction. No global bundles on every page. - Reusable components SHOULD use
@wordpress/componentsand@wordpress/dataselectors. - Provide server‑side rendering only when necessary; prefer static markup with hydration for performance.
- Wrap all user‑visible strings in i18n functions (
__,_x,_n, etc.). Provide a consistent text domain. - Load text domain, generate POT/PO/MO files, and call
wp_set_script_translationsfor block scripts. - Follow i18n writing guidelines (whole sentences, placeholders, no stray whitespace).
- Keyboard access, focus management, and visible focus states are mandatory.
- Use semantic HTML first; ARIA only to enhance, not replace semantics.
- Announce live region updates with
@wordpress/a11ywhen appropriate. - Color contrast meets AA.
- Enqueue scope: Load assets only on screens that need them. Split bundles by screen/block.
- Avoid admin‑ajax for APIs—prefer REST. Cache expensive operations (transients or persistent object cache).
- Images and icons: prefer SVG (sanitized) or sprite sheets. Inline critical CSS for above‑the‑fold when necessary.
- Unit/Integration: PHPUnit with the WordPress test suite. Mock external services.
- E2E: Playwright (or
@wordpress/e2e-testsif justified) against a disposable environment. - JS: Jest + React Testing Library for block/editor logic.
- CI must run
phpcs,eslint, tests, and build verification on each PR.
- Source in
/src; built assets in/build(ignored in VCS unless publishing to wp.org). - Readme complies with the Plugin Directory spec (if applicable). SemVer for releases.
- Tag Git, update changelog, bump versions in plugin headers and
block.jsonas needed.
- Do not throw fatal errors in production. Convert exceptions to
WP_Erroror admin notices as appropriate. - Instrument key flows with
error_log(dev only) or configured logger; never leak secrets.
- Composer and npm scripts:
composer phpcs,composer phpcbf,composer testnpm run lint:js,npm run build,npm run test
- Pre‑commit hooks run linters and tests.
- This file MUST be kept in
.specify/memory/constitution.mdand versioned. - Changes require PR + approval by tech lead and QA. Breaking policy changes get a minor version bump in the constitution header.
- Specs/plans/tasks that contradict this document must be rewritten before implementation.
- When generating code, the assistant MUST:
- Adhere to WPCS/ESLint rules and fix lint errors before suggesting diffs.
- Use proper WordPress nonces, capabilities, escaping/sanitization, and REST
permission_callback. - Prefer block‑based UIs with
block.json; no enqueueing global assets unnecessarily. - Add i18n wrappers and text domain.
- Propose tests (PHPUnit/Jest/Playwright) with the feature.
- The assistant MUST NOT:
- Create routes/actions without auth checks.
- Introduce heavy dependencies when core APIs suffice.
- Bypass build tooling defined above.
- Security: capabilities, nonces, sanitization, escaping
- Performance: scoped enqueues, no needless queries
- Accessibility: keyboard, labels, contrast, announcements
- i18n: strings wrapped, domain set, POT updated
- Tests: unit + integration/e2e where applicable
- Linting: PHPCS (WPCS) & ESLint/Prettier pass in CI
- Docs: hooks documented, public APIs explained
{
"scripts": {
"build": "wp-scripts build",
"start": "wp-scripts start",
"lint:js": "eslint --ext .js,.jsx,.ts,.tsx src",
"test": "jest",
"e2e": "playwright test"
}
}<?xml version="1.0"?>
<ruleset name="Project WPCS">
<description>WordPress Coding Standards for this project.</description>
<rule ref="WordPress-Core"/>
<rule ref="WordPress-Extra"/>
<rule ref="WordPress-Docs"/>
<config name="testVersion" value="8.1-"/>
</ruleset>Status: v1.0 of this constitution. Update via PRs only.