VOOZH about

URL: https://deepwiki.com/calevans/staticforge/6-template-system

⇱ Template System | calevans/staticforge | DeepWiki


Loading...
Last indexed: 11 February 2026 (5f6a2a)
Menu

Template System

Purpose and Scope

This document describes StaticForge's Twig-based template system, which transforms processed content into HTML pages. The template system handles template selection, variable injection, Twig inheritance, and asset management.

For information about content processing before templates are applied, see Content Management. For details about how features contribute template variables, see Feature System.

The template system operates during the RENDER event and is invoked by renderer features (MarkdownRenderer, HtmlRenderer) after content transformation but before file writing.


Template Architecture

Template Resolution Pipeline

StaticForge resolves which template to apply using a three-tier priority system:


Sources: src/Services/TemplateRenderer.php42-72 src/Core/BaseRendererFeature.php33-39

Template Resolution Logic

The resolution algorithm is implemented in TemplateRenderer::render():

PrioritySourceExampleCode Location
1 (Highest)Frontmatter template fieldtemplate: docsdocs.html.twigsrc/Services/TemplateRenderer.php46-48
2Category template mappingcategory: blog + category_templates[blog] = blog-postsrc/Services/TemplateRenderer.php49-67
3 (Fallback)Default templateNo metadata → base.html.twigsrc/Services/TemplateRenderer.php43 src/Core/BaseRendererFeature.php17

The category_templates mapping is stored in the Container by the Categories feature and maps category slugs to template names.

Sources: src/Services/TemplateRenderer.php42-72

Template Directory Structure

Templates are organized within the active template directory:

templates/
└── staticforce/ # Active template (from TEMPLATE env var)
 ├── base.html.twig # Master layout
 ├── docs.html.twig # Documentation layout
 ├── index.html.twig # Landing page
 ├── standard_page.html.twig
 ├── category.html.twig
 ├── _footer.html.twig # Partial (underscore prefix)
 ├── _form.html.twig
 ├── _chapter_nav.html.twig
 └── contact_us.html.twig

The active template is determined by TEMPLATE_DIR (base path) and TEMPLATE (subdirectory name) configuration variables. The FilesystemLoader is configured to search both the active template directory and the templates root:

Sources: src/Services/TemplateRenderer.php76-78

Twig Environment Configuration


Configuration Details:

  • debug: true: Enables Twig debugging extensions
  • strict_variables: false: Undefined variables render as empty instead of throwing errors
  • autoescape: 'html': Automatic HTML escaping for security (use |raw filter to bypass)
  • cache: false: Disables template compilation cache for development

Sources: src/Services/TemplateRenderer.php79-84

TemplateRenderer Service

The TemplateRenderer class is the central service for template operations:


Primary Methods:

  • render(): Main rendering pipeline - resolves template, builds variables, renders Twig, injects assets
  • renderTemplate(): Direct template rendering for partials/shortcodes (bypasses resolution logic)
  • injectAssets(): Fallback asset injection if template doesn't include asset variables
  • applyBasicTemplate(): Fallback HTML template if Twig rendering fails

Sources: src/Services/TemplateRenderer.php14-278

Renderer Feature Integration

Both MarkdownRenderer and HtmlRenderer instantiate TemplateRenderer during their register() method:

MarkdownRenderer Setup:


Sources: src/Features/MarkdownRenderer/Feature.php40-62 src/Features/HtmlRenderer/Feature.php40-53


Template Inheritance

Twig Block System

StaticForge templates use Twig's {% extends %} and {% block %} directives to create a master layout with overrideable sections:


Sources: templates/staticforce/base.html.twig1-124

Base Template Structure

The base.html.twig master layout defines the HTML skeleton and standard blocks:

Block NamePurposeDefault ContentLocation
titlePage <title> tag{{ title }} | {{ site_name }}templates/staticforce/base.html.twig44
extra_headAdditional <head> contentEmptytemplates/staticforce/base.html.twig63
search_barSearch input UISearch form HTMLtemplates/staticforce/base.html.twig79-84
bodyMain page structureSidebar + content wrappertemplates/staticforce/base.html.twig89-103
contentContent area inside body{{ content|raw }}templates/staticforce/base.html.twig98-100
search_scriptsSearch initializationMiniSearch loadertemplates/staticforce/base.html.twig108-120
scriptsAdditional footer scriptsEmptytemplates/staticforce/base.html.twig121

Sources: templates/staticforce/base.html.twig1-124

Child Template Patterns

Documentation Template (docs.html.twig)

Implements a 3-column layout for technical documentation:


