From f2bc638509045eaa7f07792e6dfb3b31a727e551 Mon Sep 17 00:00:00 2001 From: Jason Eugene Garrison Date: Sat, 11 Jul 2026 20:16:27 -0500 Subject: [PATCH] Fortify Bible reference interpretation --- plugins/bible-reference-tooltips/CHANGELOG.md | 6 + .../bible-reference-tooltips.php | 361 ++++++++++-------- plugins/bible-reference-tooltips/readme.txt | 8 +- tools/testlab/README.md | 5 +- tools/testlab/config/environments.json | 7 - tools/testlab/results/wp6-php74.json | 149 -------- tools/testlab/results/wp7-php84.json | 28 +- tools/testlab/scripts/common.ps1 | 2 +- tools/testlab/scripts/run-env.ps1 | 44 ++- 9 files changed, 284 insertions(+), 326 deletions(-) delete mode 100644 tools/testlab/results/wp6-php74.json diff --git a/plugins/bible-reference-tooltips/CHANGELOG.md b/plugins/bible-reference-tooltips/CHANGELOG.md index 81e73de..8c21034 100644 --- a/plugins/bible-reference-tooltips/CHANGELOG.md +++ b/plugins/bible-reference-tooltips/CHANGELOG.md @@ -1,5 +1,11 @@ # Bible Reference Tooltips Changelog +## 1.1.6 - 2026-07-12 + +- Centralizes Bible book aliases, eBible source-code aliases, lookup candidates, repair maps, and frontend detection aliases into one registry. +- Adds an admin text-integrity panel showing canonical book coverage for installed translations. +- Expands the Docker smoke matrix with direct interpretation-registry checks and additional alias REST lookups. + ## 1.1.5 - 2026-07-12 - Adds the public workspace conventions and tracked Docker test lab as the bounded release workflow for this public package. diff --git a/plugins/bible-reference-tooltips/bible-reference-tooltips.php b/plugins/bible-reference-tooltips/bible-reference-tooltips.php index 7451ada..3f3fbc1 100644 --- a/plugins/bible-reference-tooltips/bible-reference-tooltips.php +++ b/plugins/bible-reference-tooltips/bible-reference-tooltips.php @@ -3,7 +3,7 @@ * Plugin Name: Bible Reference Tooltips * Plugin URI: https://christit.com/bible-reference-tooltips * Description: Local, open Bible reference tooltips for WordPress content. Detects verse references on page load and serves hover cards from a local verse table. - * Version: 1.1.5 + * Version: 1.1.6 * Stage: Stable * Release Channel: Public * Public Release: Yes @@ -26,11 +26,11 @@ if (!defined('ABSPATH')) exit; if (!class_exists('Bible_Reference_Tooltips')) { class Bible_Reference_Tooltips { - const VERSION = '1.1.5'; + const VERSION = '1.1.6'; const SLUG = 'bible-reference-tooltips'; const NONCE = 'brt_nonce'; const OPTION_KEY = 'brt_settings'; - const SETTINGS_VERSION = '1.1.5'; + const SETTINGS_VERSION = '1.1.6'; const TABLE_VERSION = '1'; private $book_map = null; @@ -191,6 +191,7 @@ if (!class_exists('Bible_Reference_Tooltips')) { 'underline' => !empty($settings['underline']), 'showTranslation' => !empty($settings['show_translation']), 'showTooltips' => !empty($settings['show_tooltips']), + 'bookAliases' => $this->frontend_book_alias_patterns(), 'caseSensitive' => empty($settings['case_insensitive']), 'tagChapters' => !empty($settings['tag_chapters']), 'scanComments' => !empty($settings['scan_comments']), @@ -428,17 +429,7 @@ if (!class_exists('Bible_Reference_Tooltips')) { private function book_lookup_candidates($parsed) { $abbr = strtoupper(preg_replace('/[^A-Z0-9]/i', '', $parsed['book'] ?? '')); $name = strtoupper(preg_replace('/[^A-Z0-9]/i', '', $parsed['book_name'] ?? '')); - $variants = [ - 'JHN' => ['JHN', 'JOH', 'JOHN'], - 'PSA' => ['PSA', 'PS', 'PSM', 'PSALM', 'PSALMS'], - 'SNG' => ['SNG', 'SON', 'SOS', 'SONG'], - 'JAS' => ['JAS', 'JA', 'JAM', 'JMS', 'JM', 'JAC', 'JACOB', 'EPISTLEOFJAMES', 'THEEPISTLEOFJAMES'], - 'JOL' => ['JOL', 'JOE'], - 'NAM' => ['NAM', 'NAH'], - 'PHM' => ['PHM', 'PHLM', 'PHILEM'], - 'REV' => ['REV', 'RE', 'APO'], - ]; - $candidates = array_merge([$abbr, $name], $variants[$abbr] ?? [], $this->source_book_lookup_candidates($abbr)); + $candidates = array_merge([$abbr, $name], $this->book_registry_aliases($abbr), $this->source_book_lookup_candidates($abbr)); foreach ($this->book_map() as $alias => $entry) { if (strtoupper($entry['abbr']) !== $abbr) continue; $candidates[] = strtoupper(preg_replace('/[^A-Z0-9]/i', '', $alias)); @@ -451,14 +442,13 @@ if (!class_exists('Bible_Reference_Tooltips')) { private function book_name_lookup_candidates($parsed) { $abbr = strtoupper(preg_replace('/[^A-Z0-9]/i', '', $parsed['book'] ?? '')); $names = [$parsed['book_name'] ?? '', $abbr]; - foreach ($this->book_map() as $alias => $entry) { - if (strtoupper($entry['abbr']) !== $abbr) continue; - $names[] = $entry['name']; - $names[] = $alias; - $names[] = strtoupper($alias); - } - if ($abbr === 'JAS') { - $names = array_merge($names, ['James', 'Jas', 'JAS', 'Ja', 'JA', 'Jam', 'JAM', 'Jms', 'JMS', 'Jm', 'JM', 'Jac', 'JAC', 'Jacob', 'Epistle of James', 'The Epistle of James']); + $book = $this->book_registry_entry($abbr); + if ($book) { + $names[] = $book['name']; + foreach ($book['aliases'] as $alias) { + $names[] = $alias; + $names[] = strtoupper($alias); + } } return array_values(array_unique(array_filter(array_map('strval', $names)))); } @@ -525,115 +515,145 @@ if (!class_exists('Bible_Reference_Tooltips')) { } private function ebible_vpl_book_map() { - $source_to_canonical = [ - 'GEN' => 'GEN', 'EXO' => 'EXO', 'LEV' => 'LEV', 'NUM' => 'NUM', 'DEU' => 'DEU', - 'JOS' => 'JOS', 'JDG' => 'JDG', 'RUT' => 'RUT', '1SA' => '1SA', '2SA' => '2SA', - '1KI' => '1KI', '2KI' => '2KI', '1CH' => '1CH', '2CH' => '2CH', 'EZR' => 'EZR', - 'NEH' => 'NEH', 'EST' => 'EST', 'JOB' => 'JOB', 'PSA' => 'PSA', 'PRO' => 'PRO', - 'ECC' => 'ECC', 'SNG' => 'SNG', 'SOL' => 'SNG', 'ISA' => 'ISA', 'JER' => 'JER', 'LAM' => 'LAM', - 'EZE' => 'EZK', 'EZK' => 'EZK', 'DAN' => 'DAN', 'HOS' => 'HOS', 'JOL' => 'JOL', 'JOE' => 'JOL', - 'AMO' => 'AMO', 'OBA' => 'OBA', 'JON' => 'JON', 'MIC' => 'MIC', 'NAM' => 'NAM', 'NAH' => 'NAM', - 'HAB' => 'HAB', 'ZEP' => 'ZEP', 'HAG' => 'HAG', 'ZEC' => 'ZEC', 'MAL' => 'MAL', - 'MAT' => 'MAT', 'MAR' => 'MRK', 'MRK' => 'MRK', 'LUK' => 'LUK', 'JHN' => 'JHN', 'JOH' => 'JHN', - 'ACT' => 'ACT', 'ROM' => 'ROM', '1CO' => '1CO', '2CO' => '2CO', 'GAL' => 'GAL', - 'EPH' => 'EPH', 'PHP' => 'PHP', 'PHI' => 'PHP', 'COL' => 'COL', '1TH' => '1TH', '2TH' => '2TH', - '1TI' => '1TI', '2TI' => '2TI', 'TIT' => 'TIT', 'PHM' => 'PHM', 'HEB' => 'HEB', - 'JAS' => 'JAS', 'JAM' => 'JAS', '1PE' => '1PE', '2PE' => '2PE', '1JO' => '1JN', '1JN' => '1JN', - '2JO' => '2JN', '2JN' => '2JN', '3JO' => '3JN', '3JN' => '3JN', 'JUD' => 'JUD', - 'REV' => 'REV', - ]; $map = []; - foreach ($source_to_canonical as $source_abbr => $canonical_abbr) { - $map[$source_abbr] = ['abbr' => $canonical_abbr, 'name' => $this->book_name_from_abbr($canonical_abbr)]; + foreach ($this->book_registry() as $book) { + foreach ($book['source_aliases']['ebible_vpl'] as $source_abbr) { + $map[$source_abbr] = ['abbr' => $book['abbr'], 'name' => $book['name']]; + } } return $map; } private function book_map() { if ($this->book_map !== null) return $this->book_map; - $books = [ - ['GEN','Genesis',['gen','ge','gn']], - ['EXO','Exodus',['exo','ex','exod']], - ['LEV','Leviticus',['lev','le','lv']], - ['NUM','Numbers',['num','nu','nm','nb']], - ['DEU','Deuteronomy',['deut','deu','dt']], - ['JOS','Joshua',['josh','jos']], - ['JDG','Judges',['judg','jdg','jg']], - ['RUT','Ruth',['ruth','rut']], - ['1SA','1 Samuel',['1samuel','1sam','isamuel','isam']], - ['2SA','2 Samuel',['2samuel','2sam','iisamuel','iisam']], - ['1KI','1 Kings',['1kings','1kgs','1ki','ikings']], - ['2KI','2 Kings',['2kings','2kgs','2ki','iikings']], - ['1CH','1 Chronicles',['1chronicles','1chron','1chr','ichronicles']], - ['2CH','2 Chronicles',['2chronicles','2chron','2chr','iichronicles']], - ['EZR','Ezra',['ezra','ezr']], - ['NEH','Nehemiah',['neh','ne']], - ['EST','Esther',['esther','est']], - ['JOB','Job',['job']], - ['PSA','Psalms',['psalms','psalm','psa','ps']], - ['PRO','Proverbs',['proverbs','prov','pro','pr']], - ['ECC','Ecclesiastes',['ecclesiastes','eccl','ecc','qoheleth']], - ['SNG','Song of Solomon',['songofsolomon','songofsongs','song','sos','sng']], - ['ISA','Isaiah',['isaiah','isa']], - ['JER','Jeremiah',['jeremiah','jer']], - ['LAM','Lamentations',['lamentations','lam']], - ['EZK','Ezekiel',['ezekiel','ezek','ezk','eze']], - ['DAN','Daniel',['daniel','dan','dn']], - ['HOS','Hosea',['hosea','hos']], - ['JOL','Joel',['joel','jol','joe']], - ['AMO','Amos',['amos','amo']], - ['OBA','Obadiah',['obadiah','oba','obad']], - ['JON','Jonah',['jonah','jon']], - ['MIC','Micah',['micah','mic']], - ['NAM','Nahum',['nahum','nah','nam']], - ['HAB','Habakkuk',['habakkuk','hab']], - ['ZEP','Zephaniah',['zephaniah','zeph','zep']], - ['HAG','Haggai',['haggai','hag']], - ['ZEC','Zechariah',['zechariah','zech','zec']], - ['MAL','Malachi',['malachi','mal']], - ['MAT','Matthew',['matthew','matt','mat','mt']], - ['MRK','Mark',['mark','mrk','mk','mar']], - ['LUK','Luke',['luke','luk','lk']], - ['JHN','John',['john','jhn','jn','joh']], - ['ACT','Acts',['acts','act']], - ['ROM','Romans',['romans','rom','ro']], - ['1CO','1 Corinthians',['1corinthians','1cor','1co','icorinthians']], - ['2CO','2 Corinthians',['2corinthians','2cor','2co','iicorinthians']], - ['GAL','Galatians',['galatians','gal']], - ['EPH','Ephesians',['ephesians','eph']], - ['PHP','Philippians',['philippians','phil','php','phi']], - ['COL','Colossians',['colossians','col']], - ['1TH','1 Thessalonians',['1thessalonians','1thess','1th','ithessalonians']], - ['2TH','2 Thessalonians',['2thessalonians','2thess','2th','iithessalonians']], - ['1TI','1 Timothy',['1timothy','1tim','1ti','itimothy']], - ['2TI','2 Timothy',['2timothy','2tim','2ti','iitimothy']], - ['TIT','Titus',['titus','tit']], - ['PHM','Philemon',['philemon','phm']], - ['HEB','Hebrews',['hebrews','heb']], - ['JAS','James',['james','jas','ja','jam','jms','jm','jac','jacob','epistleofjames','theepistleofjames']], - ['1PE','1 Peter',['1peter','1pet','1pe','ipeter']], - ['2PE','2 Peter',['2peter','2pet','2pe','iipeter']], - ['1JN','1 John',['1john','1jn','1jhn','1jo','ijohn','ijn','ijhn','ijo']], - ['2JN','2 John',['2john','2jn','2jhn','2jo','iijohn','iijn','iijhn','iijo']], - ['3JN','3 John',['3john','3jn','3jhn','3jo','iiijohn','iiijn','iiijhn','iiijo']], - ['JUD','Jude',['jude','jud']], - ['REV','Revelation',['revelation','rev','re']], - ]; $map = []; - foreach ($books as $book) { - $name_key = strtolower(preg_replace('/[^a-z0-9]/i', '', $book[1])); - $map[$name_key] = ['abbr' => $book[0], 'name' => $book[1]]; - foreach ($book[2] as $alias) $map[$alias] = ['abbr' => $book[0], 'name' => $book[1]]; + foreach ($this->book_registry() as $book) { + $map[$this->alias_key($book['name'])] = ['abbr' => $book['abbr'], 'name' => $book['name']]; + foreach ($book['aliases'] as $alias) $map[$this->alias_key($alias)] = ['abbr' => $book['abbr'], 'name' => $book['name']]; } return $this->book_map = $map; } + private function book_registry_entry($abbr) { + $abbr = strtoupper(preg_replace('/[^A-Z0-9]/i', '', (string)$abbr)); + foreach ($this->book_registry() as $book) { + if ($book['abbr'] === $abbr) return $book; + } + return null; + } + + private function book_registry_aliases($abbr) { + $book = $this->book_registry_entry($abbr); + if (!$book) return []; + $aliases = [$book['abbr'], $book['name']]; + $aliases = array_merge($aliases, $book['aliases'], $book['source_aliases']['ebible_vpl']); + return array_map(function($alias) { + return strtoupper(preg_replace('/[^A-Z0-9]/i', '', (string)$alias)); + }, $aliases); + } + + private function alias_key($alias) { + return strtolower(preg_replace('/[^a-z0-9]/i', '', (string)$alias)); + } + + private function frontend_book_alias_patterns() { + $patterns = []; + foreach ($this->book_registry() as $book) { + foreach (array_merge([$book['name']], $book['aliases']) as $alias) { + $patterns[] = $this->frontend_book_alias_pattern($alias); + } + } + usort($patterns, function($a, $b) { return strlen($b) - strlen($a); }); + return array_values(array_unique(array_filter($patterns))); + } + + private function frontend_book_alias_pattern($alias) { + $alias = trim((string)$alias); + if ($alias === '') return ''; + $pattern = preg_quote($alias, '/'); + $pattern = preg_replace('/\\\\\s+/', '\\\\s*', $pattern); + $pattern = preg_replace('/^([1-3])([A-Za-z])/', '$1\\\\s*$2', $pattern); + return str_replace('\\ ', '\\s*', $pattern); + } + + private function book_registry() { + return [ + ['abbr'=>'GEN','name'=>'Genesis','aliases'=>['gen','ge','gn'],'source_aliases'=>['ebible_vpl'=>['GEN']]], + ['abbr'=>'EXO','name'=>'Exodus','aliases'=>['exo','ex','exod'],'source_aliases'=>['ebible_vpl'=>['EXO']]], + ['abbr'=>'LEV','name'=>'Leviticus','aliases'=>['lev','le','lv'],'source_aliases'=>['ebible_vpl'=>['LEV']]], + ['abbr'=>'NUM','name'=>'Numbers','aliases'=>['num','nu','nm','nb'],'source_aliases'=>['ebible_vpl'=>['NUM']]], + ['abbr'=>'DEU','name'=>'Deuteronomy','aliases'=>['deut','deu','dt'],'source_aliases'=>['ebible_vpl'=>['DEU']]], + ['abbr'=>'JOS','name'=>'Joshua','aliases'=>['josh','jos'],'source_aliases'=>['ebible_vpl'=>['JOS']]], + ['abbr'=>'JDG','name'=>'Judges','aliases'=>['judg','jdg','jg'],'source_aliases'=>['ebible_vpl'=>['JDG']]], + ['abbr'=>'RUT','name'=>'Ruth','aliases'=>['ruth','rut'],'source_aliases'=>['ebible_vpl'=>['RUT']]], + ['abbr'=>'1SA','name'=>'1 Samuel','aliases'=>['1samuel','1sam','i samuel','isamuel','isam'],'source_aliases'=>['ebible_vpl'=>['1SA']]], + ['abbr'=>'2SA','name'=>'2 Samuel','aliases'=>['2samuel','2sam','ii samuel','iisamuel','iisam'],'source_aliases'=>['ebible_vpl'=>['2SA']]], + ['abbr'=>'1KI','name'=>'1 Kings','aliases'=>['1kings','1kgs','1ki','i kings','ikings'],'source_aliases'=>['ebible_vpl'=>['1KI']]], + ['abbr'=>'2KI','name'=>'2 Kings','aliases'=>['2kings','2kgs','2ki','ii kings','iikings'],'source_aliases'=>['ebible_vpl'=>['2KI']]], + ['abbr'=>'1CH','name'=>'1 Chronicles','aliases'=>['1chronicles','1chron','1chr','i chronicles','ichronicles'],'source_aliases'=>['ebible_vpl'=>['1CH']]], + ['abbr'=>'2CH','name'=>'2 Chronicles','aliases'=>['2chronicles','2chron','2chr','ii chronicles','iichronicles'],'source_aliases'=>['ebible_vpl'=>['2CH']]], + ['abbr'=>'EZR','name'=>'Ezra','aliases'=>['ezra','ezr'],'source_aliases'=>['ebible_vpl'=>['EZR']]], + ['abbr'=>'NEH','name'=>'Nehemiah','aliases'=>['neh','ne'],'source_aliases'=>['ebible_vpl'=>['NEH']]], + ['abbr'=>'EST','name'=>'Esther','aliases'=>['esther','est'],'source_aliases'=>['ebible_vpl'=>['EST']]], + ['abbr'=>'JOB','name'=>'Job','aliases'=>['job'],'source_aliases'=>['ebible_vpl'=>['JOB']]], + ['abbr'=>'PSA','name'=>'Psalms','aliases'=>['psalms','psalm','psa','ps','psm'],'source_aliases'=>['ebible_vpl'=>['PSA']]], + ['abbr'=>'PRO','name'=>'Proverbs','aliases'=>['proverbs','prov','pro','pr'],'source_aliases'=>['ebible_vpl'=>['PRO']]], + ['abbr'=>'ECC','name'=>'Ecclesiastes','aliases'=>['ecclesiastes','eccl','ecc','qoheleth'],'source_aliases'=>['ebible_vpl'=>['ECC']]], + ['abbr'=>'SNG','name'=>'Song of Solomon','aliases'=>['songofsolomon','song of songs','songofsongs','song','sos','sng','sol'],'source_aliases'=>['ebible_vpl'=>['SNG','SOL']]], + ['abbr'=>'ISA','name'=>'Isaiah','aliases'=>['isaiah','isa'],'source_aliases'=>['ebible_vpl'=>['ISA']]], + ['abbr'=>'JER','name'=>'Jeremiah','aliases'=>['jeremiah','jer'],'source_aliases'=>['ebible_vpl'=>['JER']]], + ['abbr'=>'LAM','name'=>'Lamentations','aliases'=>['lamentations','lam'],'source_aliases'=>['ebible_vpl'=>['LAM']]], + ['abbr'=>'EZK','name'=>'Ezekiel','aliases'=>['ezekiel','ezek','ezk','eze'],'source_aliases'=>['ebible_vpl'=>['EZK','EZE']]], + ['abbr'=>'DAN','name'=>'Daniel','aliases'=>['daniel','dan','dn'],'source_aliases'=>['ebible_vpl'=>['DAN']]], + ['abbr'=>'HOS','name'=>'Hosea','aliases'=>['hosea','hos'],'source_aliases'=>['ebible_vpl'=>['HOS']]], + ['abbr'=>'JOL','name'=>'Joel','aliases'=>['joel','jol','joe'],'source_aliases'=>['ebible_vpl'=>['JOL','JOE']]], + ['abbr'=>'AMO','name'=>'Amos','aliases'=>['amos','amo'],'source_aliases'=>['ebible_vpl'=>['AMO']]], + ['abbr'=>'OBA','name'=>'Obadiah','aliases'=>['obadiah','oba','obad'],'source_aliases'=>['ebible_vpl'=>['OBA']]], + ['abbr'=>'JON','name'=>'Jonah','aliases'=>['jonah','jon'],'source_aliases'=>['ebible_vpl'=>['JON']]], + ['abbr'=>'MIC','name'=>'Micah','aliases'=>['micah','mic'],'source_aliases'=>['ebible_vpl'=>['MIC']]], + ['abbr'=>'NAM','name'=>'Nahum','aliases'=>['nahum','nah','nam'],'source_aliases'=>['ebible_vpl'=>['NAM','NAH']]], + ['abbr'=>'HAB','name'=>'Habakkuk','aliases'=>['habakkuk','hab'],'source_aliases'=>['ebible_vpl'=>['HAB']]], + ['abbr'=>'ZEP','name'=>'Zephaniah','aliases'=>['zephaniah','zeph','zep'],'source_aliases'=>['ebible_vpl'=>['ZEP']]], + ['abbr'=>'HAG','name'=>'Haggai','aliases'=>['haggai','hag'],'source_aliases'=>['ebible_vpl'=>['HAG']]], + ['abbr'=>'ZEC','name'=>'Zechariah','aliases'=>['zechariah','zech','zec'],'source_aliases'=>['ebible_vpl'=>['ZEC']]], + ['abbr'=>'MAL','name'=>'Malachi','aliases'=>['malachi','mal'],'source_aliases'=>['ebible_vpl'=>['MAL']]], + ['abbr'=>'MAT','name'=>'Matthew','aliases'=>['matthew','matt','mat','mt'],'source_aliases'=>['ebible_vpl'=>['MAT']]], + ['abbr'=>'MRK','name'=>'Mark','aliases'=>['mark','mrk','mk','mar'],'source_aliases'=>['ebible_vpl'=>['MRK','MAR']]], + ['abbr'=>'LUK','name'=>'Luke','aliases'=>['luke','luk','lk'],'source_aliases'=>['ebible_vpl'=>['LUK']]], + ['abbr'=>'JHN','name'=>'John','aliases'=>['john','jhn','jn','joh'],'source_aliases'=>['ebible_vpl'=>['JHN','JOH']]], + ['abbr'=>'ACT','name'=>'Acts','aliases'=>['acts','act'],'source_aliases'=>['ebible_vpl'=>['ACT']]], + ['abbr'=>'ROM','name'=>'Romans','aliases'=>['romans','rom','ro'],'source_aliases'=>['ebible_vpl'=>['ROM']]], + ['abbr'=>'1CO','name'=>'1 Corinthians','aliases'=>['1corinthians','1cor','1co','i corinthians','icorinthians'],'source_aliases'=>['ebible_vpl'=>['1CO']]], + ['abbr'=>'2CO','name'=>'2 Corinthians','aliases'=>['2corinthians','2cor','2co','ii corinthians','iicorinthians'],'source_aliases'=>['ebible_vpl'=>['2CO']]], + ['abbr'=>'GAL','name'=>'Galatians','aliases'=>['galatians','gal'],'source_aliases'=>['ebible_vpl'=>['GAL']]], + ['abbr'=>'EPH','name'=>'Ephesians','aliases'=>['ephesians','eph'],'source_aliases'=>['ebible_vpl'=>['EPH']]], + ['abbr'=>'PHP','name'=>'Philippians','aliases'=>['philippians','phil','php','phi'],'source_aliases'=>['ebible_vpl'=>['PHP','PHI']]], + ['abbr'=>'COL','name'=>'Colossians','aliases'=>['colossians','col'],'source_aliases'=>['ebible_vpl'=>['COL']]], + ['abbr'=>'1TH','name'=>'1 Thessalonians','aliases'=>['1thessalonians','1thess','1th','i thessalonians','ithessalonians'],'source_aliases'=>['ebible_vpl'=>['1TH']]], + ['abbr'=>'2TH','name'=>'2 Thessalonians','aliases'=>['2thessalonians','2thess','2th','ii thessalonians','iithessalonians'],'source_aliases'=>['ebible_vpl'=>['2TH']]], + ['abbr'=>'1TI','name'=>'1 Timothy','aliases'=>['1timothy','1tim','1ti','i timothy','itimothy'],'source_aliases'=>['ebible_vpl'=>['1TI']]], + ['abbr'=>'2TI','name'=>'2 Timothy','aliases'=>['2timothy','2tim','2ti','ii timothy','iitimothy'],'source_aliases'=>['ebible_vpl'=>['2TI']]], + ['abbr'=>'TIT','name'=>'Titus','aliases'=>['titus','tit'],'source_aliases'=>['ebible_vpl'=>['TIT']]], + ['abbr'=>'PHM','name'=>'Philemon','aliases'=>['philemon','phm','phlm','philemeon'],'source_aliases'=>['ebible_vpl'=>['PHM']]], + ['abbr'=>'HEB','name'=>'Hebrews','aliases'=>['hebrews','heb'],'source_aliases'=>['ebible_vpl'=>['HEB']]], + ['abbr'=>'JAS','name'=>'James','aliases'=>['james','jas','ja','jam','jms','jm','jac','jacob','epistleofjames','the epistle of james','theepistleofjames'],'source_aliases'=>['ebible_vpl'=>['JAS','JAM']]], + ['abbr'=>'1PE','name'=>'1 Peter','aliases'=>['1peter','1pet','1pe','i peter','ipeter'],'source_aliases'=>['ebible_vpl'=>['1PE']]], + ['abbr'=>'2PE','name'=>'2 Peter','aliases'=>['2peter','2pet','2pe','ii peter','iipeter'],'source_aliases'=>['ebible_vpl'=>['2PE']]], + ['abbr'=>'1JN','name'=>'1 John','aliases'=>['1john','1jn','1jhn','1jo','i john','ijohn','ijn','ijhn','ijo'],'source_aliases'=>['ebible_vpl'=>['1JN','1JO']]], + ['abbr'=>'2JN','name'=>'2 John','aliases'=>['2john','2jn','2jhn','2jo','ii john','iijohn','iijn','iijhn','iijo'],'source_aliases'=>['ebible_vpl'=>['2JN','2JO']]], + ['abbr'=>'3JN','name'=>'3 John','aliases'=>['3john','3jn','3jhn','3jo','iii john','iiijohn','iiijn','iiijhn','iiijo'],'source_aliases'=>['ebible_vpl'=>['3JN','3JO']]], + ['abbr'=>'JUD','name'=>'Jude','aliases'=>['jude','jud'],'source_aliases'=>['ebible_vpl'=>['JUD']]], + ['abbr'=>'REV','name'=>'Revelation','aliases'=>['revelation','rev','re','apo'],'source_aliases'=>['ebible_vpl'=>['REV']]], + ]; + } + public function admin_page() { if (!current_user_can('manage_options')) return; $settings = $this->settings(); $stats = $this->translation_stats(); $translations = $this->available_translations(); $installed = $this->installed_translations(); + $integrity = $this->text_integrity_summary(); $installed_by_code = []; foreach ($installed as $row) $installed_by_code[$row['code']] = $row; $msg = sanitize_text_field($_GET['msg'] ?? ''); @@ -732,6 +752,26 @@ if (!class_exists('Bible_Reference_Tooltips')) { +
+

