Marketing Site (PHP)

The marketing site is a standalone plain PHP application with zero dependencies. No Composer, no Node.js, no build step.

Directory Structure

marketing/
├── public/                  # Web root (point server here)
│   ├── index.php            # Front controller
│   ├── router.php           # PHP dev server router
│   ├── .htaccess            # Apache URL rewriting
│   ├── css/style.css        # All styles
│   ├── js/
│   │   ├── app.js           # Dropdowns, theme, accordion
│   │   └── lucide.min.js    # Icons (self-hosted)
│   ├── images/              # Screenshots, og-image
│   ├── robots.txt
│   └── sitemap.xml
├── config.php               # URLs, plans, locales
├── routes.php               # URI → template mapping
├── lang/
│   ├── en.json              # English (200+ keys)
│   └── pt.json              # Portuguese
├── src/
│   └── helpers.php          # i18n, showcase, breadcrumb, markdown
└── templates/
    ├── layouts/main.php     # HTML shell, SEO, structured data
    ├── partials/
    │   ├── header.php       # Nav, theme toggle, lang switcher
    │   └── footer.php
    └── pages/
        ├── home.php         # Landing page
        ├── features.php     # Feature showcases
        ├── pricing.php      # Plans, FAQ, comparison
        ├── docs.php         # Docs index
        ├── docs-page.php    # Docs layout (sidebar + content)
        ├── 404.php
        └── docs/            # Doc content pages
            ├── installation/
            ├── project-structure/
            ├── authentication/
            └── ...

How Routing Works

All requests go through public/index.php (via .htaccess rewrite or Nginx try_files).

  1. Parse the URI and detect locale prefix (/pt/pricing → locale=pt, uri=/pricing)
  2. Match against routes.php for marketing pages
  3. Match against /docs/{section}/{page} pattern for documentation
  4. Render the template through layouts/main.php

i18n System

Translations live in lang/*.json files. The t('key') helper looks up strings:

// In a template:
<h1><?= t('home.title') ?></h1>

// With placeholders:
<p><?= t('greeting', ['name' => 'John']) ?></p>

URL routing adds a locale prefix for non-default languages: /pricing (English) vs /pt/pricing (Portuguese).

Adding a Language

  1. Copy lang/en.json to lang/es.json
  2. Translate the values
  3. Add to config.php: 'es' => 'Español' in the locales array

Theme System

Dark/light/system theme toggle stored in localStorage. CSS uses [data-theme="dark"] and [data-theme="light"] selectors with CSS variables for all colors.

Performance

  • CSS inlined in <head> (zero render-blocking stylesheets)
  • No external fonts (system font stack)
  • JS deferred (app.js) or async (lucide.min.js)
  • Icons self-hosted (no CDN round trips)
  • Gzip + cache headers via .htaccess