`SmartenContent` is the runtime placeholder engine that resolves dynamic values
inside content structures using a record context.

## What SmartenContent does

It traverses nested content and replaces `{{...}}` expressions in strings.

This allows dynamic text in CMS blocks, filters, and query-like structures.

## Supported notation styles

`{{property=firstname&object=user&relation=owner&defaultValue=John}}`

Common parameters include:

- `property`: The name of the property or field you want to resolve from the record context (e.g., `firstname`).
- `object`: The object type from which to fetch the property value (e.g., `user`, `candidate`). Controls the lookup context of a related record.
- `relation`: The name of the relation to traverse in order to fetch a related record before resolving the property (e.g., `owner`, `applied_for`).
- `defaultValue`: The value to use if resolution fails or the target property is missing/no record found.
- `relationType` (`primary` or `all`): Determines whether to resolve only the primary related record (`primary`) or aggregate values from all related records (`all`).
- `seperator`: String used to join multiple values when `relationType=all` aggregates several results (note: spelling should usually be `separator`).
- `internal`: If true, fetches the internal/raw value (e.g., underlying ID) instead of the display/transformed value.
- `cypher`: Enables custom Cypher query injection for advanced graph traversals before value resolution. Used for power user graph queries.
- `user`: Context flag for injecting the current user (e.g., for `user=uuid`), allowing placeholders to resolve based on the active session.
- `failLevel`: Determines the error-handling strategy on resolution failure, such as whether to prune just a field, the entire block, or a larger content subtree.


## Relation and object-aware resolution

When relation/object context is provided:

- related records are loaded using the relation
- values can be aggregated (`relationType=all`) with separator joining
- fallback default values are used when no related value resolves


This enables expressive dynamic text beyond simple property interpolation.

## Why fail levels matter

`failLevel` supports higher-level pruning decisions in caller logic (for
example CMS tree pruning in `PageContent` workflows). It helps you decide
whether to:

- remove only a field
- remove a block
- remove a parent subtree


based on where smartening failed.

## Practical usage recommendations

- Prefer explicit `property`, `object`, and `relation` parameters in new
templates.
- Use `defaultValue` for safer public rendering.
- Use `internal=true` only when raw/internal values are actually required.
- Keep placeholders small and deterministic for easier debugging.


## Related reading

- [Save records](/blog/2026-03-25-save-records)