PDF

Release Notes

v1.19.9
Changelog 59 releases
v1.19.9 SAAF and SAN organigrams
2026-08-27
  • Migrations 54–55: seed South African Air Force and South African Navy OrgEntityAttachment trees from include/saafOob.json and include/sanOob.json
  • New saafOrganigram.php and sanOrganigram.php (Info menu) — live SVG organigrams for squadrons/bases and fleet combatants/patrol/support/bases
  • Shared include/organigramOob.php + organigramPage.php helpers; cross-links across Army, Air Force, Navy, and RSF organigram pages
v1.19.8 Rhodesian Security Forces organigrams
2026-08-27
  • Migration 53: seed OrgEntityAttachment trees for RSF from include/rsfOob.json under umbrella Category "Rhodesian Security Forces (organigram)"
  • New rsfOrganigram.php (Info menu) — live SVG organigrams for RSF overview, Rhodesian Army, Air Force, BSAP, and Internal Affairs/Guard Force; trees rebuild from DB attachments on each request
  • Cross-links between SA Army and RSF organigram pages
v1.19.7 Wartime division names on the organigram
2026-08-26
  • Migration 52: Wikipedia Template:SA Army Units piped [[1st Infantry Division (South Africa)|1]] as Name "1", which collided with leftover person Unit fragments (Lynsky/Beer/Fourie). Organigram now uses 1st/2nd/3rd South African Infantry Division, 3rd/6th South African Armoured Division, and the same expansion for numbered brigades, WWI SA Infantry / SAMR regiments, field engineers, and homeland battalions. Stub Unit="1"/"2" rows are left in place with the division Wikipedia URL removed.
v1.19.6 Rhodesian Security Forces (RSF) on the roll
2026-08-26
  • DefenceForce catalog code RSF (Rhodesian Security Forces, 11 Nov 1965–30 Mar 1980) — distinct from SADF/SANDF
  • Imported/enriched Prop Geldenhuys Rhodesian War Casualties chronological roll: Force=RSF on matched Rhodesian units, new records where not already on the roll, Geldenhuys citation, OrgEntity Branch=Rhodesian
  • Seeded Rhodesian memorial stubs (Operation Miracle, RFMP, RLI Trooper, Warren Hills, Gweru, London RAA, Donaldson Canberra, All Rhodesian Aircrew)
v1.19.5 Live SA Army organigrams
2026-08-26
  • Migration 51: seed Formation / Division / Command echelons and OrgEntityAttachment trees from Wikipedia Template:SA Army Units (include/saArmyOob.json)
  • New armyOrganigram.php under Info — search + SVG organigrams live from the database
  • Info menu: Formations, Divisions, Commands, Army Organigrams
v1.19.4 DLI name history and unit links
2026-08-26
  • Migration 50: Durban Light Infantry and Natal Carbineers drop "Royal" in 1961 (Republic) — shown on org pages as a dated name history, not only the next rename
  • Person page Unit/Regiment links when the ID is missing but the name matches an organisation; force labels like South African Army are not linked as a regiment
v1.19.3 Commando Group Commands and General Support Bases
2026-08-26
  • Migration 49: SADF/SANDF Commando System order of battle from Wikipedia Template:SA Commandos — numbered Group Commands and General Support Bases as organisation pages like Brigades, with commandos attached underneath
  • Folded duplicate GROUP N / Group N HQ / GSB KIMB rows onto the canonical Group Command / GSB entity
  • Info menu: Commandos, Group Commands, General Support Bases
