Adding a feature
A new feature of the framework touches the same places every time: the attribute or class consumers use, the build, the manifest, the run time, the tests in two repositories, the benchmark and the documentation. This checklist goes through them in order. Architecture explains the chain behind it; src/Hook/ is the smallest complete example.
Before you start
- Check the design decisions: is the idea among the rejected alternatives, and does it fit the principles?
- Verify the WordPress behavior you build on in the source of WordPress (the
wordpressimage of wp-test-env has it in/usr/src/wordpress) and note file and line. The same for Twig, Composer, Strauss or a browser API. - Decide the API from the consumer's side first: names, required and optional arguments, enums instead of strings, what is a build error.
The checklist
- Attribute or API class in the directory of its area (
src/<Area>/):final readonly, public promoted properties for an attribute, a doc comment for the class and every parameter,@api <group>if consumers use it (the groups are intools/ApiReference/Generator.php),@internalon members only the framework uses. - Collector (
<Area>Collector): reads the attribute in the build, checks everything that can be checked and returns plain data. Every mistake is an error message with class, method and parameter. Shared checks of entry points are insrc/Manifest/EntryPointInspector.php. - Definition (
<Area>Definition): the PHPStan array shapes of that data. - Manifest: call the collector in
ManifestBuilder, add the data to the manifest and raiseManifest::FORMAT. If the build reads a new kind of input (a file type, a directory), make it part of the signature or listing hash of the development cache, or changes will not rebuild the manifest. - Registrar (
<Area>Registrar): registers the feature from the manifest at run time, called fromInstance. No reflection, no file checks, no writes into the consumer; services resolved only when they are needed; errors thrown withWP_DEBUGand logged otherwise. - Unit tests in
tests/Unit/<Area>/: the collector with valid fixtures (tests/Fixtures/<Area>Valid/) and a fixture for every build error (<Area>Broken/, with@phpstan-ignoreand the reason), the registrar against the WordPress doubles. Add missing doubles totests/Stubs/with the real signatures. - JavaScript, if the editor or the front end is involved: the runtime modules in
assets/, Vitest tests next to them, the declarations intypes/if consumers import something new. - Test consumer: use the feature in theme-dev-test (and in plugin-dev-test or theme-dev-test-child if plugins or child themes behave differently), with a browser spec, a render case, a WP-CLI or a lifecycle check – whatever proves it in WordPress. List new specs in its README; update the expected output of
composer build-manifestthere. - Benchmark: if the feature runs on requests, add a scenario to theme-bench, so the next benchmark (run on request) measures it;
bin/bench --coverageshows that the scenario reaches the code. - Texts for editors (see Conventions): new texts in PHP or the scripts with the text domain
wp-app-framework, thenphp tools/translationsand the German translation; new texts consumers write in attributes are translated where they reach WordPress or the editor (I18n\Translator) and listed bywp-app-framework pot(I18n\AttributeTexts). - Documentation: the guide page of the area (or a new one, linked in
docs/rspress.config.mjs), with what it is for, how it works, an example and the rules; Upgrading if anything a consumer relies on changes; these development pages if conventions, tests or pipelines change. - Checks before the commit:
composer lint,npm run lint, the documentation build (it fails on missing doc comments of the API), and lint and build of the changed consumers. Before the push, the development build with the browser suites (see Testing).
Changing an existing feature
The same list applies to the parts you touch. In addition:
- A change of the consumer API before 1.0 is allowed only with a section in Upgrading: what changed, why, and what consumers do. From 1.0 on, the API only grows within a major version.
- The filters and actions between instances (
wp_app_framework/api/{slug},wp_app_framework/template/{slug},wp_app_framework/init/{slug},wp_app_framework/namespace/{namespace}) may only be extended, never changed, because instances of different framework versions use them together. - Changing behavior also changes the doc comments, the guide and the tests in the consumers in the same commit.