@ai-kits/wp-ag-kit 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (104) hide show
  1. package/ANTIGRAVITY-README.md +47 -0
  2. package/CONTRIBUTING.md +122 -0
  3. package/README.md +135 -0
  4. package/STRUCTURE.md +200 -0
  5. package/agents/wordpress-expert.md +36 -0
  6. package/agents/wp-frontend-expert.md +21 -0
  7. package/bin/antigravity-agent.js +159 -0
  8. package/docs/authoring-guide.md +56 -0
  9. package/docs/compatibility-policy.md +18 -0
  10. package/docs/packaging.md +26 -0
  11. package/docs/principles.md +7 -0
  12. package/docs/skill-set-v1.md +21 -0
  13. package/docs/upstream-sync.md +52 -0
  14. package/package.json +47 -0
  15. package/rules/GEMINI.md +273 -0
  16. package/shared/references/.gitkeep +1 -0
  17. package/shared/references/gutenberg-releases.json +155 -0
  18. package/shared/references/wordpress-core-versions.json +208 -0
  19. package/shared/references/wp-gutenberg-version-map.json +886 -0
  20. package/shared/scripts/ai-generate-updates.mjs +458 -0
  21. package/shared/scripts/scaffold-skill.mjs +62 -0
  22. package/shared/scripts/skillpack-build.mjs +165 -0
  23. package/shared/scripts/skillpack-install.mjs +275 -0
  24. package/shared/scripts/update-upstream-indices.mjs +173 -0
  25. package/skills/wordpress-router/SKILL.md +51 -0
  26. package/skills/wordpress-router/references/decision-tree.md +55 -0
  27. package/skills/wp-abilities-api/SKILL.md +95 -0
  28. package/skills/wp-abilities-api/references/php-registration.md +67 -0
  29. package/skills/wp-abilities-api/references/rest-api.md +13 -0
  30. package/skills/wp-block-development/SKILL.md +174 -0
  31. package/skills/wp-block-development/references/attributes-and-serialization.md +22 -0
  32. package/skills/wp-block-development/references/block-json.md +49 -0
  33. package/skills/wp-block-development/references/creating-new-blocks.md +46 -0
  34. package/skills/wp-block-development/references/debugging.md +36 -0
  35. package/skills/wp-block-development/references/deprecations.md +24 -0
  36. package/skills/wp-block-development/references/dynamic-rendering.md +23 -0
  37. package/skills/wp-block-development/references/inner-blocks.md +25 -0
  38. package/skills/wp-block-development/references/registration.md +30 -0
  39. package/skills/wp-block-development/references/supports-and-wrappers.md +18 -0
  40. package/skills/wp-block-development/references/tooling-and-testing.md +21 -0
  41. package/skills/wp-block-development/scripts/list_blocks.mjs +121 -0
  42. package/skills/wp-block-themes/SKILL.md +116 -0
  43. package/skills/wp-block-themes/references/creating-new-block-theme.md +37 -0
  44. package/skills/wp-block-themes/references/debugging.md +24 -0
  45. package/skills/wp-block-themes/references/patterns.md +18 -0
  46. package/skills/wp-block-themes/references/style-variations.md +14 -0
  47. package/skills/wp-block-themes/references/templates-and-parts.md +16 -0
  48. package/skills/wp-block-themes/references/theme-json.md +59 -0
  49. package/skills/wp-block-themes/scripts/detect_block_themes.mjs +117 -0
  50. package/skills/wp-interactivity-api/SKILL.md +179 -0
  51. package/skills/wp-interactivity-api/references/debugging.md +29 -0
  52. package/skills/wp-interactivity-api/references/directives-quickref.md +30 -0
  53. package/skills/wp-interactivity-api/references/server-side-rendering.md +310 -0
  54. package/skills/wp-performance/SKILL.md +146 -0
  55. package/skills/wp-performance/references/autoload-options.md +24 -0
  56. package/skills/wp-performance/references/cron.md +20 -0
  57. package/skills/wp-performance/references/database.md +20 -0
  58. package/skills/wp-performance/references/http-api.md +15 -0
  59. package/skills/wp-performance/references/measurement.md +21 -0
  60. package/skills/wp-performance/references/object-cache.md +24 -0
  61. package/skills/wp-performance/references/query-monitor-headless.md +38 -0
  62. package/skills/wp-performance/references/server-timing.md +22 -0
  63. package/skills/wp-performance/references/wp-cli-doctor.md +24 -0
  64. package/skills/wp-performance/references/wp-cli-profile.md +32 -0
  65. package/skills/wp-performance/scripts/perf_inspect.mjs +128 -0
  66. package/skills/wp-phpstan/SKILL.md +97 -0
  67. package/skills/wp-phpstan/references/configuration.md +52 -0
  68. package/skills/wp-phpstan/references/third-party-classes.md +76 -0
  69. package/skills/wp-phpstan/references/wordpress-annotations.md +124 -0
  70. package/skills/wp-phpstan/scripts/phpstan_inspect.mjs +263 -0
  71. package/skills/wp-playground/SKILL.md +101 -0
  72. package/skills/wp-playground/references/blueprints.md +36 -0
  73. package/skills/wp-playground/references/cli-commands.md +39 -0
  74. package/skills/wp-playground/references/debugging.md +16 -0
  75. package/skills/wp-plugin-development/SKILL.md +112 -0
  76. package/skills/wp-plugin-development/references/data-and-cron.md +19 -0
  77. package/skills/wp-plugin-development/references/debugging.md +19 -0
  78. package/skills/wp-plugin-development/references/lifecycle.md +33 -0
  79. package/skills/wp-plugin-development/references/security.md +29 -0
  80. package/skills/wp-plugin-development/references/settings-api.md +22 -0
  81. package/skills/wp-plugin-development/references/structure.md +16 -0
  82. package/skills/wp-plugin-development/scripts/detect_plugins.mjs +122 -0
  83. package/skills/wp-project-triage/SKILL.md +38 -0
  84. package/skills/wp-project-triage/references/triage.schema.json +143 -0
  85. package/skills/wp-project-triage/scripts/detect_wp_project.mjs +592 -0
  86. package/skills/wp-rest-api/SKILL.md +114 -0
  87. package/skills/wp-rest-api/references/authentication.md +18 -0
  88. package/skills/wp-rest-api/references/custom-content-types.md +20 -0
  89. package/skills/wp-rest-api/references/discovery-and-params.md +20 -0
  90. package/skills/wp-rest-api/references/responses-and-fields.md +30 -0
  91. package/skills/wp-rest-api/references/routes-and-endpoints.md +36 -0
  92. package/skills/wp-rest-api/references/schema.md +22 -0
  93. package/skills/wp-wpcli-and-ops/SKILL.md +123 -0
  94. package/skills/wp-wpcli-and-ops/references/automation.md +30 -0
  95. package/skills/wp-wpcli-and-ops/references/cron-and-cache.md +23 -0
  96. package/skills/wp-wpcli-and-ops/references/debugging.md +17 -0
  97. package/skills/wp-wpcli-and-ops/references/multisite.md +22 -0
  98. package/skills/wp-wpcli-and-ops/references/packages-and-updates.md +22 -0
  99. package/skills/wp-wpcli-and-ops/references/safety.md +30 -0
  100. package/skills/wp-wpcli-and-ops/references/search-replace.md +40 -0
  101. package/skills/wp-wpcli-and-ops/scripts/wpcli_inspect.mjs +90 -0
  102. package/skills/wpds/SKILL.md +58 -0
  103. package/workflows/create-block.md +27 -0
  104. package/workflows/wp-lint.md +27 -0
