Release Notes

v1.5.1
Changelog 35 releases
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