v1.19.2 OrgEntity duplicates, 1940 OOB, helmet flashes
2026-08-26
  • Migration 48: folded 103 duplicate Regiment+Unit rows for the same organisation (the merge had kept both copies, so a Battalion typed as Regiment listed people whose Unit was a different battalion)
  • Cleared Regiment when it was a battalion-level name and Unit named a different formed unit (e.g. 1 Para on a 116 SAI / 101 Battalion record)
  • Stripped CWGC ", S.A. Forces" suffixes from organisation names; decoded HTML entities (Duke of Edinburgh's Own Rifles)
  • Split leftover "X attd. Y" primary Units onto PersonUnitAttachment (7 Medical Battalion Group attached to 44 Parachute Brigade)
  • 1–4 Parachute Battalion sit under 44 Parachute Brigade (1978–1999) then 44 Parachute Regiment; 1940 infantry-brigade attachments from Wikipedia OOB where both names already exist
  • Helmet/shoulder flashes from Wikipedia can display beside the cap badge on org.php
v1.19.1 Info menu for organisations
2026-08-26
  • New Info menu: Units, Regiments, Corps, Brigades, and Defence Forces moved off Lists onto organisation catalog/detail pages
  • info.php hub, listOrgs.php type catalogs (search + A–Z), and org.php detail pages (badge, Wikipedia, eras, order-of-battle parents/children, personnel)
  • Old listPeopleUnit/Regiment/Corps URLs redirect to org.php so person-page links keep working
  • Defence Force page shows the catalog description and Wikipedia link for each era
v1.19.0 OrgEntity merge, Corps field, and unit-history model
2026-08-26
  • Migration 40-41: merged the separate Regiment and Unit tables into one OrgEntity table (EntityType: Regiment/Corps/Brigade/Battalion/Battalion Group/Commando/Category/Unit) -- PersonInfoRaw.RegimentID/Regiment and .UnitID/Unit are unchanged, they just reference OrgEntity now; folded two RegimentID mis-keyings (Cape Corps+SWATF, SW African Police+SA Police) onto their correct entity instead of preserving the collision; fixed 10 stale Unit/Regiment text spellings
  • Migration 42-43: added Corps/CorpsID to PersonInfoRaw -- classified 25,462 of 26,874 Force-set rows (94.7%) via roh_classify_corps(), moving generic corps-as-Regiment labels (e.g. South African Infantry Corps) into Corps with Regiment cleared, and assigning a Corps to named regiments (e.g. Natal Carbineers -> SAIC) while keeping Regiment; also cleared 81 Regiment=SANDF mis-entries
  • Migration 44: finished the DefenceForce catalog (table existed in code but was never created) with two new codes, Colonial and SAP
  • Migration 45-46: repointed 214 PersonInfoRaw rows off duplicate attd. X Unit entities onto the clean entity already resolved via PersonUnitAttachment; cleared 1,327 redundant Unit2 attd. values and retired the dead UnitID2 column
  • Added OrgEntityAlias (replaces UnitAlias), OrgEntityEra (Force/Corps/Role/Status over time), and OrgEntityAttachment (order of battle) tables for unit-history research
  • New Corps field on the person page (linked, with sibling count) and listPeopleCorps.php; Corps added to search.php
  • Deleted normalize_lookup_tables.php and rebuild_tables_with_fks.php (stale admin tools that would have corrupted the merged schema if run)
  • See .cursor/rules/military-fields.mdc for the full model
v1.18.1 Ciskei Defence Force (CDF) on the Defence Force field
2026-08-20
  • Migration 34: Ciskei Defence Force deaths March 1981–26 April 1994 show Force CDF, not SADF and not blank
  • CDF was formed March 1981 from SADF 141 Battalion; Ciskei independence 4 December 1981; amalgamated into SANDF 27 April 1994
  • Post-27 April 1994 Ciskei regiment rows stay SANDF (e.g. Closure Unit)
  • Ciskei Parachute Battalion as a unit on a non-Ciskei regiment (1 Para / SA Army) does not change Force
v1.18.0 Gallantry awards and Honoris Crux / VC citations
2026-08-20
  • Migration 33: Award catalogue and PersonAward links for confirmed Victoria Cross and Honoris Crux recipients on the roll
  • Person page shows post-nominals after the surname (click for a scrollable medal modal)
  • Citations block filled for Honoris Crux records that previously had no citation text, from Wikipedia recipient lists and existing death narratives; London Gazette / Ogongo / Winterbottom texts were left unchanged
v1.17.0 Physical memorials (SADF Wall of Remembrance)
2026-08-19
  • Migration 29: Memorial, MemorialPhoto and PersonMemorial tables for walls of remembrance and similar sites
  • SADF Wall of Remembrance seeded with address, OpenStreetMap coordinates, and links for everyone listed at CemeteryID 2194 (panel number parsed from GraveRef where present)
  • Person page shows a Memorial card (name, location, panel, position on the panel)
  • listMemorials.php and warMemorial.php list the site and its names; cemetery listings are unchanged
  • Panel photographs can be added later and will list the names on that panel
v1.16.0 Citation page thumbnails from The Gazette
2026-08-17
  • Migration 28: CitationImage stores London Gazette page scans for award citations
  • Person page Citations card shows a thumbnail (lightbox) for each page found, with a link back to The Gazette
  • Gazette refs are parsed from Citation and ExtraCitation (LG/EG dates, issue numbers, gazette.co.uk URLs)
v1.15.0 Related Deaths: Unknown names and Civilian category
2026-08-17
  • Unnamed related deaths are stored with LastName Unknown (Tshabalala wife; second Group 39 HQ casualty)
  • Migration 27: RelatedDeathCategory Civilian for civilians killed in military-related activity
  • Serrano recategorised from Other to Civilian
  • First TRC batch: named civilians from SADF cross-border raids and attacks on military/security-force targets
v1.14.0 Old ROH person number + story attribution
2026-08-17
  • Migration 26: OldRohPersonNumber on PersonInfoRaw stores the pre-rohsa JustDone person number when uniquely matched
  • Archive stories/dedications remapped from JustDone PN to current PersonNumber (same unique-match rule as 32824)
  • Contributor name and email stripped from the end of imported bodies into ContributorName / ContributorEmail; new submissions are parsed the same way
v1.13.0 Related Death categories Other and Unknown
2026-08-17
  • Migration 25: RelatedDeathCategory gains Other and Unknown so inserts do not fail when the category is missing or does not fit Relative / Former member / Associated
  • roh_related_death_category_id() maps a name or id and falls back to Unknown
v1.12.0 Cause code (KIA / MIA / DOW) on person records
2026-08-17
  • Migration 24: CauseCode lookup table and PersonInfoRaw.CauseCode — short codes for statistics
  • KIA, MIA and DOW are first-class; also KOAS, DOAS, POW, FF, DUTY, MVA, AA, DROW, SEA, ACC, SHOT, MURD, SUIC, DIS, NAT, DISCH, UNK
  • Derived from ActualCause plus the raw CauseDeath narrative (e.g. knife wounds → DOW)
  • person.php shows Cause code next to the long cause of death; listPeopleCause.php?code=KIA lists a code; cause charts group by CauseCode
v1.11.0 Related Death category lookup
2026-08-17
  • Migration 23: RelatedDeathCategory table with foreign key from RelatedDeath.CategoryID
  • Seeded values: Relative, Former member, Associated
  • Related Death list and detail pages join the lookup for the category name
v1.10.0 Defence Force field (UDF / SADF / SANDF)
2026-08-17
  • Migration 22: Force column on PersonInfoRaw — UDF (1912–1957), SADF (1957–26 Apr 1994), SANDF (from 27 Apr 1994)
  • Derived from unit and regiment (South African military only; police, Rhodesian, Boer and foreign forces are left blank) plus date of death
  • 5 SAI and other SADF-era army units show SADF; the same units after 27 April 1994 show SANDF
  • person.php Military Service card shows Defence Force next to Secondary Unit; listPeopleForce.php lists each force
v1.9.0 Related Deaths — people not on the main roll
2026-08-17
  • Migration 21: RelatedDeath table and PersonRelatedDeath link table for relatives, former members who died after leaving the service, and other associated deaths that do not belong on the Roll of Honour
  • listRelatedDeaths.php lists them separately from the main roll; relatedDeath.php is the detail page
  • person.php shows a Related Deaths card (not mixed into the ROH record) when a link exists
  • Existing after-discharge PersonInfoRaw rows stay on the main roll — they already have SAWGP PersonNumbers
v1.8.0 External source catalog and per-person deep links
2026-08-17
  • Migration 20: ExternalSource catalog and PersonExternalSource link table (PersonNumber + SourceID + Url + Reference)
  • Every record gets a South African War Graves Project deep link (details.php?id={PersonNumber})
  • ExtraCitation URLs and named sources (SADF.info, Koevoet wall, WMBR, samilhistory, Graham Last Post, Mike Sandham) moved onto the link table
  • Editorial leftovers (stolen service-number notes, date-placeholder notes) stay in ExtraCitation as Research notes
  • person.php Additional Information card lists named external sources with deep links instead of a single ExtraCitation blob
v1.7.0 Stories and Dedications on person pages
2026-08-17
  • Migration 19: Stories and Dedications tables (PersonNumber, Body, contributor fields, DateAdded, Status approved/pending/rejected)
  • Imported archive scrape stories (2,049) and dedications (899) from the old justdone.co.za ROH as approved entries
  • person.php: Stories and Dedications cards with scrollable Add modals; new submissions go to Status=pending for review
  • submitMemorial.php + include/memorial.php: CSRF cookie, honeypot, validation; email is stored but never shown publicly
  • sql/stories_dedications_schema.sql and tools/import_stories_dedications.php for schema + re-import
v1.6.0 Remembrance List view on On This Day
2026-08-16
  • listOnThisDay.php: added a tab selector between the existing Table view and a new Remembrance List view (view=table / view=roll); the selected day and view are preserved across the date selector and pagination
  • Remembrance List renders each record as a narrative sentence — year, record number, rank and name, service number, unit (regiment), age, and the circumstances of death — ordered chronologically by year, 100 per page
  • Added a Copy as text button that copies the page as plain text (heading, one bullet per person, and the closing line) for posting to social media; falls back to a selectable text box where the clipboard API is blocked
  • Added roh_clean_field() in functions.php — decodes HTML entities stored in the database (names such as King's Royal Rifle Corps were being displayed double-encoded) and treats Unknown/N/A placeholders as empty; applied to the On This Day table columns as well
  • Added roh_otd_formation(), roh_otd_circumstances(), roh_otd_entry() and roh_otd_entry_text() helpers for building the narrative entries; Age = 0 is treated as unknown rather than printed as aged 0
v1.5.1 Search pagination and release note fix
2026-06-04
  • search.php: replaced hard LIMIT 100 with paginated results (100 per page, page parameter, total count, pagination nav) — drill-downs from chartConflict.php and other range-based filters now show all matching records
  • Release notes: fixed 1.5.0 INSERT OR IGNORE — the changes column was silently null due to PHP variable interpolation issue inside a double-quoted SQL string; consolidated to a single inline string literal
v1.5.0 Chart white-screen fixes, drill-down navigation overhaul, search expansion
2026-06-04
  • Migration 14 column count fix — INSERT SELECT in fixDatabase.php now includes NULL AS ExtraCitation for 34-column alignment
  • Fixed roh_cache fatal error — added roh_cache to core table guard; cacheGet() now calls ensureAnalyticsTables() before querying
  • Pageviews chart white-screen fix — replaced IIFE with DOMContentLoaded; wrapped every new Chart() in try-catch; restored max-height: 420px
  • Applied DOMContentLoaded + try-catch to all 17 chart files via chartGeneric.php roh_chart_script() and 8 inline chart pages
  • Moved RohData.sql3* to data/ directory; moved config.php to include/config.php with internal paths updated
  • Search broadened to 14 fields — search.php now searches Rank, Regiment, Unit, DateDeath, CauseDeath, ActualCause, Cemetery, Locality, Country, ServiceNo, GraveRef alongside name/number
  • Field-specific search parameters — search.php accepts FromYear, ToYear, AgeMin, AgeMax, Rank, Regiment, Unit, Cemetery, Cause as optional URL params that combine via AND; active filters shown as dismissible badges with Clear All
  • Conflict chart drill-down fixed — chartConflict.php now navigates to search.php?FromYear=&ToYear= using the conflict year range instead of dead search.php?q= route
  • Age chart drill-downs fixed — chartAge.php and chartAgeRank.php parse age-group labels into AgeMin/AgeMax parameters via search.php
  • New listPeopleAge.php — paginated sortable age-range filter page
  • New listPeopleRankGroup.php — paginated sortable rank-group filter page with dropdown selector
v1.3.9 Migrate dead izkor.gov.il citation URLs
2026-05-18
  • Added ExtraCitation column to PersonInfoRaw
  • Migration 17: all 2,598 records whose Citation field contained a dead izkor.gov.il URL (site completely rebuilt; old .asp?t= links all return 404) have been updated — ExtraCitation is set to https://www.izkor.gov.il so users can still search the Israeli Fallen Soldiers & Victims of Terrorism database by name, and the broken URL has been removed from Citation
  • The t= values in the old URLs were batch source IDs shared by up to 237 records each (74 unique values across 2,598 records), so individual URL reconstruction was not possible
  • person.php Additional Information card now shows an 'External Source' row with the link and a note to search by name
v1.3.10 South African War Graves Project link
2026-05-18
  • person.php Additional Information card now shows a permanent 'South African War Graves Project' link for every record, constructed from the PersonNumber as https://www.southafricawargraves.org/search/details.php?id={PersonNumber} — no database migration required as the URL is derived entirely from the existing PersonNumber field
v1.3.11 Lightbox image gallery on person page
2026-05-18
  • Portrait images on person.php now display as clickable thumbnails (160px height, object-fit cover) in a flex row
  • Clicking any thumbnail opens GLightbox — a lightweight MIT-licensed overlay showing the full image with keyboard/swipe navigation, name and record number as caption
  • No-image placeholders are excluded from the gallery entirely
  • Thumbnails have a scale + cyan glow hover effect matching the linked-field button style
v1.3.12 Fix image download for URLs with spaces in path
2026-05-18
  • Added roh_encode_url_path() helper in functions.php: percent-encodes raw spaces and special characters in URL path segments (decode-then-re-encode makes it idempotent — already-encoded URLs are not double-encoded)
  • Applied to roh_download_remote_image_safe() before curl_init — cURL was rejecting URLs like southafricawargraves.org image paths containing spaces and parentheses with exit code 3 (malformed URL), silently failing to download the image
  • Applied to GetImgSrc() fallback branch so the browser img src is also valid before the file has been downloaded locally
v1.3.13 Coordinates field links to Google Maps
2026-05-18
  • Coordinates field on person.php is now a clickable link to Google Maps (opens in new tab) — previously it showed the lat/long as plain text with no link
  • Fixed map marker icon class from 'fa fa-map-marker' (Font Awesome 4 — broken in FA5/6) to 'fas fa-map-marker-alt' on both the Cemetery map button and its fallback
v1.4.0 Unit info panel with Wikipedia integration
2026-05-18
  • Migration 18: added seven metadata columns to the Unit table — WikipediaUrl, Description, BadgeUrl, BadgeLocal, Formed, Disbanded, Branch (all TEXT, all NULL by default, idempotent)
  • Created UnitBadges/ directory for locally cached badge/insignia images
  • listPeopleUnit.php completely rewritten: unit info panel at the top shows badge image (locally cached preferred, remote URL fallback), unit name, branch/formed/disbanded pills, record count, description, and Wikipedia button; graceful 'no information on file' prompt with Add link when empty; sortable columns now use ASC/DESC toggle with dir= param; pagination style matches other list pages
  • Created editUnit.php — admin form to set WikipediaUrl, Description, BadgeUrl, Formed, Disbanded, Branch; on save with a BadgeUrl the image is automatically downloaded and cached in UnitBadges/ using the existing SSRF-safe download helper
  • Created unitWikiFetch.php — AJAX endpoint with two actions: action=search returns up to 6 Wikipedia page matches for a query; action=summary returns the full extract + thumbnail URL for a specific page title
  • Edit page has a live Wikipedia search panel: type the unit name, click a result, form fields auto-fill from the Wikipedia REST summary API (description, Wikipedia URL, badge thumbnail URL); badge preview button shows the image before saving
v1.4.1 Fix concurrent DB lock crashes
2026-05-18
  • Moved PRAGMA busy_timeout to execute before PRAGMA journal_mode = WAL — previously the WAL pragma could contend for a write lock before the timeout was even active, causing the very first statement to fail
  • Increased busy_timeout from 5 s to 30 s
  • Wrapped roh_run_migrations() in try/catch(SQLite3Exception) — a transient lock during migration now logs a warning and defers to the next request rather than crashing the page with a fatal error
  • Added roh_applied_migrations table: each migration now records itself as complete after its first successful run; subsequent requests check a single cheap SELECT and skip immediately — eliminates the flood of concurrent write queries that caused the locking storm on a busy server
  • Batch migrations (2, 3, 4, 11) mark themselves done only when their batch is empty, so they continue across requests until complete then become no-ops
  • All migration transactions upgraded from BEGIN to BEGIN IMMEDIATE to acquire the write lock upfront and wait (respecting busy_timeout) rather than failing mid-batch
v1.4.2 Harden editUnit.php against missing Unit columns
2026-05-18
  • editUnit.php: added an inline column-guard at page load that checks whether the seven Unit metadata columns (WikipediaUrl, Description, BadgeUrl, BadgeLocal, Formed, Disbanded, Branch) exist, and adds any missing ones immediately — prevents the 'no such column' fatal crash if migration 18 was deferred due to a DB lock
  • Wrapped the UPDATE Unit … execute() call in a try/catch so a column error or lock shows a user-friendly alert instead of a fatal crash
  • Added an error alert block in the HTML to display save errors to the user
v1.4.3 Wikipedia infobox preview on unit edit page
2026-05-18
  • editUnit.php: when a Wikipedia search result is selected, the Wikipedia infobox table is now fetched and displayed below the search results — styled for the dark theme with appropriate colours for title rows, label/data cells, and images
  • unitWikiFetch.php: added action=infobox — fetches section 0 of the Wikipedia article, extracts the first table.infobox via DOMDocument, cleans up edit-section spans, citation superscripts, and internal anchor links (text kept, href removed), fixes protocol-relative image src (//upload.wikimedia.org → https://), returns the cleaned HTML
  • editUnit.php: added block for the 'Unknown Unit' placeholder — visiting editUnit.php for that unit now redirects back to the unit list instead of showing an editable form
  • listPeopleUnit.php: 'Edit Unit Info' button is hidden when the unit name is 'Unknown Unit'
v1.3.1 Chart rebuilds and data cleanup
2026-05-17
  • Migration 13: NULLs out literal 'Unknown', 'N/A', '?', 'None', 'Not Known', 'Not Recorded' values in Unit, Cemetery, Locality, and Regiment fields
  • Rebuilt chartCemetery.php, chartLocality.php, chartRegiment.php from scratch — all three were broken (blank page) due to dependency on removed chartGeneric.php include
  • Fixed chartRank.php: removed RankID > 0 filter which silently excluded records, replaced CountNoRank()/CountTotalDeaths() helpers with inline queries
  • Fixed chartAge.php: replaced broken main age-group chart (was also using chartGeneric.php) with inline Chart.js bar chart; births-by-decade section unchanged
  • Rebuilt chartCauseOfDeathYear.php: now renders a proper stacked bar chart with the top 8 causes as separate coloured series by year, plus a full cause summary table
v1.3.2 Navigation menu additions
2026-05-17
  • Added missing chart pages to Statistics navigation submenus
  • Deaths: added Cause of Death by Year (chartCauseOfDeathYear.php)
  • Personnel: added Age at Death (chartAge.php)
  • Geography: added By Regiment, By Cemetery, By Locality (chartRegiment.php, chartCemetery.php, chartLocality.php)
v1.3.3 Schema corrections and Name field
2026-05-17
  • Migration 14: rebuilds PersonInfoRaw with correct column types — Age changed from TEXT to INTEGER (data preserved via CAST), Cemetery changed from INTEGER to TEXT; all 7 indexes recreated automatically
  • Migration 15: populates the Name field as 'Surname, FirstName (Initials)' for all records (falls back to 'Surname, FirstName' or 'Surname' if fields are absent); adds two SQLite triggers (trg_person_name_insert, trg_person_name_update) to keep Name current for all future inserts and edits to FirstName, LastName, or Initials
v1.3.4 Fix locality/country mismatches
2026-05-17
  • Migration 16: corrects Country to 'South Africa' for all records where Locality is a South African province but Country was set to another country (e.g. Gauteng/Zimbabwe, Eastern Cape/Namibia) — affects ~300 records across 9 provinces
  • Normalises variant province spellings: 'Kwazulu Natal' to 'KwaZulu-Natal', 'Limpopo Province' to 'Limpopo', 'North West Province' to 'North West'
  • chartLocality.php table now shows Country column alongside Locality
v1.3.5 Expanded person record page
2026-05-17
  • Rewrote person.php to show all fields in four grouped cards: Identity, Military Service, Death Record, Location, and Additional Information
  • Empty fields shown as muted italic 'Unknown' rather than hidden
  • Cause of Death shows normalised ActualCause as primary value with raw CauseDeath as a smaller subtitle
  • Cemetery name links to Google Maps when lat/long coordinates are present
  • Added Previous / Next navigation buttons to move between records
  • Date fields formatted as 'dd Month YYYY'
  • Record last-checked date shown in footer of the page
v1.3.6 Linked fields and badges on person page
2026-05-17
  • Citation field now detects URLs and renders them as clickable links opening in a new tab
  • Date of Death links to On This Day page with badge showing deaths on that calendar day
  • Date of Birth links to On This Day page with badge showing deaths on that calendar day
  • Regiment links to By Regiment list with badge showing total records in that regiment
  • Unit links to new By Unit list page with badge showing total records in that unit
  • Estimated Birth Year links to new By Est. Birth Year list page with badge showing how many share that birth year
  • Surname links to search results with badge showing total records with that surname
  • Linked fields styled as Bootstrap outline-info buttons with cyan glow on hover
  • Added listPeopleUnit.php — paginated list filtered by unit with sortable columns and unit dropdown selector
  • Added listPeopleEstBirthYear.php — paginated list filtered by estimated birth year with year dropdown
  • Added both new pages to Lists menu; renamed 'By Year' to 'By Year of Death' for clarity
v1.3.7 More linked fields on person page
2026-05-17
  • Added linked button + count badge for five more fields on person.php: Cause of Death (links to list by cause), Grave Reference (links to same cemetery filtered by plot ref), Country (links to list by country), Locality (links to list by locality), Cemetery (links to list by cemetery; map icon moved to a separate button alongside)
  • Added listPeopleCause.php — paginated sortable list filtered by ActualCause
  • Added listPeopleCountry.php — paginated sortable list filtered by Country
  • Added listPeopleLocality.php — paginated sortable list filtered by Locality
  • Added listPeopleCemetery.php — paginated sortable list filtered by CemeteryID; accepts optional grave= param to further narrow to a specific grave reference
v1.3.8 Minor person page cleanup
2026-05-17
  • Removed 'Record last checked: never' footer from person.php — the DateChecked field is empty on all 41,924 records and was never populated, so the line served no purpose
v1.3.0 Deaths by Unit chart
2026-05-16
  • Added chartUnit.php — horizontal bar chart of top 60 units by death count, with full ranked table showing count and percentage of records with a known unit
  • Added "By Unit" link to the Personnel submenu in the Statistics navigation
  • Rebuilt chartUnit.php from scratch replacing an old incompatible version that referenced removed helpers (UnitID filter, CountNoUnit(), chartGeneric.php)
v1.2.8 Data quality migrations 5-11
2026-05-16
  • Migration 5 (Rank cleanup): NULLs out "Rank Unknown" / "Unknown Rank" variants, strips trailing full stop, normalises Serjeant/Serjeant Major/Lance Serjeant/Staff Serjeant to modern Sergeant spellings
  • Migration 6 (CauseDeath): strips trailing full stops from raw CauseDeath field
  • Migration 7 (Initials): replaces full stops with spaces in Initials field, collapses double spaces, NULLs out blank results
  • Migration 8 (Age): converts Age = 0 to NULL (placeholder values)
  • Migration 9 (DateDeath): converts DateDeath values starting with "-0001" to NULL (SQLite date placeholder)
  • Migration 10 (ServiceNo): trims leading/trailing whitespace from ServiceNo
  • Migration 11 (Rank/Regiment/Unit title-case): converts all-caps Rank, Regiment, and Unit fields to title case; handles Mc/Mac prefixes; processed in batches of 5,000 per page load
v1.2.9 Remove spare record placeholders
2026-05-16
  • Added migration 12 to fixDatabase.php: deletes all PersonInfoRaw rows where LastName = 'Spare Record' — these are structural placeholder entries with no real person data
v1.2.7 Title-case name fields
2026-05-16
  • Added migration 4 to fixDatabase.php: converts all-caps LastName and FirstName values to title case (e.g. ABBOTT to Abbott, MCDONALD to McDonald)
  • Handles hyphens, apostrophes, and Mc/Mac prefixes
  • Affects ~41,000 LastName and ~39,000 FirstName records; processed in batches of 5,000 per page load
v1.2.6 Name field split migration
2026-05-16
  • Added migration 3 to fixDatabase.php: for records where FirstName is empty and LastName contains a space, splits the combined field at the first space into correct LastName and FirstName values
  • Excludes 151 records with Afrikaans/Dutch/French compound surname prefixes (DE, DU, DA, VAN, VON, TEN, DEN, TER, LE, LA) which must not be split
  • Where Initials is also blank, derives initials from the extracted first name by taking the first letter of each word
  • Affects ~421 records
v1.2.5 Page title fixes
2026-05-16
  • Added missing entries to roh_page_display_title() for releases.php, about.php, and chart_views.php so pageviews.php shows friendly titles instead of raw filenames
v1.2.4 Minor text fix
2026-05-16
  • Changed about.php browser tab title from "Roll of Honour — About" to "Roll of Honour — About this site"
v1.2.3 ActualCause field — normalised cause of death
2026-05-16
  • Added ActualCause column to PersonInfoRaw — parsed from the raw CauseDeath field by stripping location/narrative suffixes after the first comma, stripping parenthetical asides, and normalising ~40 variant spellings to canonical categories (e.g. "Died of pulmonary tuberculosis" → "Died of tuberculosis", MVA variants → "Died in motor vehicle accident")
  • Updated chartCauseOfDeath.php and chartCauseOfDeathYear.php to group by ActualCause instead of raw CauseDeath — reduces ~13,330 distinct values to ~200 meaningful categories
  • Updated CountNoCause() and roh_batch_person_stats() to use ActualCause
  • Updated Data Completeness chart to check ActualCause for meaningful cause data
v1.2.2 Line graph on On This Day
2026-05-16
  • Converted the yearly trend chart on listOnThisDay.php from a bar chart to a line graph with filled area, curve tension, dot markers, and dark-theme axis styling
v1.2.1 Estimated birth year
2026-05-16
  • Added EstBirthYear column to PersonInfoRaw — calculated as death year minus age at death (accurate to ±1 year), covering 30,382 records
  • Added "Estimated Births by Decade" bar chart and table to chartAge.php
  • Added estimated birth year range column (min–max) to rank detail table in chartAgeRank.php
  • Added stacked "Births by Decade by Rank Group" chart to chartAgeRank.php
  • Split "Date of Birth" in chartCompleteness.php into two rows: recorded date of birth (6 records) and estimated birth year (30,382 records)
v1.2.0 Version bump
2026-05-16
  • Minor version bump to 1.2.0
v1.1.0 Seven new statistics pages
2026-05-16
  • Added chartMap.php — interactive Leaflet.js cemetery map, circle markers sized by burial count, top-20 sites table
  • Added chartConflict.php — deaths grouped by named conflict era (Anglo-Boer War, WW1, WW2, Korean War, Rhodesian Bush War, SA Border War, post-1990), plus per-year timeline coloured by conflict
  • Added chartMonth.php — deaths by calendar month with top-3 months highlighted
  • Added chartCompleteness.php — data quality dashboard: progress bars and radar chart for 16 fields across Identity, Military, Death Record, Location, and Other categories
  • Added chartAgeRank.php — average age at death by rank group (General/Flag Officer down to Other Rank), plus full age-distribution histogram
  • Added chartSurname.php — top-40 surname frequency horizontal bar chart with ranked table
  • Added chartCalendar.php — 365-day CSS heat map grid showing deaths per calendar day across all years, with top-20 days table
  • Reorganised Statistics nav dropdown into four headed sections: Deaths, Personnel, Geography, Data
v1.0.3 Fixed duplicate release notes
2026-05-16
  • Added UNIQUE constraint on roh_releases.version — INSERT OR IGNORE had nothing to conflict on so inserted a new row every page load
  • Added deduplication DELETE before index creation to clean up existing duplicates on the server
  • Added CREATE UNIQUE INDEX IF NOT EXISTS for pre-existing installs
v1.0.2 Removed duplicate page views page
2026-05-16
  • Deleted chart_views.php — pageviews.php is the superset (includes everything chart_views had plus Top 40 table and daily 3-month chart)
  • Updated footer Quick Links to point to pageviews.php
  • Removed chart_views.php entry from roh_page_display_title()
v1.0.1 Bug fix
2026-05-16
  • Fixed Personnel with Images count on home page — was counting locally downloaded files only (returned 1); now counts distinct PersonNumber values with a real image URL, excluding the no_image.jpg placeholder (correct count: 30,183)
v1.0.0 Initial versioned release
2026-05-16
  • Initial versioned release of the Roll of Honour website
  • Removed deprecated gethostbynamel() call — now uses dns_get_record() exclusively (PHP 8.3+ compatible)
  • Replaced INSERT/catch/UPDATE race condition in page-view counter with atomic INSERT … ON CONFLICT DO UPDATE
  • Removed dead dirList() function
  • Added roh_batch_person_stats() — replaces 9 separate COUNT queries with a single SQL statement
  • Fixed broken HTML document on person-not-found (footer and menu now always render)
  • Consolidated image-download logic in person.php to use SaveRemoteImage() and GetImgSrc()
  • Added versioning system: roh_settings and roh_releases tables, version badge in footer
  • Added About page (about.php)
  • Added Release Notes page (releases.php)

New releases are added with each update session. Source code: github.com/JohnDovey/CreateROH