Skip to content

Commit 1b246e8

Browse files
committed
docs: extract template extensions and session cache into standalone pages
- Move globals + filters out of plugin-options into features/code-based/template-extensions, with built-in filters table and LiquidJS cross-reference - Move cache setup out of plugin-options into session-cache, clarifying named catbox cache (simple) vs CacheService subclass (full lifecycle override) - Collapse both plugin-options sections to signposts - Add template-extensions to code-based index - Expose session-cache in Reference nav sidebar
1 parent fc2f302 commit 1b246e8

2 files changed

Lines changed: 128 additions & 0 deletions

File tree

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
# Template extensions
2+
3+
The `globals` and `filters` plugin options let you extend the Nunjucks template environment with custom functions and filters. Both are available across all form page templates and in [page templates](../configuration-based/page-templates) (LiquidJS).
4+
5+
## Globals
6+
7+
Globals are functions you call directly in templates, without needing an input value. Register them via the `globals` plugin option:
8+
9+
```js
10+
await server.register({
11+
plugin,
12+
options: {
13+
globals: {
14+
getCurrentYear: () => new Date().getFullYear(),
15+
formatCurrency: (amount) =>
16+
new Intl.NumberFormat('en-GB', {
17+
style: 'currency',
18+
currency: 'GBP'
19+
}).format(amount)
20+
}
21+
}
22+
})
23+
```
24+
25+
Use them in any Nunjucks template:
26+
27+
```njk
28+
<p>Copyright {{ getCurrentYear() }}</p>
29+
<p>Total: {{ formatCurrency(123.45) }}</p>
30+
```
31+
32+
## Filters
33+
34+
Filters transform a value passed on the left side of the `|` operator. Register them via the `filters` plugin option:
35+
36+
```js
37+
const formatter = new Intl.NumberFormat('en-GB')
38+
39+
await server.register({
40+
plugin,
41+
options: {
42+
filters: {
43+
money: (value) => formatter.format(value),
44+
upper: (value) => (typeof value === 'string' ? value.toUpperCase() : value)
45+
}
46+
}
47+
})
48+
```
49+
50+
Use them in any Nunjucks template, or in [LiquidJS page templates](../configuration-based/page-templates):
51+
52+
```njk
53+
<p>{{ amount | money }}</p>
54+
<p>{{ name | upper }}</p>
55+
```
56+
57+
## Built-in filters
58+
59+
forms-engine-plugin registers several filters automatically. These are available in all templates without any configuration:
60+
61+
| Filter | Description |
62+
| ---------- | ------------------------------------------------------------------------------ |
63+
| `markdown` | Renders a Markdown string to HTML |
64+
| `answer` | Returns the user's answer for a given component name (LiquidJS only) |
65+
| `page` | Returns the page definition for a given path (LiquidJS only) |
66+
| `field` | Returns the component definition for a given name (LiquidJS only) |
67+
| `href` | Returns the full page href for a given path (LiquidJS only) |
68+
| `evaluate` | Evaluates a nested LiquidJS template using the current context (LiquidJS only) |
69+
70+
The LiquidJS-only filters are documented in full in [Page templates](../configuration-based/page-templates#built-in-filters).

docs/session-cache.md

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
# Session cache
2+
3+
The plugin stores form answers in a server-side cache keyed by the user's session. By default it uses the [hapi in-memory cache](https://hapi.dev/api/?v=21.4.0#-serveroptionscache), which is fine for development but unsuitable for production — sessions are lost on restart and are not shared across instances.
4+
5+
Configure the cache via the `cache` plugin option.
6+
7+
## Option 1 — named cache (recommended)
8+
9+
For most deployments, register a named [catbox](https://hapi.dev/module/catbox/) cache on the hapi server and pass its name as the `cache` plugin option. The plugin handles all cache reads and writes internally — you only need to supply the backing store.
10+
11+
```js
12+
import { Engine as CatboxRedis } from '@hapi/catbox-redis'
13+
14+
const server = new Hapi.Server({
15+
cache: [
16+
{
17+
name: 'session',
18+
provider: {
19+
constructor: CatboxRedis,
20+
options: {
21+
host: process.env.REDIS_HOST,
22+
port: 6379
23+
}
24+
}
25+
}
26+
]
27+
})
28+
29+
await server.register({
30+
plugin,
31+
options: {
32+
cache: 'session',
33+
// ...
34+
}
35+
})
36+
```
37+
38+
Any catbox adapter works — Redis (`@hapi/catbox-redis`), Memcached (`@hapi/catbox-memcached`), or a custom implementation.
39+
40+
## Option 2 — CacheService instance
41+
42+
Use this when you need to subclass `CacheService` to customise its behaviour. The class exposes the full state lifecycle as overridable methods — key construction, TTL, state reads and writes, confirmation state, flash messages, and component state resets — so you can override whichever parts your use case requires. Pass your subclass instance directly:
43+
44+
```js
45+
import { CacheService } from '@defra/forms-engine-plugin/cache-service.js'
46+
47+
const cacheService = new CacheService({ server, cacheName: 'session' })
48+
49+
await server.register({
50+
plugin,
51+
options: {
52+
cache: cacheService,
53+
// ...
54+
}
55+
})
56+
```
57+
58+
`CacheService` accepts `{ server, cacheName }` where `cacheName` must match a cache already registered on the hapi server. Omitting `cacheName` falls back to the default in-memory cache with a warning logged.

0 commit comments

Comments
 (0)