Key Overrides:

  • extra_head: Injects docs.css, chapter-nav.css, toc.css stylesheets
  • body: Replaces default sidebar/content with 3-column grid structure

Sources: templates/staticforce/docs.html.twig1-88

Landing Page Template (index.html.twig)

Minimal override that removes search functionality and uses full-width layout:

Block Overrides:

  • search_bar: Emptied to remove search input from navbar
  • search_scripts: Emptied to skip search initialization
  • extra_head: Adds home.css stylesheet
  • body: Replaced with {{ content|raw }} only (no sidebars)

This allows the homepage content file to provide complete custom HTML structure.

Sources: templates/staticforce/index.html.twig1-29

Standard Page Template (standard_page.html.twig)

Single-column centered layout for general content:


Sources: templates/staticforce/standard_page.html.twig1-42

Category Template (category.html.twig)

Lists all files in a category with sidebar navigation:

Structure:

  • Left sidebar: Manual menu iteration using features.MenuBuilder.files[1] (demonstrates raw menu data access)
  • Content area: Page title, content, then category file listings with metadata

Sources: templates/staticforce/category.html.twig1-100

Partial Templates (Includes)

Partial templates (prefixed with _) are reusable components included via {% include %}:

PartialPurposeKey VariablesUsed By
_footer.html.twigSite footermenu_footer, site_nameAll templates
_chapter_nav.html.twigPrev/next navigationfeatures.ChapterNav.pagesdocs.html.twig
_form.html.twigGeneric form rendererfields, endpoint, challenge_urlShortcode system
contact_us.html.twigContact form variantSame as _form.html.twig + custom stylingShortcode system

Footer Partial Example:


Sources: templates/staticforce/_footer.html.twig1-36 templates/staticforce/_chapter_nav.html.twig1-22 templates/staticforce/_form.html.twig1-86


Template Variables

Variable Assembly Pipeline

Template variables are assembled by TemplateVariableBuilder::build() from multiple sources:


Sources: src/Services/TemplateVariableBuilder.php (referenced but implementation details in TemplateRenderer)

Core Variables

These variables are available in all templates:

VariableTypeSourceDescriptionCode Reference
site_namestringsite_config['site']['name'] or SITE_NAME env varSite name for brandingtemplates/staticforce/base.html.twig44
site_base_urlstringSITE_BASE_URL Container variableFull base URL with trailing slashtemplates/staticforce/base.html.twig69
titlestringContent frontmatter title fieldPage titletemplates/staticforce/base.html.twig44
descriptionstringContent frontmatter description fieldPage meta descriptiontemplates/staticforce/base.html.twig46-47
contentstringRendered HTML contentMain page content (use `raw` filter)
tagsstring|arrayContent frontmatter tags fieldPage keywords for meta tagtemplates/staticforce/base.html.twig48-56
source_filestringRelative path from content rootSource content file pathtemplates/staticforce/_chapter_nav.html.twig13

Variable Source Hierarchy:

  1. Content frontmatter fields are directly accessible (e.g., {{ title }})
  2. Site configuration from siteconfig.yaml accessible via site_config nested array
  3. Container variables accessible by their key names

Sources: templates/staticforce/base.html.twig8-56 src/Services/TemplateRenderer.php87

Menu Variables

Menu variables are generated by the MenuBuilder feature during POST_GLOB event:

VariableTypeSourceDescriptionCode Reference
menu_topstring (HTML)Static menu from siteconfig.yaml > menu > topTop navigation bar menutemplates/staticforce/base.html.twig73-77
menu_footerstring (HTML)Static menu from siteconfig.yaml > menu > footerFooter menutemplates/staticforce/_footer.html.twig17-20
menu1string (HTML)Content with menu: 1.x frontmatterPrimary sidebar menutemplates/staticforce/base.html.twig93
menu2string (HTML)Content with menu: 2.x frontmatterUser Guide menutemplates/staticforce/docs.html.twig48-51
menu3string (HTML)Content with menu: 3.x frontmatterFeatures menutemplates/staticforce/docs.html.twig53-56
menu4string (HTML)Content with menu: 4.x frontmatterDevelopment menutemplates/staticforce/docs.html.twig58-61

Raw Menu Data Access:

For advanced use cases, raw menu structure is available via features.MenuBuilder.files[N]:


Sources: templates/staticforce/base.html.twig73-93 templates/staticforce/docs.html.twig48-61 templates/staticforce/category.html.twig34-68

Feature Variables

Features store data in the features namespace during event processing:


Common Feature Variables:

Variable PathTypeFeatureDescriptionCode Reference
cache_busterstringCacheBusterUnique hash for cache busting (also available as top-level)templates/staticforce/base.html.twig62
tocstring (HTML)TableOfContentsGenerated table of contentstemplates/staticforce/docs.html.twig64-68
features.ChapterNav.pages[source_file]arrayChapterNavPrev/next navigation datatemplates/staticforce/_chapter_nav.html.twig17-20
features.MenuBuilder.files[N]arrayMenuBuilderRaw menu structure for manual iterationtemplates/staticforce/category.html.twig34
category_filesarrayCategoryIndexList of files in current categorytemplates/staticforce/category.html.twig78-92

Features store their data in the Container with a key pattern of features.{FeatureName}.{dataKey}. The TemplateVariableBuilder retrieves all variables prefixed with features. and makes them available in templates.

Sources: templates/staticforce/base.html.twig17-22 templates/staticforce/docs.html.twig16-17 templates/staticforce/_chapter_nav.html.twig14-15

Asset Variables

Asset variables are generated by AssetManager when features register CSS/JS files:

VariableTypeDescriptionFallback BehaviorCode Reference
stylesstring (HTML)All registered CSS <link> tagsAuto-injected before </head> if not renderedsrc/Services/TemplateRenderer.php227-256
head_scriptsstring (HTML)Scripts registered for <head>Auto-injected before </head> if not renderedsrc/Services/TemplateRenderer.php227-259
scriptsstring (HTML)Scripts registered for footerAuto-injected before </body> if not renderedsrc/Services/TemplateRenderer.php262-265

Usage in Templates:


If templates omit these variables, TemplateRenderer::injectAssets() automatically injects them as a fallback.

Sources: src/Services/TemplateRenderer.php218-268

Special Variables

VariableTypeSourceDescription
herostringContent frontmatterPath to hero image for banner display
category_templatesarrayCategories featureMapping of category slugs to template names
site_configarraysiteconfig.yamlComplete site configuration (nested structure)

Sources: templates/staticforce/docs.html.twig32-33 src/Services/TemplateRenderer.php51-59


Asset Management

Asset Registration Flow


Sources: src/Services/TemplateRenderer.php92-95 src/Services/TemplateRenderer.php218-268

AssetManager Integration

The AssetManager is an optional service that features use to register CSS and JavaScript assets. It's injected into TemplateRenderer during construction:

Initialization in Renderer Features:


Sources: src/Features/MarkdownRenderer/Feature.php44-54

Asset Injection Strategy

StaticForge implements a two-phase asset injection pattern:

Phase 1: Template Variable Rendering

  • AssetManager generates HTML strings via getStyles() and getScripts()
  • Strings are added to template variables as styles, head_scripts, scripts
  • Templates render these variables using {{ styles|raw }}

Phase 2: Automatic Fallback Injection

  • After Twig rendering, TemplateRenderer::injectAssets() checks if asset HTML is present
  • If missing, assets are automatically injected before </head> and </body> tags
  • Uses string search to avoid duplicate injection

Injection Logic:


Sources: src/Services/TemplateRenderer.php218-268

Asset Registration Patterns

Features typically register assets during their event handlers:

Example: CSS Registration


Example: JavaScript Registration


Assets paths are relative to SITE_BASE_URL and are not validated during registration - the template rendering phase simply generates HTML tags with the provided paths.

Sources: src/Features/MarkdownRenderer/Feature.php45-48

Template Asset Variables

Templates should render asset variables in appropriate locations:

Standard Pattern:


The |raw filter is required to prevent Twig from HTML-escaping the <link> and <script> tags.

Sources: templates/staticforce/base.html.twig62-63 templates/staticforce/base.html.twig107-121

Fallback Template

If Twig rendering fails, TemplateRenderer::applyBasicTemplate() generates a minimal HTML structure using string replacement:

Fallback Variables:

  • {{SITE_NAME}}
  • {{SITE_BASE_URL}}
  • {{PAGE_TITLE}}
  • {{CONTENT}}
  • {{META_DESCRIPTION}}
  • {{META_KEYWORDS}}

This ensures content is always rendered even if template files are missing or contain errors.

Sources: src/Services/TemplateRenderer.php155-213


renderTemplate() Method

For features that need to render partial templates (e.g., shortcodes, forms), TemplateRenderer provides renderTemplate():

Method Signature:


Usage:


This method bypasses template resolution logic and directly renders the specified template with provided variables. It automatically merges site configuration variables into the context.

Sources: src/Services/TemplateRenderer.php115-148

Refresh this wiki

On this page