@@ -0,0 +1,67 @@
1
+ # PHP registration quick guide
2
+
3
+ Key concepts and entrypoints for the WordPress Abilities API:
4
+
5
+ - Register ability categories and abilities in PHP.
6
+ - Use the Abilities API init hooks to ensure registration occurs at the right lifecycle time.
7
+
8
+ ## Hook order (critical)
9
+
10
+ **Categories must be registered before abilities.** Use the correct hooks:
11
+
12
+ 1. `wp_abilities_api_categories_init` — Register categories here first.
13
+ 2. `wp_abilities_api_init` — Register abilities here (after categories exist).
14
+
15
+ **Warning:** Registering abilities outside `wp_abilities_api_init` triggers `_doing_it_wrong()` and the registration will fail.
16
+
17
+ ```php
18
+ // 1. Register category first
19
+ add_action( 'wp_abilities_api_categories_init', function() {
20
+ wp_register_ability_category( 'my-plugin', [
21
+ 'label' => __( 'My Plugin', 'my-plugin' ),
22
+ ] );
23
+ } );
24
+
25
+ // 2. Then register abilities
26
+ add_action( 'wp_abilities_api_init', function() {
27
+ wp_register_ability( 'my-plugin/get-info', [
28
+ 'label' => __( 'Get Site Info', 'my-plugin' ),
29
+ 'description' => __( 'Returns basic site information.', 'my-plugin' ),
30
+ 'category' => 'my-plugin',
31
+ 'callback' => 'my_plugin_get_info_callback',
32
+ 'meta' => [ 'show_in_rest' => true ],
33
+ ] );
34
+ } );
35
+ ```
36
+
37
+ ## Common primitives
38
+
39
+ - `wp_register_ability_category( $category_id, $args )`
40
+ - `wp_register_ability( $ability_id, $args )`
41
+
42
+ ## Key arguments for `wp_register_ability()`
43
+
44
+ | Argument | Description |
45
+ |----------|-------------|
46
+ | `label` | Human-readable name for UI (e.g., command palette) |
47
+ | `description` | What the ability does |
48
+ | `category` | Category ID (must be registered first) |
49
+ | `callback` | Function that executes the ability |
50
+ | `input_schema` | JSON Schema for expected input (enables validation) |
51
+ | `output_schema` | JSON Schema for returned output |
52
+ | `permission_callback` | Optional function to check if current user can execute |
53
+ | `meta.show_in_rest` | Set `true` to expose via REST API |
54
+ | `meta.readonly` | Set `true` if ability is informational only |
55
+
56
+ ## Recommended patterns
57
+
58
+ - Namespace IDs (e.g. `my-plugin:feature.edit`).
59
+ - Treat IDs as stable API; changing IDs is a breaking change.
60
+ - Use `input_schema` and `output_schema` for validation and to help AI agents understand usage.
61
+ - Always include a `permission_callback` for abilities that modify data.
62
+
63
+ ## References
64
+
65
+ - Abilities API handbook: https://developer.wordpress.org/apis/abilities-api/
66
+ - Dev note: https://make.wordpress.org/core/2025/11/10/abilities-api-in-wordpress-6-9/
67
+
@@ -0,0 +1,13 @@
1
+ # REST API quick guide (`wp-abilities/v1`)
2
+
3
+ The Abilities API exposes endpoints under the REST namespace:
4
+
5
+ - `wp-abilities/v1/abilities`
6
+ - `wp-abilities/v1/categories`
7
+
8
+ Debug checklist:
9
+
10
+ - Confirm the route exists under `wp-json/wp-abilities/v1/...`.
11
+ - Verify the ability/category shows in REST responses.
12
+ - If missing, confirm `meta.show_in_rest` is enabled for that ability.
13
+
@@ -0,0 +1,174 @@
1
+ ---
2
+ name: wp-block-development
3
+ description: "Use when developing WordPress (Gutenberg) blocks: block.json metadata, register_block_type(_from_metadata), attributes/serialization, supports, dynamic rendering (render.php/render_callback), deprecations/migrations, viewScript vs viewScriptModule, and @wordpress/scripts/@wordpress/create-block build and test workflows."
4
+ compatibility: "Targets WordPress 6.9+ (PHP 7.2.24+). Filesystem-based agent with bash + node. Some workflows require WP-CLI."
5
+ ---
6
+
7
+ # WP Block Development
8
+
9
+ ## When to use
10
+
11
+ Use this skill for block work such as:
12
+
13
+ - creating a new block, or updating an existing one
14
+ - changing `block.json` (scripts/styles/supports/attributes/render/viewScriptModule)
15
+ - fixing “block invalid / not saving / attributes not persisting”
16
+ - adding dynamic rendering (`render.php` / `render_callback`)
17
+ - block deprecations and migrations (`deprecated` versions)
18
+ - build tooling for blocks (`@wordpress/scripts`, `@wordpress/create-block`, `wp-env`)
19
+
20
+ ## Inputs required
21
+
22
+ - Repo root and target (plugin vs theme vs full site).
23
+ - The block name/namespace and where it lives (path to `block.json` if known).
24
+ - Target WordPress version range (especially if using modules / `viewScriptModule`).
25
+
26
+ ## Procedure
27
+
28
+ ### 0) Triage and locate blocks
29
+
30
+ 1. Run triage:
31
+ - `node skills/wp-project-triage/scripts/detect_wp_project.mjs`
32
+ 2. List blocks (deterministic scan):
33
+ - `node skills/wp-block-development/scripts/list_blocks.mjs`
34
+ 3. Identify the block root (directory containing `block.json`) you’re changing.
35
+
36
+ If this repo is a full site (`wp-content/` present), be explicit about *which* plugin/theme contains the block.
37
+
38
+ ### 1) Create a new block (if needed)
39
+
40
+ If you are creating a new block, prefer scaffolding rather than hand-rolling structure:
41
+
42
+ - Use `@wordpress/create-block` to scaffold a modern block/plugin setup.
43
+ - If you need Interactivity API from day 1, use the interactive template.
44
+
45
+ Read:
46
+ - `references/creating-new-blocks.md`
47
+
48
+ After scaffolding:
49
+
50
+ 1. Re-run the block list script and confirm the new block root.
51
+ 2. Continue with the remaining steps (model choice, metadata, registration, serialization).
52
+
53
+ ### 2) Ensure apiVersion 3 (WordPress 6.9+)
54
+
55
+ WordPress 6.9 enforces `apiVersion: 3` in the block.json schema. Blocks with apiVersion 2 or lower trigger console warnings when `SCRIPT_DEBUG` is enabled.
56
+
57
+ **Why this matters:**
58
+ - WordPress 7.0 will run the post editor in an iframe regardless of block apiVersion.
59
+ - apiVersion 3 ensures your block works correctly inside the iframed editor (style isolation, viewport units, media queries).
60
+
61
+ **Migration:** Changing from version 2 to 3 is usually as simple as updating the `apiVersion` field in `block.json`. However:
62
+ - Test in a local environment with the iframe editor enabled.
63
+ - Ensure any style handles are included in `block.json` (styles missing from the iframe won't apply).
64
+ - Third-party scripts attached to a specific `window` may have scoping issues.
65
+
66
+ Read:
67
+ - `references/block-json.md` (apiVersion and schema details)
68
+
69
+ ### 3) Pick the right block model
70
+
71
+ - **Static block** (markup saved into post content): implement `save()`; keep attributes serialization stable.
72
+ - **Dynamic block** (server-rendered): use `render` in `block.json` (or `render_callback` in PHP) and keep `save()` minimal or `null`.
73
+ - **Interactive frontend behavior**:
74
+ - Prefer `viewScriptModule` for modern module-based view scripts where supported.
75
+ - If you're working primarily on `data-wp-*` directives or stores, also use `wp-interactivity-api`.
76
+
77
+ ### 4) Update `block.json` safely
78
+
79
+ Make changes in the block’s `block.json`, then confirm registration matches metadata.
80
+
81
+ For field-by-field guidance, read:
82
+ - `references/block-json.md`
83
+
84
+ Common pitfalls:
85
+
86
+ - changing `name` breaks compatibility (treat it as stable API)
87
+ - changing saved markup without adding `deprecated` causes “Invalid block”
88
+ - adding attributes without defining source/serialization correctly causes “attribute not saving”
89
+
90
+ ### 5) Register the block (server-side preferred)
91
+
92
+ Prefer PHP registration using metadata, especially when:
93
+
94
+ - you need dynamic rendering
95
+ - you need translations (`wp_set_script_translations`)
96
+ - you need conditional asset loading
97
+
98
+ Read and apply:
99
+ - `references/registration.md`
100
+
101
+ ### 6) Implement edit/save/render patterns
102
+
103
+ Follow wrapper attribute best practices:
104
+
105
+ - Editor: `useBlockProps()`
106
+ - Static save: `useBlockProps.save()`
107
+ - Dynamic render (PHP): `get_block_wrapper_attributes()`
108
+
109
+ Read:
110
+ - `references/supports-and-wrappers.md`
111
+ - `references/dynamic-rendering.md` (if dynamic)
112
+
113
+ ### 7) Inner blocks (block composition)
114
+
115
+ If your block is a “container” that nests other blocks, treat Inner Blocks as a first-class feature:
116
+
117
+ - Use `useInnerBlocksProps()` to integrate inner blocks with wrapper props.
118
+ - Keep migrations in mind if you change inner markup.
119
+
120
+ Read:
121
+ - `references/inner-blocks.md`
122
+
123
+ ### 8) Attributes and serialization
124
+
125
+ Before changing attributes:
126
+
127
+ - confirm where the attribute value lives (comment delimiter vs HTML vs context)
128
+ - avoid the deprecated `meta` attribute source
129
+
130
+ Read:
131
+ - `references/attributes-and-serialization.md`
132
+
133
+ ### 9) Migrations and deprecations (avoid "Invalid block")
134
+
135
+ If you change saved markup or attributes:
136
+
137
+ 1. Add a `deprecated` entry (newest → oldest).
138
+ 2. Provide `save` for old versions and an optional `migrate` to normalize attributes.
139
+
140
+ Read:
141
+ - `references/deprecations.md`
142
+
143
+ ### 10) Tooling and verification commands
144
+
145
+ Prefer whatever the repo already uses:
146
+
147
+ - `@wordpress/scripts` (common) → run existing npm scripts
148
+ - `wp-env` (common) → use for local WP + E2E
149
+
150
+ Read:
151
+ - `references/tooling-and-testing.md`
152
+
153
+ ## Verification
154
+
155
+ - Block appears in inserter and inserts successfully.
156
+ - Saving + reloading does not create “Invalid block”.
157
+ - Frontend output matches expectations (static: saved markup; dynamic: server output).
158
+ - Assets load where expected (editor vs frontend).
159
+ - Run the repo’s lint/build/tests that triage recommends.
160
+
161
+ ## Failure modes / debugging
162
+
163
+ If something fails, start here:
164
+
165
+ - `references/debugging.md` (common failures + fastest checks)
166
+ - `references/attributes-and-serialization.md` (attributes not saving)
167
+ - `references/deprecations.md` (invalid block after change)
168
+
169
+ ## Escalation
170
+
171
+ If you’re uncertain about upstream behavior/version support, consult canonical docs first:
172
+
173
+ - WordPress Developer Resources (Block Editor Handbook, Theme Handbook, Plugin Handbook)
174
+ - Gutenberg repo docs for bleeding-edge behaviors
@@ -0,0 +1,22 @@
1
+ # Attributes and serialization
2
+
3
+ Use this file when attributes aren’t saving, content becomes “Invalid block”, or you’re changing markup.
4
+
5
+ ## How attributes persist
6
+
7
+ Attributes can come from:
8
+
9
+ - the comment delimiter JSON (common and stable)
10
+ - the block’s saved HTML (from tags/attributes)
11
+ - context
12
+
13
+ Read the canonical guide for supported `source`/`selector`/`attribute` patterns:
14
+
15
+ - https://developer.wordpress.org/block-editor/reference-guides/block-api/block-attributes/
16
+
17
+ ## Common pitfalls
18
+
19
+ - Changing saved HTML without a `deprecated` version breaks existing posts.
20
+ - Using the `meta` attribute source (deprecated) causes long-term pain; avoid it.
21
+ - Choosing brittle selectors leads to attributes “not found” when markup changes slightly.
22
+
@@ -0,0 +1,49 @@
1
+ # `block.json` (metadata) guidance
2
+
3
+ Use this file when you’re editing `block.json` fields or choosing between script/styles fields.
4
+
5
+ ## Practical rules
6
+
7
+ - Treat `name` as stable API (renaming breaks existing content).
8
+ - Prefer adding new functionality without changing saved markup; if markup must change, add a `deprecated` version.
9
+ - Keep assets scoped: editor assets should not ship to frontend unless needed.
10
+
11
+ ## API version + schema
12
+
13
+ **WordPress 6.9+ requires apiVersion 3.** The block.json schema now only validates blocks with `apiVersion: 3`. Older versions (1 or 2) trigger console warnings when `SCRIPT_DEBUG` is enabled.
14
+
15
+ **Why apiVersion 3 matters:**
16
+ - The post editor will be iframed if all registered blocks have apiVersion 3+.
17
+ - WordPress 7.0 will always use the iframe editor regardless of apiVersion.
18
+ - Benefits: style isolation (admin CSS won't affect editor content), correct viewport units (vw, vh), native media queries.
19
+
20
+ **Migration checklist:**
21
+ 1. Update `apiVersion` to `3` in block.json.
22
+ 2. Ensure all style handles are declared in block.json (styles not included won't load in the iframe).
23
+ 3. Test blocks that rely on third-party scripts (window scoping may differ).
24
+ 4. Add a `$schema` to improve editor tooling and validation.
25
+
26
+ References:
27
+
28
+ - Block metadata: https://developer.wordpress.org/block-editor/reference-guides/block-api/block-metadata/
29
+ - Block API versions: https://developer.wordpress.org/block-editor/reference-guides/block-api/block-api-versions/
30
+ - Iframe migration guide: https://developer.wordpress.org/block-editor/reference-guides/block-api/block-api-versions/block-migration-for-iframe-editor-compatibility/
31
+ - Block schema index: https://schemas.wp.org/
32
+
33
+ ## Modern asset fields to know
34
+
35
+ This is not a full schema; it’s a “what matters in practice” list:
36
+
37
+ - `editorScript` / `editorStyle`: editor-only assets.
38
+ - `script` / `style`: shared assets.
39
+ - `viewScript` / `viewStyle`: frontend view assets.
40
+ - `viewScriptModule`: module-based frontend scripts (newer WP).
41
+ - `render`: points to a PHP render file for dynamic blocks (newer WP).
42
+
43
+ ## Helpful upstream references
44
+
45
+ - Block metadata reference (block.json):
46
+ - https://developer.wordpress.org/block-editor/reference-guides/block-api/block-metadata/
47
+ - Block.json schema (editor tooling):
48
+ - https://schemas.wp.org/trunk/block.json
49
+
@@ -0,0 +1,46 @@
1
+ # Creating new blocks (scaffolding)
2
+
3
+ Use this file when you are creating a new block (or a new block plugin) from scratch.
4
+
5
+ ## Preferred path: `@wordpress/create-block`
6
+
7
+ `@wordpress/create-block` scaffolds a modern block setup that tends to track current best practices.
8
+
9
+ Typical options to decide up front:
10
+
11
+ - TypeScript vs JavaScript
12
+ - Static vs dynamic (`render.php` / server rendering)
13
+ - Whether the block should be interactive on the frontend
14
+
15
+ Canonical docs:
16
+
17
+ - https://developer.wordpress.org/block-editor/reference-guides/packages/packages-create-block/
18
+
19
+ ## “Most up-to-date” interactive blocks
20
+
21
+ For a modern interactive block, prefer the official Interactivity API template:
22
+
23
+ - Template: `@wordpress/create-block-interactive-template`
24
+
25
+ This template is designed to integrate:
26
+
27
+ - Interactivity API directives (`data-wp-*`)
28
+ - module-based view scripts (`viewScriptModule`)
29
+ - server rendering (`render.php`)
30
+
31
+ References:
32
+
33
+ - https://developer.wordpress.org/block-editor/reference-guides/packages/packages-create-block/
34
+ - https://make.wordpress.org/core/2024/03/04/a-first-look-at-the-interactivity-api-in-wordpress-6-5/
35
+
36
+ ## Manual fallback (when scaffolding is not available)
37
+
38
+ If you cannot run `create-block` (no Node tooling or restricted network):
39
+
40
+ 1. Create a plugin or theme location that will register the block.
41
+ 2. Create a block folder with a valid `block.json`.
42
+ 3. Register via `register_block_type_from_metadata()` in PHP.
43
+ 4. Add editor JS and (optionally) frontend view assets.
44
+
45
+ Then follow the rest of `wp-block-development` for metadata, registration, and serialization.
46
+
@@ -0,0 +1,36 @@
1
+ # Debugging quick routes
2
+
3
+ ## Block doesn’t appear in inserter
4
+
5
+ - Confirm `block.json` `name` is valid and the block is registered.
6
+ - Confirm build output exists and scripts are enqueued.
7
+ - If using PHP registration, confirm `register_block_type_from_metadata()` runs (wrong hook/file not loaded is common).
8
+
9
+ ## “This block contains unexpected or invalid content”
10
+
11
+ - You changed saved markup or attribute parsing.
12
+ - Add `deprecated` versions and a migration path.
13
+ - Reproduce with an old post containing the previous markup.
14
+
15
+ ## Attributes not saving
16
+
17
+ - Confirm attribute definition matches actual markup.
18
+ - If the value is in delimiter JSON, avoid brittle selectors.
19
+ - Avoid `meta` attribute source (deprecated).
20
+
21
+ ## Console warnings about apiVersion (WordPress 6.9+)
22
+
23
+ If you see "The block 'namespace/block' is registered with API version 2 or lower":
24
+
25
+ - Update `apiVersion` to `3` in block.json.
26
+ - This warning only appears when `SCRIPT_DEBUG` is true.
27
+ - WordPress 7.0 will require apiVersion 3 for proper iframe editor support.
28
+
29
+ ## Styles not applying in editor (apiVersion 3 / iframe)
30
+
31
+ If styles work on frontend but not in the editor:
32
+
33
+ - Ensure style handles are declared in block.json (`editorStyle`, `style`).
34
+ - Styles not included in block.json won't load inside the iframed editor.
35
+ - Check for Dashicons or other dependencies that need explicit inclusion.
36
+
@@ -0,0 +1,24 @@
1
+ # Deprecations and migrations
2
+
3
+ Use this file when you must change saved markup or attribute shapes without breaking existing content.
4
+
5
+ ## `deprecated` basics
6
+
7
+ Block deprecations are handled in JS block registration.
8
+
9
+ - Add older implementations to `deprecated` (newest → oldest).
10
+ - Each deprecated entry can include:
11
+ - `attributes`
12
+ - `supports`
13
+ - `save`
14
+ - `migrate`
15
+
16
+ Upstream reference:
17
+
18
+ - https://developer.wordpress.org/block-editor/reference-guides/block-api/block-deprecation/
19
+
20
+ ## Practical guardrails
21
+
22
+ - Keep fixtures: store example content for each deprecated version.
23
+ - When in doubt, add a migration path rather than silently changing selectors.
24
+
@@ -0,0 +1,23 @@
1
+ # Dynamic blocks (server rendering)
2
+
3
+ Use this file when converting a block to dynamic, or debugging frontend output mismatch.
4
+
5
+ ## Choose the mechanism
6
+
7
+ - Prefer `render` in `block.json` (dynamic render file).
8
+ - Alternative: pass `render_callback` when registering the block in PHP.
9
+
10
+ ## Wrapper attributes
11
+
12
+ In PHP render output, always use:
13
+
14
+ - `get_block_wrapper_attributes()`
15
+
16
+ This preserves support-generated classes/styles.
17
+
18
+ ## Practical checklist
19
+
20
+ - Ensure PHP file exists and is reachable from the block root.
21
+ - Ensure registration runs on every request (not only in admin).
22
+ - Keep `save()` empty or `null` for fully dynamic output, unless you intentionally save fallback markup.
23
+
@@ -0,0 +1,25 @@
1
+ # Inner Blocks (nested blocks)
2
+
3
+ Use this file when your block contains other blocks (container blocks).
4
+
5
+ ## Canonical references
6
+
7
+ - Nested blocks guide: https://developer.wordpress.org/block-editor/how-to-guides/block-tutorial/nested-blocks-inner-blocks/
8
+ - `@wordpress/block-editor` package: https://developer.wordpress.org/block-editor/reference-guides/packages/packages-block-editor/
9
+ - Block supports: https://developer.wordpress.org/block-editor/reference-guides/block-api/block-supports/
10
+
11
+ ## Practical patterns
12
+
13
+ - Editor:
14
+ - Use `useInnerBlocksProps( useBlockProps(), { ... } )` to combine wrapper props with inner blocks.
15
+ - Use templates/allowed blocks only when you have a clear UX reason (too strict is frustrating).
16
+ - Save:
17
+ - Use `useInnerBlocksProps.save( useBlockProps.save(), { ... } )` if you need wrapper props.
18
+ - Output nested content via `<InnerBlocks.Content />` when appropriate.
19
+
20
+ ## Common pitfalls
21
+
22
+ - Only one `InnerBlocks` should exist per block.
23
+ - Changing the wrapper structure that contains inner blocks can invalidate existing content; consider deprecations/migrations.
24
+ - If you need to constrain allowed blocks, prefer doing it intentionally and documenting why.
25
+
@@ -0,0 +1,30 @@
1
+ # Registration patterns (PHP-first)
2
+
3
+ Use this file when you need to register blocks robustly across repo types (plugin/theme/site).
4
+
5
+ ## Prefer metadata registration
6
+
7
+ Prefer:
8
+
9
+ - `register_block_type_from_metadata( $path_to_block_dir, $args = [] )`
10
+
11
+ Why:
12
+
13
+ - keeps metadata authoritative (`block.json`)
14
+ - supports dynamic render (`render`) and other metadata-driven fields
15
+ - enables cleaner asset handling
16
+
17
+ Upstream reference:
18
+
19
+ - https://developer.wordpress.org/reference/functions/register_block_type_from_metadata/
20
+
21
+ ## Where to register
22
+
23
+ - Plugins: register on `init` in the main plugin bootstrap or a dedicated loader.
24
+ - Themes: register on `init` (or `after_setup_theme` if you need theme supports first), but keep it predictable.
25
+
26
+ ## Dynamic render mapping
27
+
28
+ If `block.json` includes `render`, ensure the file exists relative to the block root.
29
+ Inside the render file, use `get_block_wrapper_attributes()` for wrapper attributes.
30
+
@@ -0,0 +1,18 @@
1
+ # Supports and wrapper attributes
2
+
3
+ Use this file when changing `supports` or when your block wrapper styling behaves unexpectedly.
4
+
5
+ ## Required patterns
6
+
7
+ - In `edit()`, use `useBlockProps()`.
8
+ - In `save()`, use `useBlockProps.save()`.
9
+
10
+ If the block is dynamic (PHP render), use:
11
+
12
+ - `get_block_wrapper_attributes()`
13
+
14
+ Upstream reference:
15
+
16
+ - https://developer.wordpress.org/block-editor/reference-guides/block-api/block-supports/
17
+ - https://developer.wordpress.org/reference/functions/get_block_wrapper_attributes/
18
+
@@ -0,0 +1,21 @@
1
+ # Tooling and testing
2
+
3
+ Use this file when deciding what commands to run and what “good verification” looks like.
4
+
5
+ ## Common toolchains
6
+
7
+ - `@wordpress/scripts` for build/lint/test:
8
+ - https://developer.wordpress.org/block-editor/reference-guides/packages/packages-scripts/
9
+ - `@wordpress/create-block` to scaffold new blocks:
10
+ - https://developer.wordpress.org/block-editor/reference-guides/packages/packages-create-block/
11
+ - Interactivity API template for `create-block`:
12
+ - https://www.npmjs.com/package/@wordpress/create-block-interactive-template
13
+ - `@wordpress/env` (wp-env) for local WordPress environments:
14
+ - https://developer.wordpress.org/block-editor/reference-guides/packages/packages-env/
15
+
16
+ ## Verification checklist
17
+
18
+ - `npm run build` (or repo equivalent) succeeds.
19
+ - JS lint passes (repo-specific).
20
+ - E2E tests pass if present.
21
+ - Manual: insert block, save post, reload editor, confirm no “Invalid block”.
@@ -0,0 +1,121 @@
1
+ import fs from "node:fs";
2
+ import path from "node:path";
3
+
4
+ const DEFAULT_IGNORES = new Set([
5
+ ".git",
6
+ "node_modules",
7
+ "vendor",
8
+ "dist",
9
+ "build",
10
+ "coverage",
11
+ ".next",
12
+ ".turbo",
13
+ ]);
14
+
15
+ function statSafe(p) {
16
+ try {
17
+ return fs.statSync(p);
18
+ } catch {
19
+ return null;
20
+ }
21
+ }
22
+
23
+ function existsDir(p) {
24
+ const st = statSafe(p);
25
+ return Boolean(st && st.isDirectory());
26
+ }
27
+
28
+ function readJsonSafe(p) {
29
+ try {
30
+ return JSON.parse(fs.readFileSync(p, "utf8"));
31
+ } catch {
32
+ return null;
33
+ }
34
+ }
35
+
36
+ function findFilesRecursive(repoRoot, predicate, { maxFiles = 6000, maxDepth = 10 } = {}) {
37
+ const results = [];
38
+ const queue = [{ dir: repoRoot, depth: 0 }];
39
+ let visited = 0;
40
+
41
+ while (queue.length > 0) {
42
+ const { dir, depth } = queue.shift();
43
+ if (depth > maxDepth) continue;
44
+
45
+ let entries;
46
+ try {
47
+ entries = fs.readdirSync(dir, { withFileTypes: true });
48
+ } catch {
49
+ continue;
50
+ }
51
+
52
+ for (const ent of entries) {
53
+ const fullPath = path.join(dir, ent.name);
54
+ if (ent.isDirectory()) {
55
+ if (DEFAULT_IGNORES.has(ent.name)) continue;
56
+ queue.push({ dir: fullPath, depth: depth + 1 });
57
+ continue;
58
+ }
59
+ if (!ent.isFile()) continue;
60
+
61
+ visited += 1;
62
+ if (visited > maxFiles) return { results, truncated: true };
63
+ if (predicate(fullPath)) results.push(fullPath);
64
+ }
65
+ }
66
+
67
+ return { results, truncated: false };
68
+ }
69
+
70
+ function summarizeBlockJson(repoRoot, blockJsonPath) {
71
+ const json = readJsonSafe(blockJsonPath);
72
+ if (!json) {
73
+ return {
74
+ path: path.relative(repoRoot, blockJsonPath),
75
+ error: "invalid-json",
76
+ };
77
+ }
78
+
79
+ const rel = path.relative(repoRoot, blockJsonPath);
80
+ const blockRoot = path.dirname(rel);
81
+
82
+ return {
83
+ path: rel,
84
+ blockRoot,
85
+ name: typeof json?.name === "string" ? json.name : null,
86
+ title: typeof json?.title === "string" ? json.title : null,
87
+ apiVersion: typeof json?.apiVersion === "number" ? json.apiVersion : null,
88
+ render: typeof json?.render === "string" ? json.render : null,
89
+ viewScript: json?.viewScript ?? null,
90
+ viewScriptModule: json?.viewScriptModule ?? null,
91
+ editorScript: json?.editorScript ?? null,
92
+ script: json?.script ?? null,
93
+ style: json?.style ?? null,
94
+ editorStyle: json?.editorStyle ?? null,
95
+ attributes: json?.attributes ? Object.keys(json.attributes).slice(0, 50) : [],
96
+ };
97
+ }
98
+
99
+ function main() {
100
+ const repoRoot = process.cwd();
101
+
102
+ const { results: blockJsonFiles, truncated } = findFilesRecursive(repoRoot, (p) => path.basename(p) === "block.json", {
103
+ maxFiles: 8000,
104
+ maxDepth: 12,
105
+ });
106
+
107
+ const blocks = blockJsonFiles.map((p) => summarizeBlockJson(repoRoot, p));
108
+
109
+ const report = {
110
+ tool: { name: "list_blocks", version: "0.1.0" },
111
+ repoRoot,
112
+ truncated,
113
+ count: blocks.length,
114
+ blocks,
115
+ };
116
+
117
+ process.stdout.write(`${JSON.stringify(report, null, 2)}\n`);
118
+ }
119
+
120
+ main();
121
+