VOOZH about

URL: https://deepwiki.com/calevans/staticforge/1-overview

⇱ calevans/staticforge | DeepWiki


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

Overview

Purpose and Scope

This document provides a high-level introduction to StaticForge, a PHP-based static site generator with an event-driven, plugin architecture. It covers the core architectural components, initialization process, and the fundamental patterns used throughout the system.

For detailed information on specific subsystems:

Sources: composer.json1-60 README.md1-95


What is StaticForge

StaticForge is a static site generator that transforms content files (Markdown and HTML) into deployment-ready static websites. Built with PHP 8.4+, it uses Twig for templating and implements an event-driven architecture where all major functionality is provided through a plugin system called "Features".

Key Characteristics:

  • Language: PHP 8.4+
  • Template Engine: Twig 3.0
  • Architecture: Event-driven with dependency injection
  • Extensibility: Feature-based plugin system
  • Content Formats: Markdown (via CommonMark) and HTML
  • Configuration: Multi-tier (environment variables, site configuration, CLI options)

The project is distributed as both a library (eicc/staticforge) installable via Composer and can be run in development mode from source.

Sources: composer.json1-60 README.md1-95 content/guide/quick-start.md14-25


Core Architecture Components

The following diagram maps the system's conceptual components to their actual code implementations:

Diagram: Core System Components and Their Code Entities


Component Descriptions:

ComponentClass/FilePurpose
ContainerEICC\Utils\ContainerDependency injection container; stores services and configuration variables
EventManagerEICC\StaticForge\Core\EventManagerPublishes events and manages listener registration with priority ordering
FeatureManagerEICC\StaticForge\Core\FeatureManagerDiscovers and loads features from multiple sources (user, composer, library)
FileDiscoveryEICC\StaticForge\Core\FileDiscoveryScans content directories, parses frontmatter, generates URL mappings
FileProcessorEICC\StaticForge\Core\FileProcessorOrchestrates the build by firing events at each processing stage
ExtensionRegistryEICC\StaticForge\Core\ExtensionRegistryMaps file extensions (.md, .html) to processing features
AssetManagerEICC\StaticForge\Core\AssetManagerTracks CSS/JS assets registered by features for template injection

Sources: src/bootstrap.php46-257 composer.json38-46 content/development/architecture.md1-247


Application Initialization Flow

The following diagram details the bootstrap sequence that occurs when any command is executed:

Diagram: Bootstrap Initialization Sequence


Key Bootstrap Steps:

  1. Autoloader Discovery - Locates Composer's autoloader in vendor installations or development mode src/bootstrap.php23-44
  2. Environment Loading - Loads .env file into $_ENV superglobal src/bootstrap.php63-77
  3. Path Normalization - Converts relative paths to absolute, handles platform differences src/bootstrap.php95-109
  4. Default Configuration - Sets sensible defaults for all paths and settings src/bootstrap.php111-126
  5. Container Setup - Creates DI container and stores configuration src/bootstrap.php128-141
  6. Site Configuration - Loads optional siteconfig.yaml src/bootstrap.php143-171
  7. Template Resolution - Determines active template from multiple sources src/bootstrap.php173-187
  8. Service Registration - Instantiates and registers all core services src/bootstrap.php190-257

Sources: src/bootstrap.php1-258 content/development/bootstrap.md1-246


Event-Driven Processing Lifecycle

StaticForge uses events to decouple the core processing logic from feature implementations. All events are defined as string constants and fired by FileProcessor during the build.

Diagram: Build Event Sequence


Event Phases:

EventPhasePurposeTypical Listeners
CREATEInitializationFeature state setupCacheBuster, TemplateAssets
POST_GLOBPlanningSite structure analysis with full file listMenuBuilder, CategoryIndex, Tags
PRE_RENDERPre-processingPer-file metadata enrichmentReadingTime, RelatedPosts
RENDERTransformationContent conversion to HTMLMarkdownRenderer, HtmlRenderer
POST_RENDERPost-processingPer-file HTML modification, data collectionSearch indexer, Analytics injection
POST_LOOPAggregationSite-wide artifact generationRssFeed, Sitemap, RobotsTxt
DESTROYCleanupResource releaseConnection closers, temp file cleanup

