Emad Ashraf

Madraset El Shamamsa, Part 3: The PHP Component-Rendering Pipeline

3 min read

The most project-specific part of Madraset El Shamamsa is its PHP page-composition/rendering pipeline. It solves a practical publishing problem: many pages share the same shape, but each content library has its own records and presentation details.

It is not a general-purpose SSR framework. It is a convention-based system built inside this application, using PHP includes as composition boundaries.

From URL to complete HTML

flowchart TB
    Entry["Thin page entrypoint"] --> Generator["Library-specific generate-* assembler"]
    Generator --> Start["*-start.php context and data loader"]
    Start --> DB[("MySQL or page-specific data")]
    Generator --> Head["Metadata and head fragments"]
    Generator --> Global["Shared navbar, breadcrumbs, footer, scripts"]
    Generator --> Local["Library intro, body, media, navigation"]
    Head --> Document["Complete server-rendered HTML document"]
    Global --> Document
    Local --> Document
    Document --> Browser["Browser or crawler"]

The entrypoint identifies the page. The generate-* file defines the document structure for that family of pages. Its *-start.php dependency prepares variables and retrieves records. Shared components provide the global shell, while library components own the content-specific sections. PHP evaluates the graph on the server and sends an ordinary HTML document.

This pattern appears across hymn meditations, Coptic lessons, sermons, quotations, church-history articles, Bible summaries, and other libraries. Names differ because the system grew over time, but the recurring separation is visible in the codebase.

A representative, sanitized path

The real files contain library-specific names and fields. The following example keeps the control flow while removing operational detail:

<?php
// A thin content page delegates to its library assembler.
include __DIR__ . '/pageGeneration/generate-article.php';
<?php require __DIR__ . '/article-start.php'; ?>
<!doctype html>
<html lang="ar" dir="rtl">
  <head>
    <?php require $_SERVER['DOCUMENT_ROOT'] . '/common/head-includes.php'; ?>
    <?php include __DIR__ . '/article-metadata.php'; ?>
  </head>
  <body>
    <?php include $_SERVER['DOCUMENT_ROOT'] . '/common/top-navbar.php'; ?>
    <main>
      <?php include $_SERVER['DOCUMENT_ROOT'] . '/common/breadcrumb.php'; ?>
      <?php include __DIR__ . '/article-body.php'; ?>
      <?php include __DIR__ . '/article-navigation.php'; ?>
    </main>
    <?php include $_SERVER['DOCUMENT_ROOT'] . '/common/footer.php'; ?>
    <?php include $_SERVER['DOCUMENT_ROOT'] . '/common/script-includes.php'; ?>
  </body>
</html>
Rendered Arabic hymn page with shared navigation, breadcrumbs, metadata, audio controls, and library sections
A composed hymn page: the shared shell supplies navigation and metadata while library fragments provide teaching text, audio controls, and section-specific content.

The important architectural interface is the set of variables prepared by the start/data loader and consumed by the fragments. That contract is currently conventional rather than enforced by a type system.

Why it scaled

One change can reach a page family. Updating a shared shell or a library assembler avoids copying the same document structure across many entrypoints.

The output is usable before JavaScript. Readers and crawlers receive headings, text, links, and metadata as HTML. JavaScript enhances the document instead of being required to create it.

Libraries remain independent where they need to be. A Coptic lesson does not have to pretend it has the same data model as a sermon or hymn. Each family can keep its body and navigation components while sharing global infrastructure.

Modern assets can arrive gradually. Shared script and head includes connect the generated document to Vite. The composition layer does not need to know whether a module came from the development server or a hashed production file.

Next: performance, caching, and R2 delivery.