--[[ @Title: Migrate Census Family to Individual Events @Type: Standard @Author: Mike Tate @Contributors: @Version: 1.3 @Keywords: @LastUpdated: 05 Feb 2026 @Licence: This plugin is copyright (c) 2026 Mike Tate & contributors and is licensed under the MIT License which is hereby incorporated by reference (see https://pluginstore.family-historian.co.uk/fh-plugin-licence) @Description: Migrate Census (family) Events to Individual Census Events @V1.3: Handle fhCreateItem() error on invalid tag; fhInitialise(); @V1.2: Handle rich text notes and citation metafields; @V1.1: FH V7 Lua 3.5 IUP 3.28; @V1.0: Initial Plugin Store Version; ]] local strVersion = "1.3" if fhGetAppVersion() > 5 then fhSetStringEncoding("UTF-8") end -- Cater for FH V6 Unicode function CopyChildBranch(ptrSource,ptrTarget) local strTag = fhGetTag(ptrSource) if strTag == "_FMT" then return end -- Skip rich text format tag -- V1.2 if strTag == "_FIELD" then strTag = fhGetMetafieldShortcut(ptrSource) -- Handle citation metafield -- V1.2 end if strTag == "HUSB" or strTag == "WIFE" then return end -- Escape on invalid tag such as Family Census HUSB & WIFE -- V1.3 local ptrNew = fhCreateItem(strTag,ptrTarget,true) if ptrNew:IsNull() then return end -- Escape if item not created -- V1.2 fhSetValue_Copy(ptrNew,ptrSource) CopyChildren(ptrSource,ptrNew) return ptrNew end function CopyChildren(ptrSource,ptrTarget) local ptrFrom = ptrSource:Clone() ptrFrom:MoveToFirstChildItem(ptrFrom) while ptrFrom:IsNotNull() do CopyChildBranch(ptrFrom,ptrTarget) ptrFrom:MoveNext() end end function Main() local arrInd = {} -- Result Set tables arrInd[1] = {} arrInd[2] = {} local arrCen = {} arrCen[1] = {} arrCen[2] = {} local arrFam = {} local intFam = 0 local tblSpouse = { "~.HUSB[1]>", "~.WIFE[1]>", "~.HUSB[2]>", "~.WIFE[2]>" } local ptrRef = fhNewItemPtr() local ptrFam = fhNewItemPtr() ptrFam:MoveToFirstRecord("FAM") -- Loop through each Family Record while ptrFam:IsNotNull() do ptrRef:MoveTo(ptrFam,"~.CENS") -- Loop through each instance of each Census (family) Event while ptrRef:IsNotNull() do local intInd = 0 table.insert(arrFam,ptrFam:Clone()) for intRef, strRef in pairs(tblSpouse) do -- Find each Husband and Wife Individual local ptrInd = fhGetItemPtr(ptrFam,strRef) if ptrInd:IsNotNull() then local ptrNew = CopyChildBranch(ptrRef,ptrInd) -- Copy entire Census Event to each Individual intInd = intInd + 1 table.insert(arrInd[intInd],ptrInd:Clone()) table.insert(arrCen[intInd],ptrNew:Clone()) local strAge = strRef:gsub(">",".AGE") local ptrAge = fhGetItemPtr(ptrRef,strAge) -- Copy the Spouse Age to new Census Event if ptrAge:IsNotNull() then ptrNew = fhCreateItem("AGE",ptrNew) fhSetValue_Copy(ptrNew,ptrAge) end end end if intInd == 1 then table.insert(arrInd[2],fhNewItemPtr()) table.insert(arrCen[2],fhNewItemPtr()) end local ptrOld = ptrRef:Clone() ptrRef:MoveNext("SAME_TAG") local isOK = fhDeleteItem(ptrOld) -- Delete old Census (family) Event intFam = intFam + 1 end ptrFam:MoveNext() end if #arrFam > 0 then -- Output Result Set fhOutputResultSetTitles("Migrate Census Family to Individual Events "..strVersion) fhOutputResultSetColumn("Spouse 1","item",arrInd[1] ,#arrFam,120,"align_left") fhOutputResultSetColumn("Census 1","item",arrCen[1] ,#arrFam,100,"align_left") fhOutputResultSetColumn("Spouse 2","item",arrInd[2] ,#arrFam,120,"align_left") fhOutputResultSetColumn("Census 2","item",arrCen[2] ,#arrFam,100,"align_left") fhOutputResultSetColumn("Family" ,"item",arrFam ,#arrFam,200,"align_left") end if intFam > 0 then fhMessageBox("\n Migrated "..intFam.." Census (family) to Individual Events. \n\n Undo changes with 'Edit > Undo Plugin Updates' \n or 'File > Backup/Restore > Revert to Snapshot'.\n") else fhMessageBox("\n No Census (family) Events found. \n") end end fhInitialise(5,0,0,"save_recommended") -- V1.3 Main()