Frontmatter

Twig adapter

The Twig adapter generates .twig templates for Symfony, Drupal, Craft CMS, and any Twig-capable backend.

Usage

frontmatter solo:build --adapter twig
frontmatter solo:build --adapter twig --out ./render-pack

Mapping rules

The Astro-to-Twig conversion follows a small set of consistent rules:

Required props

{# Astro: headline: string #}
{{ fm.props.headline }}

Optional props

{# Astro: sub?: string #}
{% if fm.props.sub %}
  <p>{{ fm.props.sub }}</p>
{% endif %}

Astro slot → Twig block

{# Astro: <slot /> in a layout #}
{% block content %}{% endblock %}

Conditional rendering

{# Astro: {condition && <el />} #}
{% if fm.props.condition %}<el />{% endif %}

Array iteration

{# Astro: {items.map(item => <Card />)} #}
{% for item in fm.data.items %}
  {% include 'partials/card.twig' with { fm: { props: item } } %}
{% endfor %}

Page extends layout

{% extends 'layouts/base.twig' %}

{% block content %}
  {% include 'partials/hero.twig' with {
    fm: { props: fm.data.hero }
  } %}
{% endblock %}

Output structure

output/
├─ pages/
│  └─ index.twig
├─ layouts/
│  └─ base.twig
├─ partials/
│  ├─ hero.twig
│  └─ section.twig
├─ manifest.json
├─ INTEGRATION.md
└─ frontmatter.build.json

Symfony integration

Copy the output to your Symfony templates/ directory. Your controller passes the fm array:

return $this->render('pages/index.twig', [
  'fm' => [
    'page' => ['title' => 'Home'],
    'data' => [
      'hero' => [
        'headline' => 'Welcome',
        'sub'      => 'We build things.',
      ],
    ],
  ],
]);

Drupal integration

The .twig files work with Drupal's theme layer. Adapt the include paths to Drupal's template naming conventions and map fm.props to Drupal's template variables.

Strict mode

Add --strict to treat framework component warnings (W410–W412) as blocking errors:

frontmatter solo:build --adapter twig --strict

On this page