Sources: content/development/events.md1-179 content/development/architecture.md64-112 content/development/templates.md1-270


Feature System Architecture

Features are the primary extensibility mechanism in StaticForge. They are self-contained plugins that register event listeners to hook into the processing pipeline.

Diagram: Feature Discovery and Registration


Feature Lifecycle:

  1. Discovery - FeatureManager scans three locations in priority order: user features, composer-declared features, library features src/Core/FeatureManager.php
  2. Name-based Override - Features with identical names from higher-priority sources replace lower-priority ones, enabling user customization of core features
  3. Instantiation - Each feature class is instantiated and passed to the registration phase
  4. Registration - Feature's register() method is called with EventManager and Container, allowing it to bind event listeners
  5. Event Handling - When events fire during the build, the feature's methods are called according to registered event/priority pairs

Feature Base Class Structure:


Sources: content/development/features.md1-152 src/Core/FeatureManager.php content/development/architecture.md173-213


Configuration System Hierarchy

Configuration flows through a four-tier system with explicit override semantics:

Diagram: Configuration Resolution Hierarchy


Configuration Semantics:

SourcePurposeCommitted to VCSExample Keys
Hardcoded DefaultsSensible defaults for standard PHP project structureN/ASOURCE_DIR, OUTPUT_DIR, LOG_LEVEL
.env FileInfrastructure settings, secrets, environment-specific paths❌ No (.gitignored)SITE_BASE_URL, SFTP_HOST, SFTP_PASSWORD, LOG_LEVEL
siteconfig.yamlSite identity, menus, feature settings✅ Yessite.name, menu.top, disabled_features
CLI OptionsRuntime overrides for testing/debuggingN/A--template=test, --output=/tmp/build

Key Configuration Variables:

  • Required: SITE_BASE_URL - Base URL for the deployed site (used in all absolute URLs)
  • Directories: SOURCE_DIR, OUTPUT_DIR, TEMPLATE_DIR, LOG_DIR - All normalized to absolute paths during bootstrap
  • Template Selection: Resolved as siteconfig.yaml['site']['template']$_ENV['TEMPLATE']'staticforce'
  • Site Identity: site_name, site_tagline from siteconfig.yaml - available in all templates

Sources: src/bootstrap.php95-187 .env.example1-42 content/guide/configuration.md1-468 content/guide/site-config.md1-395


Content Processing Pipeline

The complete flow from content files to generated HTML:

Diagram: Content-to-Output Transformation


Processing Stages:

  1. Discovery - FileDiscovery::discoverFiles() scans SOURCE_DIR, parses frontmatter, filters based on draft/date metadata, generates URLs src/Core/FileDiscovery.php
  2. Planning - POST_GLOB event allows features to analyze the complete file list before rendering begins
  3. Rendering - Each file passes through PRE_RENDERRENDERPOST_RENDER event sequence
  4. Output - FileProcessor writes rendered_content to output_path in OUTPUT_DIR
  5. Aggregation - POST_LOOP event enables generation of site-wide artifacts from accumulated data

URL Generation Logic:

content/blog/my-post.md
→ Remove content/ prefix: blog/my-post.md
→ Remove extension: blog/my-post
→ Add .html: blog/my-post.html
→ Apply category (if metadata.category exists): {category}/my-post.html
→ Prepend SITE_BASE_URL: https://example.com/category/my-post.html

Sources: content/development/architecture.md17-61 src/Core/FileDiscovery.php src/Core/FileProcessor.php


Key Directories and Files

Project Structure:

staticforge/
├── bin/
│ └── staticforge.php # CLI entry point
├── src/
│ ├── bootstrap.php # Application initialization
│ ├── Core/ # Core services
│ │ ├── EventManager.php # Event system
│ │ ├── FeatureManager.php # Feature loader
│ │ ├── FileDiscovery.php # Content scanner
│ │ ├── FileProcessor.php # Build orchestrator
│ │ ├── ExtensionRegistry.php # File type registry
│ │ └── AssetManager.php # CSS/JS management
│ ├── Features/ # Core features (library)
│ │ ├── MarkdownRenderer/ # Markdown → HTML
│ │ ├── MenuBuilder/ # Navigation menus
│ │ ├── Categories/ # Category organization
│ │ ├── Sitemap/ # sitemap.xml
│ │ └── ... # Other built-in features
│ └── Commands/ # CLI commands
├── templates/ # Template collections
│ ├── staticforce/ # Documentation template
│ └── sample/ # Clean default template
├── content/ # Content source (user)
│ ├── *.md # Markdown pages
│ ├── *.html # HTML pages
│ └── assets/ # Images, CSS, JS
├── public/ # Generated output (user)
├── .env # Environment config (gitignored)
├── siteconfig.yaml # Site config (committed)
└── composer.json # Dependencies and metadata

Configuration Files:

Core Namespaces:

  • EICC\StaticForge\Core\* - Core services and infrastructure
  • EICC\StaticForge\Features\* - Built-in features shipped with the library
  • EICC\StaticForge\Commands\* - CLI command implementations
  • EICC\Utils\* - Utility classes from the eicc/utils package (Container, Log)

Sources: composer.json38-46 content/guide/quick-start.md246-260 README.md1-95


Processing Philosophy

StaticForge follows several architectural principles:

  1. Single Parse - Content files are read and parsed exactly once during the discovery phase. All subsequent operations use the in-memory discovered_files data structure.

  2. Immutable Discovery - The file list and URL mappings are established before any rendering occurs, preventing broken links and circular dependencies.

  3. Event-Driven Decoupling - The core never directly calls feature code. All interactions occur through the event system, allowing features to be added/removed without core modifications.

  4. Priority-Based Ordering - Event listeners execute in numeric priority order (0-999, ascending), enabling precise control over execution sequences when multiple features handle the same event.

  5. Bucket Brigade Pattern - Event handlers receive a data array, modify it, and return it. This creates a pipeline where each handler enriches the data for subsequent handlers.

  6. Lazy Rendering - Heavy operations like Markdown parsing and template rendering only occur during the RENDER event, after all metadata enrichment is complete.

Sources: content/development/architecture.md17-46 content/development/events.md1-179


Template System Integration

Templates use Twig 3.0 for rendering. The TemplateRenderer service provides template context assembly:

Template Variable Sources:

Variable CategorySourceExample Variables
Core MetadataFile frontmattertitle, description, tags, category
Container VariablesBootstrap configurationsite_name, site_base_url, SITE_BASE_URL
Feature DataFeature-injected datafeatures.MenuBuilder.html, features.Tags.cloud
Asset VariablesAssetManagerstyles, head_scripts, scripts
Computed ValuesSystem-generatedcache_buster, current_url

Template Resolution:

  1. Check file metadata for template field
  2. If category exists, use category-specific template
  3. Fall back to base.html.twig

Templates extend a base layout and override blocks to customize structure. The AssetManager tracks CSS/JS registered by features and makes them available as {{ styles|raw }} and {{ scripts|raw }} variables.

Sources: content/development/templates.md1-270 src/Features/MarkdownRenderer/Feature.php


Extension and Customization

Feature Override Mechanism:

Users can replace any built-in feature by creating a feature with the same name in src/Features/. The FeatureManager loads user features with highest priority, shadowing library features. This enables complete customization without forking the core.

Composer Integration:

Third-party features can be distributed via Composer by declaring type: staticforge-feature and registering the feature path in extra.staticforge.feature. The FeatureManager automatically discovers these during initialization.

Configuration Interfaces:

Features implementing ConfigurableFeatureInterface declare their required configuration keys, enabling:

  • The audit:config command to validate setup
  • Self-documenting configuration via getConfigHelp() methods
  • Runtime validation with meaningful error messages

Sources: content/development/features.md125-150 src/Core/FeatureManager.php