Browse topics
On this page
- Actions (Fire-and-Forget)
- Firing an action
- Listening for an action
- Filters (Data Transformation)
- Registering a filter handler
- Applying a filter
- Priority
- API Reference
- rp.hooks.doAction(hookName, payload?)
- rp.hooks.onAction(hookName, callback)
- rp.hooks.addFilter(hookName, handler, opts?)
- rp.hooks.applyFilter(hookName, value)
- rp.hooks.removeFilter(hookName)
- Manifest Configuration
- Naming Convention
- Example: Plugin System
- Backend Limitations
Hooks API
WordPress-style actions and filters for inter-resource communication.
Hooks API
Hooks let resources communicate with each other using the WordPress action/filter pattern. Resources can fire actions (broadcast events) and apply filters (transform data through a chain of handlers).
Capability required: hooks:provide (to register handlers and fire actions) and/or hooks:consume (to listen for actions and apply filters)
Actions (Fire-and-Forget)
Actions broadcast a payload to all listeners. The sender doesn’t wait for a response.
Firing an action
// Resource A (capability: hooks:provide)
await rp.hooks.doAction("weather:data_updated", { temp: 72, city: "Seoul" });
Listening for an action
// Resource B (capability: hooks:consume)
const unsubscribe = rp.hooks.onAction("weather:data_updated", (payload) => {
console.log("Weather changed:", payload);
// { temp: 72, city: "Seoul" }
});
// Later: stop listening
unsubscribe();
Filters (Data Transformation)
Filters pass a value through a chain of handlers. Each handler can transform the value before passing it to the next.
Registering a filter handler
// Resource A (capability: hooks:provide)
rp.hooks.addFilter("weather:format_temp", (value) => {
// Convert Fahrenheit to Celsius
return { ...value, tempC: Math.round((value.tempF - 32) * 5 / 9) };
}, { priority: 10 });
Applying a filter
// Resource B (capability: hooks:consume)
const result = await rp.hooks.applyFilter("weather:format_temp", { tempF: 72 });
console.log(result); // { tempF: 72, tempC: 22 }
Priority
Multiple handlers on the same filter run in priority order (lower number first). Default priority is 10.
// Runs first (priority 5)
rp.hooks.addFilter("myapp:process_data", handler1, { priority: 5 });
// Runs second (priority 10, default)
rp.hooks.addFilter("myapp:process_data", handler2);
// Runs third (priority 20)
rp.hooks.addFilter("myapp:process_data", handler3, { priority: 20 });
Each handler receives the return value of the previous handler.
API Reference
rp.hooks.doAction(hookName, payload?)
Fire an action to all registered listeners.
| Parameter | Type | Description |
|---|---|---|
hookName | string | Hook name (e.g., "weather:data_updated") |
payload | unknown (optional) | Data to broadcast |
rp.hooks.onAction(hookName, callback)
Listen for an action. Returns an unsubscribe function.
| Parameter | Type | Description |
|---|---|---|
hookName | string | Hook name to listen for |
callback | (payload: unknown) => void | Called when the action fires |
| Returns | () => void | Call to unsubscribe |
rp.hooks.addFilter(hookName, handler, opts?)
Register a filter handler.
| Parameter | Type | Description |
|---|---|---|
hookName | string | Filter name |
handler | (value: unknown) => unknown | Transform function (can be async) |
opts.priority | number (optional) | Execution order (default: 10, lower runs first) |
rp.hooks.applyFilter(hookName, value)
Run a value through all registered filter handlers.
| Parameter | Type | Description |
|---|---|---|
hookName | string | Filter name |
value | unknown | Initial value to transform |
| Returns | Promise<unknown> | Transformed value |
If no handlers are registered, the original value is returned unchanged.
rp.hooks.removeFilter(hookName)
Remove your resource’s filter handler for a hook.
| Parameter | Type | Description |
|---|---|---|
hookName | string | Filter name to unregister from |
Manifest Configuration
Declare which hooks your resource provides and consumes:
{
"capabilities": [
"hooks:provide",
"hooks:consume"
]
}
Use hooks:provide if your resource fires actions or registers filter handlers.
Use hooks:consume if your resource listens for actions or applies filters.
Most resources that use hooks will need both.
Naming Convention
Hook names use a namespace prefix followed by a colon:
{namespace}:{event_name}
Examples:
weather:data_updated— weather resource fires when data changesanalytics:page_view— analytics resource fires on page viewscms:post_published— CMS resource fires when content is published
Use your resource’s name or ID as the namespace to avoid collisions.
Example: Plugin System
// Theme resource provides a filter for page rendering
rp.hooks.addFilter("theme:render_header", (html) => {
return html + '<div class="announcement-bar">Sale today!</div>';
});
// Main app applies the filter
const headerHtml = await rp.hooks.applyFilter("theme:render_header", "<header>...</header>");
Backend Limitations
From the Node.js backend, doAction, applyFilter, and removeFilter work normally. However, onAction and addFilter are not yet available from backends — use the frontend SDK for receiving hooks.