Data contract
Solo uses a fixed namespace for all template variables. Understanding this contract is essential for wiring backend data to the generated templates.
The fm namespace
Every variable in every generated template lives under a fixed namespace with four keys:
| Key | Read by | Contains |
|---|---|---|
| fm.site | Pages, layouts | Site-wide data — name, URL, global config |
| fm.page | Pages, layouts | Page-level data — title, description, canonical |
| fm.data | Pages, layouts | Template-specific data — arrays, collections, content |
| fm.props | Partials only | Component props — passed when including a partial |
In Twig
{# Layout — reads fm.site and fm.page #}
<!doctype html>
<html lang="en">
<head>
<title>{{ fm.page.title }}</title>
<meta name="description" content="{{ fm.page.description }}" />
</head>
<body>
{% block content %}{% endblock %}
</body>
</html> {# Page — reads fm.data #}
{% extends 'layouts/base.html.twig' %}
{% block content %}
{% include 'partials/hero.html.twig' with {
fm: { props: fm.data.hero }
} %}
{% for item in fm.data.products %}
{% include 'partials/card.html.twig' with {
fm: { props: item }
} %}
{% endfor %}
{% endblock %} {# Partial — reads fm.props only #}
<section class="hero">
<h1>{{ fm.props.headline }}</h1>
{% if fm.props.sub %}
<p>{{ fm.props.sub }}</p>
{% endif %}
</section> In PHP
The same contract, accessed as a PHP array:
<?php // Layout ?>
<!doctype html>
<html lang="en">
<head>
<title><?= htmlspecialchars($fm['page']['title']) ?></title>
</head>
<body>
<?php // content included by page ?>
</body>
</html> <?php // Page — you populate $fm, then include partials
$fm['props'] = $fm['data']['hero'];
include __DIR__ . '/../partials/hero.php';
foreach ($fm['data']['products'] as $item) {
$fm['props'] = $item;
include __DIR__ . '/../partials/card.php';
} <?php // Partial — reads $fm['props'] only ?>
<section class="hero">
<h1><?= htmlspecialchars($fm['props']['headline']) ?></h1>
<?php if (!empty($fm['props']['sub'])): ?>
<p><?= htmlspecialchars($fm['props']['sub']) ?></p>
<?php endif; ?>
</section> Your responsibility
Solo generates the template structure. Your backend is responsible for populating the fm namespace from your data source — a CMS, a database, an API, or hardcoded values.
INTEGRATION.md documents exactly what each template expects under each key. The backend developer reads it once and knows what to wire.
Partials never fetch their own data. A partial only renders what it receives via
fm.props. Data fetching always happens in the page or layout, never inside a partial.
Prop types in the contract
Since Solo only accepts literal props, the value types in fm.props are always one of:
stringnumber(float or integer)booleannull— for explicitly absent optional values