# Aircrew Remembered — CMS Technical Documentation June 2026 **Site:** aircrewremembered.com **CMS:** Custom PHP/MySQL (built 2025–2026, replacing Perch CMS) **Admin:** cms.aircrewremembered.com **Hosting:** Clook shared UK hosting **PHP version:** 5.6 **MySQL version:** 8 **Deployment:** FTP via Transmit (Mac). No SSH available. **Primary editor:** CotEditor (Mac) **Last updated:** June 2026 --- ## 1. Overview This is a bespoke lightweight CMS built to replace Perch CMS, which managed approximately 6,577 legacy archive report pages. The CMS serves reports dynamically via URL rewriting while preserving all legacy Perch URLs unchanged. The site also retains thousands of static Perch-generated HTML pages which coexist alongside CMS-served pages. The site is a non-profit historical aviation research resource. Data integrity and editor resilience are the highest priorities throughout. --- ## 2. Server File Structure ``` public_html/ ├── index.php — Random homepage selector (picks one of 5 static homepages) ├── index-gibraltar-searchlights.html — Homepage variant 1 ├── index-homepage-master.html — Homepage variant 2 ├── index-london-night.html — Homepage variant 3 ├── index-aa-tracers.html — Homepage variant 4 ├── index-nightsky-mountain.html — Homepage variant 5 ├── .htaccess — URL rewriting rules ├── cms-router.php — Central router: maps URLs to CMS reports ├── cms-site/ │ ├── templates/ │ │ ├── loss.php — Allied Forces report template │ │ ├── luftwaffe-loss.php — Luftwaffe/Axis report template │ │ ├── us-loss.php — USAAF report template │ │ ├── mcguiness-loss.php — Paul McGuiness RAAF archive template │ │ └── rob-philips-loss.php — Rob Philips Dutch archive template │ └── includes/ │ ├── config_loader.php │ ├── save_helpers.php │ └── search_helpers.php ├── ARCSS/ │ └── trebuchetx.css — Main sitewide stylesheet ├── ARSiteImages/ — All site images │ ├── HomepageIcons/ — 32px homepage icon strip images │ └── Crests/ — Squadron/unit badge images ├── Includes/ │ ├── mainmenux.html — Shared navigation menu (PHP included) │ └── template-left-sidebar3.html — Shared left sidebar └── JavaScriptFolder/ └── searchhi.js — Search term highlighter ``` --- ## 3. How URLs Are Routed `.htaccess` rewrites all requests for archive report URLs to `cms-router.php`: ``` RewriteRule ^([a-z0-9-]+)\.html$ cms-router.php?slug=$1 [L,QSA] ``` `cms-router.php` looks up the slug in the MySQL database. If found, it loads the appropriate template from `cms-site/templates/` and passes the report data. If not found, it falls through to a static file (legacy Perch page) if one exists. **Key principle:** Legacy Perch pages and CMS pages share the same URL namespace. The `.htaccess` rewrite only fires if no physical file exists at that path. This means static Perch HTML files take priority over CMS routing automatically. --- ## 4. Database The CMS uses MySQL 8. The primary tables are: - `ar_reports` — main archive reports table (slug, headline, story content, template type, tags, author, dates, soft-delete flag) - `name_index` — cross-table name search index, populated by MySQL triggers - Various legacy database tables (Kracker Archive, Allied Losses, etc.) accessed via the EnhancedUpdater suite at `cms.aircrewremembered.com` ### Key columns in ar_reports | Column | Purpose | |--------|---------| | `slug` | URL-safe identifier, matches the .html filename | | `headline` | Report title shown on page | | `story` | Main body HTML (TinyMCE editor output) | | `template` | Which template to use (loss, luftwaffe-loss, us-loss, etc.) | | `picture` | Squadron badge/crest img tag | | `nav_text` | AI-generated navigation description | | `meta_desc` | AI-generated meta description | | `tags` | Comma-separated tag list | | `author_date` | Free text credit line | | `deleted` | Soft-delete flag (1 = hidden from public) | | `_eu_edited` | Last edit record: YYYY-MM-DD initials | --- ## 5. Templates Each template in `cms-site/templates/` is a self-contained PHP file that produces a complete HTML page. They share a common structure: ### Common Structure of All Templates ``` Section 1 — Site header and banner image Section 2 — Accessibility controls (font slider + contrast toggle) Section 3 — Left sidebar (PHP include of template-left-sidebar3.html) Section 4 — Main content column (800px, margin-left:130px) Section 5 — Report header ("Archive Report: Allied Forces") Section 6 — Squadron badge / portrait image (top right) Section 7 — Mission headline Section 8 — Main story content (TinyMCE HTML) Section 9 — Supplementary content (optional) Section 10 — Author/date stamp Section 11 — Tag strip Section 12 — Editor's notes Section 13 — Hidden content Section 14 — Pages of Outstanding Interest Section 15 — Acknowledgements Section 16 — Footer ``` ### Key Layout Facts - Body is `width:1000px; margin-left:auto; margin-right:auto; position:relative` - `position:relative` on body is **essential** — it makes the body the containing block for the absolutely-positioned left sidebar. Without it the sidebar anchors to the viewport and appears off to the left on wide screens. - Left sidebar: `width:120px; position:absolute; left:0` - Main content: `width:800px; margin-left:130px` - Colour palette: `#063384` (dark blue), `#0a4fd4` (mid blue), `#e8edf8` (light blue background) - Header text colour: `#4f3b0b` (brown, Courier font) ### Template Variants | Template | Used for | Body background | |----------|----------|----------------| | `loss.php` | Allied Forces reports | default | | `luftwaffe-loss.php` | Luftwaffe/Axis reports | default | | `us-loss.php` | USAAF reports | default | | `mcguiness-loss.php` | Paul McGuiness RAAF Archive | `#f2fffd` (pale green tint) | | `rob-philips-loss.php` | Rob Philips Dutch Archive | `#e6f0ff` (pale blue tint) | --- ## 6. Accessibility Controls Each template includes a font size slider and high-contrast toggle, positioned top-right below the navigation bar. ### Critical Implementation Detail The functions `siteSetTextSize()` and `siteToggleContrast()` **must be defined in the `
`**, before the slider HTML is parsed. This is because the slider uses `oninput="siteSetTextSize(this.value)"` — an inline event handler — and modern Safari and Chrome (2025+) require the function to be defined before the element is parsed. The `localStorage` restore block (which reads saved preferences and applies them) must run at `DOMContentLoaded`, not in the ``, because it needs `document.getElementById('site-text-size')` to exist. The accessibility controls div has `margin-top:-20px` to tuck it up visually. It also requires `position:relative; z-index:100` to sit above the navigation menu div in the stacking order — without this only the bottom edge of the slider is clickable. --- ## 7. Left Sidebar The left sidebar is a shared PHP include: `Includes/template-left-sidebar3.html` It contains: - "Recent Archive Reports" button image - Amazon affiliate banner - Donate button - Auto-generated QR code for the current page URL (using qrcodejs from cdnjs) - Bullet list of database links The QR code script generates a canvas element then hides it and shows the img element, with a 100ms timeout to allow rendering. --- ## 8. Homepage The homepage uses a random rotation system. `index.php` at the site root selects one of five static HTML files at random using `array_rand()`: ```php $pages = [ 'index-gibraltar-searchlights.html', 'index-homepage-master.html', 'index-london-night.html', 'index-aa-tracers.html', 'index-nightsky-mountain.html' ]; include $pages[array_rand($pages)]; ``` Each homepage file is identical except for the background image (1050×1200px). Apache serves `index.php` in preference to `index.html` automatically — no `.htaccess` change required. The old `index.html` should be renamed or removed. ### Homepage Layout The homepage uses a large image (1050×1200px) as its base visual layer. The navigation menu, search box, tagline ("Honour. Remember. Respect"), icon strip and footer text are all overlaid using negative `margin-top` values that pull them up into the image area. This is intentional legacy behaviour — do not attempt to restructure it. The icon strip is a flexbox row of 32px circular icon images with CSS tooltips (`data-tooltip` attribute, white text on `#5ba3c9` background, Candara 12px, 5px border radius). --- ## 9. CSS — trebuchetx.css The main sitewide stylesheet. Key rules relevant to the CMS: - `body` — Avenir/Candara/Arial font stack, 14px, `#f1eef5` background - `#menu` — Navigation dropdown, `position:relative` (important: this creates a stacking context) - `.tip span` — Tooltip style for helpdesk/broken links icons at page bottom - `img { border: 1px solid #000000 }` — All images have a 1px black border by default. Images inside `.story-content` with float styles have margin overrides applied via attribute selectors. **Do not edit trebuchetx.css** without checking the effect on legacy Perch pages. Many thousands of pages depend on it. --- ## 10. TinyMCE Editor The CMS editor uses TinyMCE with custom paste normalisation. When content is pasted from macOS TextEdit, `` tags. Empty divs (which TinyMCE inserts when Enter is pressed for spacing) are collapsed to zero height via CSS: ```css .story-content div:empty { margin: 0; padding: 0; line-height: 0; height: 0; } ``` --- ## 11. Static File Publishing The CMS admin includes a publish-to-static feature that writes a physical `.html` file for a report. This is used for reports that need to be crawlable by search engines without dynamic rendering. Published static files take priority over CMS routing (see Section 3). There is overwrite protection for legacy Perch files. --- ## 12. EnhancedUpdater Suite A browser-based PHP/MySQL editing tool for the historical database tables, accessible at `cms.aircrewremembered.com`. Key features: - Sequential crew entry flow with shared-field pre-population - Purple progress banner - Bulk fill with folder dropdown and Add/Replace toggle - `image_awards` and `html` field types - Insert Link modal with smart-quote normalisation - Inline two-click delete - Post-create redirect with success banner - Admin panel Tables tab for adding tables via GUI - `_eu_edited` column written as `YYYY-MM-DD initials` on save **Working rule:** Always use the current live server file as the base for any edit. Never use the original zip. The active `save_helpers.php` is in the `includes/` folder (not the root). It uses `array_key_exists()` to preserve existing database values for fields not present in the submitted form, preventing accidental data loss. --- ## 13. Known Legacy Issues - jQuery 1.7.1 (2011) is loaded on all CMS pages. It is used for the back-to-top scroll button. Upgrading would require testing across all templates. - The navigation menu HTML has malformed nesting (some `