Text Integrity

+ +

No local Bible texts are installed yet.

+ + + + + + + + + + + + +
TranslationCanonical booksStatus
Complete' : esc_html('Missing: ' . implode(', ', $row['missing'])); ?>
+

This checks whether each installed text has at least one row for every canonical Bible book after source-code interpretation.

+ +

Open Text Policy

This plugin is designed for Bible texts that are public domain, openly licensed, or otherwise legally permitted for local storage and display. It does not provide import tools for restricted commercial translations unless a future integration explicitly supports proper licensing.

@@ -748,6 +788,29 @@ if (!class_exists('Bible_Reference_Tooltips')) { return $wpdb->get_results("SELECT translation, COUNT(*) AS verses, MAX(source) AS source FROM " . self::table() . " GROUP BY translation ORDER BY translation ASC"); } + private function text_integrity_summary() { + global $wpdb; + $expected = array_map(function($book) { return $book['abbr']; }, $this->book_registry()); + $translations = $wpdb->get_col("SELECT DISTINCT translation FROM " . self::table() . " ORDER BY translation ASC"); + $summary = []; + foreach ((array)$translations as $translation) { + $found = $wpdb->get_col($wpdb->prepare( + "SELECT DISTINCT book FROM " . self::table() . " WHERE translation = %s ORDER BY book ASC", + $translation + )); + $found = array_values(array_unique(array_map('strtoupper', array_map('strval', $found ?: [])))); + $missing = array_values(array_diff($expected, $found)); + $summary[] = [ + 'translation' => strtoupper((string)$translation), + 'expected' => count($expected), + 'found' => count(array_intersect($expected, $found)), + 'missing' => $missing, + 'ok' => !$missing, + ]; + } + return $summary; + } + private function available_translations() { return [ 'WEB' => [ @@ -1028,22 +1091,7 @@ if (!class_exists('Bible_Reference_Tooltips')) { private function repair_book_aliases() { if (get_option('brt_alias_repair_version') === self::VERSION) return; global $wpdb; - $repairs = [ - 'JAM' => ['JAS', 'James'], - 'JMS' => ['JAS', 'James'], - 'JM' => ['JAS', 'James'], - 'JA' => ['JAS', 'James'], - 'JAC' => ['JAS', 'James'], - 'JACOB' => ['JAS', 'James'], - 'EPISTLEOFJAMES' => ['JAS', 'James'], - 'THEEPISTLEOFJAMES' => ['JAS', 'James'], - 'JOH' => ['JHN', 'John'], - 'JOE' => ['JOL', 'Joel'], - 'NAH' => ['NAM', 'Nahum'], - 'PHI' => ['PHP', 'Philippians'], - 'PHL' => ['PHM', 'Philemon'], - ]; - foreach ($repairs as $old => $new) { + foreach ($this->canonical_book_repairs() as $old => $new) { $wpdb->query($wpdb->prepare( "UPDATE IGNORE " . self::table() . " SET book = %s, book_name = %s WHERE book = %s", $new[0], @@ -1056,23 +1104,7 @@ if (!class_exists('Bible_Reference_Tooltips')) { $new[0] )); } - $name_repairs = [ - 'jam' => ['JAS', 'James'], - 'jms' => ['JAS', 'James'], - 'jm' => ['JAS', 'James'], - 'ja' => ['JAS', 'James'], - 'jas' => ['JAS', 'James'], - 'jac' => ['JAS', 'James'], - 'jacob' => ['JAS', 'James'], - 'epistleofjames' => ['JAS', 'James'], - 'theepistleofjames' => ['JAS', 'James'], - 'joh' => ['JHN', 'John'], - 'joe' => ['JOL', 'Joel'], - 'nah' => ['NAM', 'Nahum'], - 'phi' => ['PHP', 'Philippians'], - 'phl' => ['PHM', 'Philemon'], - ]; - foreach ($name_repairs as $old_name => $new) { + foreach ($this->canonical_book_name_repairs() as $old_name => $new) { $wpdb->query($wpdb->prepare( "UPDATE IGNORE " . self::table() . " SET book = %s, book_name = %s WHERE LOWER(REPLACE(REPLACE(REPLACE(book_name, ' ', ''), '.', ''), '-', '')) = %s", $new[0], @@ -1083,6 +1115,28 @@ if (!class_exists('Bible_Reference_Tooltips')) { update_option('brt_alias_repair_version', self::VERSION, false); } + private function canonical_book_repairs() { + $repairs = []; + foreach ($this->book_registry() as $book) { + foreach (array_merge($book['aliases'], $book['source_aliases']['ebible_vpl']) as $alias) { + $key = strtoupper(preg_replace('/[^A-Z0-9]/i', '', (string)$alias)); + if ($key && $key !== $book['abbr']) $repairs[$key] = [$book['abbr'], $book['name']]; + } + } + return $repairs; + } + + private function canonical_book_name_repairs() { + $repairs = []; + foreach ($this->book_registry() as $book) { + foreach (array_merge([$book['name']], $book['aliases'], $book['source_aliases']['ebible_vpl']) as $alias) { + $key = $this->alias_key($alias); + if ($key) $repairs[$key] = [$book['abbr'], $book['name']]; + } + } + return $repairs; + } + private function repair_missing_james_verses() { if (get_option('brt_james_backfill_version') === self::VERSION) return; global $wpdb; @@ -1126,20 +1180,7 @@ if (!class_exists('Bible_Reference_Tooltips')) { return <<<'JS' (function(){ if (!window.BibleReferenceTooltips || !BibleReferenceTooltips.rest) return; - const bookAliases = [ - 'Genesis','Gen','Ge','Gn','Exodus','Exod','Exo','Ex','Leviticus','Lev','Le','Lv','Numbers','Num','Nu','Nm','Nb','Deuteronomy','Deut','Deu','Dt', - 'Joshua','Josh','Jos','Judges','Judg','Jdg','Jg','Ruth','Rut','Ru','1\\s*Samuel','1\\s*Sam','1\\s*Sa','2\\s*Samuel','2\\s*Sam','2\\s*Sa', - '1\\s*Kings','1\\s*Kgs','1\\s*Ki','2\\s*Kings','2\\s*Kgs','2\\s*Ki','1\\s*Chronicles','1\\s*Chron','1\\s*Chr','2\\s*Chronicles','2\\s*Chron','2\\s*Chr', - 'Ezra','Ezr','Nehemiah','Neh','Ne','Esther','Est','Job','Psalms','Psalm','Psa','Ps','Proverbs','Prov','Pro','Pr','Ecclesiastes','Eccl','Ecc', - 'Song\\s*of\\s*Solomon','Song\\s*of\\s*Songs','Song','Sos','Sng','Isaiah','Isa','Jeremiah','Jer','Lamentations','Lam','Ezekiel','Ezek','Ezk','Eze', - 'Daniel','Dan','Dn','Hosea','Hos','Joel','Jol','Joe','Jl','Amos','Amo','Obadiah','Obad','Oba','Jonah','Jon','Micah','Mic','Nahum','Nah','Nam','Habakkuk','Hab','Zephaniah','Zeph','Zep', - 'Haggai','Hag','Zechariah','Zech','Zec','Malachi','Mal','Matthew','Matt','Mat','Mt','Mark','Mrk','Mk','Mar','Luke','Luk','Lk','John','Jhn','Jn', - 'Acts','Act','Romans','Rom','Ro','1\\s*Corinthians','1\\s*Cor','1\\s*Co','2\\s*Corinthians','2\\s*Cor','2\\s*Co','Galatians','Gal','Ephesians','Eph', - 'Philippians','Phil','Php','Colossians','Col','1\\s*Thessalonians','1\\s*Thess','1\\s*Th','2\\s*Thessalonians','2\\s*Thess','2\\s*Th', - '1\\s*Timothy','1\\s*Tim','1\\s*Ti','2\\s*Timothy','2\\s*Tim','2\\s*Ti','Titus','Tit','Philemon','Phlm','Phm','Hebrews','Heb', - 'James\\.?','Jas\\.?','Ja\\.?','Jam\\.?','Jms\\.?','Jm\\.?','Jac\\.?','Jacob','Epistle\\s*of\\s*James','1\\s*Peter','1\\s*Pet','1\\s*Pe','2\\s*Peter','2\\s*Pet','2\\s*Pe','1\\s*John','1\\s*Jn','1\\s*Jhn','1\\s*Jo', - '2\\s*John','2\\s*Jn','2\\s*Jhn','2\\s*Jo','3\\s*John','3\\s*Jn','3\\s*Jhn','3\\s*Jo','Jude','Jud','Revelation','Rev','Re' - ]; + const bookAliases = Array.isArray(BibleReferenceTooltips.bookAliases) ? BibleReferenceTooltips.bookAliases : []; const book = '(?:' + bookAliases.sort((a,b) => b.length - a.length).join('|') + ')'; const chapterPattern = BibleReferenceTooltips.tagChapters ? '(?:\\s*[:.]\\s*\\d{1,3}(?:\\s*[-\\u2013\\u2014]\\s*\\d{1,3})?)?' : '\\s*[:.]\\s*\\d{1,3}(?:\\s*[-\\u2013\\u2014]\\s*\\d{1,3})?'; const refPattern = '\\b(' + book + ')[\\s.]*\\d{1,3}' + chapterPattern + '\\b'; diff --git a/plugins/bible-reference-tooltips/readme.txt b/plugins/bible-reference-tooltips/readme.txt index 069f4c5..3600798 100644 --- a/plugins/bible-reference-tooltips/readme.txt +++ b/plugins/bible-reference-tooltips/readme.txt @@ -4,7 +4,7 @@ Tags: bible, scripture, references, tooltips, verses Requires at least: 6.0 Tested up to: 7.0.1 Requires PHP: 7.4 -Stable tag: 1.1.5 +Stable tag: 1.1.6 License: GPLv2 or later License URI: https://www.gnu.org/licenses/gpl-2.0.html @@ -49,6 +49,12 @@ Yes. The plugin is standalone and appears under Settings in the WordPress admin. == Changelog == += 1.1.6 = + +* Centralized Bible book aliases and eBible source-code interpretation into one registry. +* Added an admin text-integrity panel for installed Bible book coverage. +* Expanded smoke-test coverage for source-code normalization, human reference aliases, and compact references. + = 1.1.5 = * Added the public workspace conventions and tracked Docker test lab as the bounded release workflow. diff --git a/tools/testlab/README.md b/tools/testlab/README.md index 524a7d4..6b87bd7 100644 --- a/tools/testlab/README.md +++ b/tools/testlab/README.md @@ -6,14 +6,13 @@ The lab mounts plugin source from this workspace into disposable WordPress conta ## Environments -Initial matrix: +Default matrix: | Environment | WordPress Image | PHP | Database | | --- | --- | --- | --- | | `wp7-php84` | `wordpress:php8.4-apache` | 8.4 | MariaDB 11 | -| `wp6-php74` | `wordpress:php7.4-apache` with WP `6.8.2` download | 7.4 | MariaDB 10.6 | -The `wp7-php84` image installs the latest WordPress available in the image line. The `wp6-php74` environment uses the available PHP 7.4 WordPress image, then forces a WordPress 6.8.2 core download before install. The test script records the actual WordPress version after install. +The `wp7-php84` image installs the latest WordPress available in the image line. Legacy WordPress/PHP environments should be added only for an explicit compatibility pass, not as part of the default bounded release gate. ## Commands diff --git a/tools/testlab/config/environments.json b/tools/testlab/config/environments.json index 4822279..0bab0c7 100644 --- a/tools/testlab/config/environments.json +++ b/tools/testlab/config/environments.json @@ -4,12 +4,5 @@ "wordpressImage": "wordpress:php8.4-apache", "dbImage": "mariadb:11", "hostPort": 8070 - }, - { - "name": "wp6-php74", - "wordpressImage": "wordpress:php7.4-apache", - "dbImage": "mariadb:10.6", - "hostPort": 8068, - "wordpressVersion": "6.8.2" } ] diff --git a/tools/testlab/results/wp6-php74.json b/tools/testlab/results/wp6-php74.json deleted file mode 100644 index e88d697..0000000 --- a/tools/testlab/results/wp6-php74.json +++ /dev/null @@ -1,149 +0,0 @@ -{ - "environment": "wp6-php74", - "wordpressImage": "wordpress:php7.4-apache", - "dbImage": "mariadb:10.6", - "hostPort": 8068, - "startedAt": "2026-07-11T19:49:33.8231872-05:00", - "checks": [ - { - "name": "wp-cli available", - "passed": true, - "detail": "" - }, - { - "name": "wordpress core version prepared", - "passed": true, - "detail": "target=6.8.2" - }, - { - "name": "wordpress installed", - "passed": true, - "detail": "installed" - }, - { - "name": "runtime versions", - "passed": true, - "detail": "WP=6.8.2 PHP=7.4.33" - }, - { - "name": "plugin activated", - "passed": true, - "detail": "" - }, - { - "name": "plugin version detected", - "passed": true, - "detail": "version=1.1.5" - }, - { - "name": "verse table created", - "passed": true, - "detail": "wp_brt_verses" - }, - { - "name": "WEB import completed", - "passed": true, - "detail": "WEB import complete: 36,601 verses installed." - }, - { - "name": "KJV import completed", - "passed": true, - "detail": "KJV import complete: 35,948 verses installed." - }, - { - "name": "ASV import completed", - "passed": true, - "detail": "ASV import complete: 31,086 verses installed." - }, - { - "name": "YLT import completed", - "passed": true, - "detail": "YLT import complete: 31,102 verses installed." - }, - { - "name": "translation rows stored", - "passed": true, - "detail": "[{\"translation\":\"ASV\",\"row_count\":\"31086\"},{\"translation\":\"KJV\",\"row_count\":\"35948\"},{\"translation\":\"WEB\",\"row_count\":\"36601\"},{\"translation\":\"YLT\",\"row_count\":\"31102\"}]" - }, - { - "name": "canonical book coverage", - "passed": true, - "detail": "ok" - }, - { - "name": "REST lookup John 3:16", - "passed": true, - "detail": "ok" - }, - { - "name": "REST lookup John 3.16", - "passed": true, - "detail": "ok" - }, - { - "name": "REST lookup Jn3:16", - "passed": true, - "detail": "ok" - }, - { - "name": "REST lookup Romans 8:28", - "passed": true, - "detail": "ok" - }, - { - "name": "REST lookup James 1:5", - "passed": true, - "detail": "ok" - }, - { - "name": "REST lookup Mark 10:45", - "passed": true, - "detail": "ok" - }, - { - "name": "REST lookup Mark10:45", - "passed": true, - "detail": "ok" - }, - { - "name": "REST lookup Mk 10:45", - "passed": true, - "detail": "ok" - }, - { - "name": "REST lookup Ezekiel 36:26", - "passed": true, - "detail": "ok" - }, - { - "name": "REST lookup Eze 36:26", - "passed": true, - "detail": "ok" - }, - { - "name": "REST lookup 2 John 1:6", - "passed": true, - "detail": "ok" - }, - { - "name": "REST lookup 2Jn1:6", - "passed": true, - "detail": "ok" - }, - { - "name": "REST lookup 2 Jo 1:6", - "passed": true, - "detail": "ok" - }, - { - "name": "test post created", - "passed": true, - "detail": "" - } - ], - "phpVersion": "7.4.33", - "wordpressVersion": "6.8.2", - "pluginVersion": "1.1.5", - "completedAt": "2026-07-11T19:52:42.5557675-05:00", - "passed": true -} diff --git a/tools/testlab/results/wp7-php84.json b/tools/testlab/results/wp7-php84.json index 703a476..33a0c4a 100644 --- a/tools/testlab/results/wp7-php84.json +++ b/tools/testlab/results/wp7-php84.json @@ -3,7 +3,7 @@ "wordpressImage": "wordpress:php8.4-apache", "dbImage": "mariadb:11", "hostPort": 8070, - "startedAt": "2026-07-11T19:46:20.2262126-05:00", + "startedAt": "2026-07-11T20:12:33.4678261-05:00", "checks": [ { "name": "wp-cli available", @@ -28,13 +28,18 @@ { "name": "plugin version detected", "passed": true, - "detail": "version=1.1.5" + "detail": "version=1.1.6" }, { "name": "verse table created", "passed": true, "detail": "wp_brt_verses" }, + { + "name": "interpretation registry", + "passed": true, + "detail": "ok" + }, { "name": "WEB import completed", "passed": true, @@ -90,6 +95,16 @@ "passed": true, "detail": "ok" }, + { + "name": "REST lookup Jas 1:5", + "passed": true, + "detail": "ok" + }, + { + "name": "REST lookup Jm 1:5", + "passed": true, + "detail": "ok" + }, { "name": "REST lookup Mark 10:45", "passed": true, @@ -105,6 +120,11 @@ "passed": true, "detail": "ok" }, + { + "name": "REST lookup Mar 10:45", + "passed": true, + "detail": "ok" + }, { "name": "REST lookup Ezekiel 36:26", "passed": true, @@ -138,7 +158,7 @@ ], "phpVersion": "8.4.23", "wordpressVersion": "7.0.1", - "pluginVersion": "1.1.5", - "completedAt": "2026-07-11T19:49:33.7883010-05:00", + "pluginVersion": "1.1.6", + "completedAt": "2026-07-11T20:16:05.3978156-05:00", "passed": true } diff --git a/tools/testlab/scripts/common.ps1 b/tools/testlab/scripts/common.ps1 index 53170eb..97f6db0 100644 --- a/tools/testlab/scripts/common.ps1 +++ b/tools/testlab/scripts/common.ps1 @@ -7,7 +7,7 @@ $GeneratedRoot = Join-Path $LabRoot 'generated' $ResultsRoot = Join-Path $LabRoot 'results' $PluginSource = Join-Path $WorkspaceRoot 'plugins\bible-reference-tooltips' $PluginSlug = 'bible-reference-tooltips' -$ExpectedPluginVersion = '1.1.5' +$ExpectedPluginVersion = '1.1.6' function Get-TestLabEnvironments { Get-Content -LiteralPath $ConfigPath -Raw | ConvertFrom-Json diff --git a/tools/testlab/scripts/run-env.ps1 b/tools/testlab/scripts/run-env.ps1 index 7121464..7573ab7 100644 --- a/tools/testlab/scripts/run-env.ps1 +++ b/tools/testlab/scripts/run-env.ps1 @@ -80,6 +80,48 @@ echo $wpdb->get_var($wpdb->prepare('SHOW TABLES LIKE %s', $wpdb->prefix . 'brt_v $tableExists = (Invoke-WpCli $environment 'wp eval-file /tmp/brt-table.php --path=/var/www/html' | Out-String).Trim() Add-Check 'verse table created' ($tableExists -eq 'wp_brt_verses') $tableExists + $interpretationPhp = @' +getMethod($method); + $m->setAccessible(true); + return $m->invokeArgs($plugin, $args); +}; +$checks = []; +foreach ([ + ['parse_reference', 'James 1:5', 'JAS'], + ['parse_reference', 'Jas 1:5', 'JAS'], + ['parse_reference', 'Jm 1:5', 'JAS'], + ['parse_reference', 'Mark10:45', 'MRK'], + ['parse_reference', '2Jn1:6', '2JN'], + ['parse_reference', 'Eze 36:26', 'EZK'], +] as $case) { + $parsed = $call($case[0], $case[1]); + if (!$parsed || $parsed['book'] !== $case[2]) $checks[] = $case[1] . '=>' . json_encode($parsed); +} +foreach ([ + ['EZE 36:26 source', 'EZE', 'EZK'], + ['MAR 10:45 source', 'MAR', 'MRK'], + ['JOH 3:16 source', 'JOH', 'JHN'], + ['JAM 1:5 source', 'JAM', 'JAS'], + ['1JO 1:9 source', '1JO', '1JN'], +] as $case) { + $book = $call('normalize_source_book', $case[1], 'ebible_vpl'); + if (!$book || $book['abbr'] !== $case[2]) $checks[] = $case[0] . '=>' . json_encode($book); +} +$aliases = $call('frontend_book_alias_patterns'); +$alias_keys = array_map('strtolower', $aliases); +foreach (['James', 'Jm', 'Eze', 'Mar', '2\\s*Jn'] as $needle) { + if (!in_array(strtolower($needle), $alias_keys, true)) $checks[] = 'missing frontend alias ' . $needle; +} +echo $checks ? json_encode($checks) : 'ok'; +'@ + Write-ContainerPhpFile $environment '/tmp/brt-interpretation.php' $interpretationPhp + $interpretation = (Invoke-WpCli $environment 'wp eval-file /tmp/brt-interpretation.php --path=/var/www/html' | Out-String).Trim() + Add-Check 'interpretation registry' ($interpretation -eq 'ok') $interpretation + $translationsToImport = @('WEB', 'KJV', 'ASV', 'YLT') foreach ($translationCode in $translationsToImport) { $importPhp = @" @@ -126,7 +168,7 @@ echo $missing ? json_encode($missing) : 'ok'; $bookCoverage = (Invoke-WpCli $environment 'wp eval-file /tmp/brt-book-coverage.php --path=/var/www/html' | Out-String).Trim() Add-Check 'canonical book coverage' ($bookCoverage -eq 'ok') $bookCoverage - $refs = @('John 3:16', 'John 3.16', 'Jn3:16', 'Romans 8:28', 'James 1:5', 'Mark 10:45', 'Mark10:45', 'Mk 10:45', 'Ezekiel 36:26', 'Eze 36:26', '2 John 1:6', '2Jn1:6', '2 Jo 1:6') + $refs = @('John 3:16', 'John 3.16', 'Jn3:16', 'Romans 8:28', 'James 1:5', 'Jas 1:5', 'Jm 1:5', 'Mark 10:45', 'Mark10:45', 'Mk 10:45', 'Mar 10:45', 'Ezekiel 36:26', 'Eze 36:26', '2 John 1:6', '2Jn1:6', '2 Jo 1:6') foreach ($ref in $refs) { $lookupPhp = @"