Cookbook
Rich-Text Insertion
MIC tokens let rich-text fields reference reusable content without copying that content into the field. The field stores a token. Rendering resolves the token to HTML through a registered resolver.
Use this recipe after a MIC type exists and the content author needs to insert one item into a rich-text field.
Human Path
- Register and load a MIC type.
- Create or identify an item id shaped like
mic_0123456789abcdef. - Insert a token into a rich-text field:
``text [mic-x.my_vendor.catalog-mic_0123456789abcdef] ``
- Save the field.
- Preview or render the page and confirm that the token is replaced by resolver HTML.
The rich-text toolbar can discover registered types from the admin MIC types endpoint when the active rich-text field allows MIC insertion.
AI Path
An AI coding agent can author the resolver locally, add the type to bootstrap.php, and run verification. It can also inspect documentation and source to construct correct token examples.
An installed AI client can inspect loaded MIC type descriptors through /api/v1/content/mics/types when it has content.read and the action is exposed to it. It should not write directly to content storage or bypass the normal content editing actions.
Scopes
Type discovery requires content.read.
Creating or updating rich-text content uses the scopes required by the relevant content action or admin workflow. MIC insertion does not weaken that requirement.
Artifacts
Field artifact:
- a rich-text value containing
[mic-*]
Resolver artifacts:
MicElementResolverInterfaceMicElementRegistry- extension resolver code
Runtime artifacts:
- sanitized rich-text HTML,
- resolved resolver HTML,
- missing marker HTML for matching tokens that cannot resolve.
Token Format
The runtime resolver matches:
[mic-{type}-mic_0123456789abcdef]
For extensions, {type} is fully qualified:
x.{vendor}.{slug}
So an extension token looks like:
[mic-x.my_vendor.catalog-mic_0123456789abcdef]
The id must match mic_[a-f0-9]{16}. Use lowercase hexadecimal characters.
Sanitizer And Resolution Order
Runtime rendering sanitizes rich text first:
myronRichtextSanitize($value)
Then it resolves MIC tokens in the sanitized HTML. This means ordinary operator-authored rich text cannot smuggle unsupported tags through the field.
Resolver output is different. It is returned by trusted local PHP code and treated as pre-blessed HTML. Escape data inside resolver output and keep the returned markup narrow and deterministic.
Context Handling
The renderer currently passes:
| Key | Use |
|---|---|
pageId | Resolve page-specific references or usage tracking. |
fieldKey | Adjust output for the field being rendered. |
channel | Distinguish admin preview from public rendering. |
userScopes | Make conservative decisions based on render scope context. |
Resolvers should work when optional context keys are empty. Future context keys are additive.
Safety Boundary
Do not:
- write MIC tokens directly into the database outside normal content workflows,
- disable
myronRichtextSanitize(), - return user-controlled HTML without escaping,
- use MIC output to inject scripts or admin controls,
- use an AI client to broaden its own scopes or extension grants.
Verification
Run:
php app/tests/verify-content-banks-mic.php
Verify these cases:
- A valid table or extension token resolves to expected HTML.
- A near-miss token such as
[mic-table-bad]stays unchanged. - A matching token with an unknown id renders
myron-mic-missing. - Repeated identical tokens resolve consistently during one render.
/api/v1/content/mics/typesexposes the registered type to a scoped caller.
Failure Modes
| Failure | What it means | Safe response |
|---|---|---|
| Token displays literally | The token did not match the runtime pattern or the field does not resolve MICs. | Fix token shape and verify the field is rich text with MIC support. |
myron-mic-missing appears | Type exists or token matched, but the item id did not resolve. | Check the id, backing storage, and resolver return value. |
| Toolbar does not show a type | The field does not allow that type, discovery failed, or the type is not loaded. | Check the field configuration and /api/v1/content/mics/types. |
| Unsafe markup appears | Resolver returned unescaped or over-broad HTML. | Escape dynamic data and keep resolver output pre-blessed. |
| AI client cannot insert by UI | The admin UI is human/browser mediated. | Use documented content APIs where available and within scope. |