FF7-guiden migrerad till Astro - Första steget mot modern arkitektur

ffuniversewebbutveckling

Idag tar vi ett stort steg i migrationen av FFU till modern arkitektur - FF7-guiden är nu fullständigt migrerad från WordPress till Astro! Detta är inte bara ett tekniskt genombrott, utan också blueprint:en för hur vi kommer att migrera alla våra 21 andra spelguider framöver.

En milstolpe i migreringsarbetet

FF7-guiden har alltid varit vår största och mest komplexa guide. Med 190 sidor, 350 bilder, och 7 olika sidmallar (templates) har den varit det perfekta testfallet för att bygga upp en robust migrations-pipeline. Om vi kan migrera FF7, kan vi migrera allt!

Siffrorna bakom migrationen

Låt oss börja med lite imponerande statistik:

  • 190 sidor migrerade från WordPress XML-export
  • 350 bilder kopierade och organiserade
  • 34 draft-bossar konsoliderade in i 16 parent-boss-sidor
  • 281 totala sidor byggda (inklusive övriga delar av sajten)
  • Byggtid: 2.16 sekunder

Ja, du läste rätt - hela sajten byggs på drygt två sekunder. Det kan jämföras med WordPress som ofta tar flera sekunder bara för att ladda en sida.

De sju mallarna

En av de stora utmaningarna var att hantera FF7-guidens sju olika sidmallar som användes i WordPress:

1. Boss-mallen

Den mest komplexa mallen med stöd för boss-statistik (HP, MP, Level, Svagheter, etc.) och “related bosses”. När vi möter t.ex. Rufus i spelet slåss vi först mot hans hund Dark Nation. I WordPress hade vi detta som två separata sidor - en published för Rufus och en draft för Dark Nation. I Astro-versionen konsoliderade vi detta smart: Dark Nation är nu inkluderad direkt i Rufus-sidan som en “related boss”, vilket ger en mycket bättre användarupplevelse.

---
title: "Rufus"
template: boss
hp: "500"
mp: "0"
level: "21"
relatedBosses:
  - name: "Dark Nation"
    hp: "140"
    mp: "80"
    level: "18"
---

2-4. Karaktärs-mallarna

Tre varianter (boxes, onebox, simple) för olika typer av karaktärsidor. Alla bevarar WordPress-guidens struktur med svenskspråkiga fält som “ålder”, “längd_i_cm”, “vikt_i_kg”, “hemstad”, “yrke”, “födelsedag”, och “vapen”. Det var viktigt för oss att behålla exakt samma struktur - både för att bevara historiken och för att data ska vara konsekvent.

5. AnchorMenu-mallen

Automatgenererar en innehållsförteckning från sidans H2-rubriker. Perfekt för långa listor som “Alla Limits” eller “Enemy Skills”. Innehållsförteckningen får sticky positioning och följer med när man scrollar.

6. ChildList-mallen

Föräldrasidor som automatiskt listar alla sina undersidor i ett rutnät. Använder menuOrder för kronologisk sortering och visar coverImage som thumbnail.

7. Default-mallen

Standard-mallen för vanliga innehållssidor.

Den tekniska lösningen

XML-parsern med PHP-deserialisering

En av de tuffaste utmaningarna var att hantera WordPress Advanced Custom Fields (ACF) data. ACF sparar komplexa fält som serialiserad PHP i XML:en, inklusive arrays och objekt. Vi byggde en komplett PHP-deserializer i JavaScript som kan hantera:

a:3:{i:0;s:4:"1234";i:1;s:4:"5678";i:2;s:4:"9012";}

Detta var kritiskt för att kunna extrahera “partof”-relationer mellan bossar. När Dark Nation hade partof: ["1234"] där 1234 var Rufus post-ID, kunde vi automatiskt konsolidera dem.

Bildhantering

350 bilder flyttades från en hierarkisk WordPress-struktur till en flat struktur under public/images/ff7/. Vi skrev sedan batch-script för att uppdatera alla bildreferenser i markdown:

find src/content/ff7Pages -name "*.md" -type f -exec sed -i '' 's|!\[\](images/|![](/images/ff7/|g' {} \;

Hierarkisk routing med catch-all

URL-strukturen bevarades exakt från WordPress. En sida som bossar/rufus blev src/content/ff7Pages/bossar/rufus.md och får URL:en /guide/ff7/bossar/rufus/. Vi använder Astro’s catch-all route [...slug].astro för att hantera alla nivåer av nesting.

Layout-system med conditional rendering

Varje sida har ett template-fält i frontmatter. I den dynamiska routen läser vi detta och renderar rätt layout:

{template === 'boss' ? (
  <BossPageLayout {...layoutProps}>
    <Content />
  </BossPageLayout>
) : template === 'character-boxes' ? (
  <CharacterPageLayout {...layoutProps} variant="boxes">
    <Content />
  </CharacterPageLayout>
) : ...}

Svenskspråkiga fält bevarade

Ett viktigt mål var att bevara alla originalfält från WordPress, inklusive de svenskspråkiga. Det ger oss historisk kontinuitet och gör framtida migrationer enklare. Här är ett exempel på boss-frontmatter:

---
title: "Rufus"
hp: "500"
mp: "0"
level: "21"
svagheter: "Inga"
stark_mot: "-"
rekommenderad_lvl: "18"
drop: "Protect Vest"
steal: "Guard Source"
exp: "960"
gil: "2400"
---

Och för karaktärer:

---
title: "Cloud Strife"
ålder: "21"
langd_i_cm: "173"
vikt_i_kg: "?"
kon: "Man"
hemstad: "Nibelheim"
yrke: "Ex-SOLDIER"
fodelsedag: "11 augusti"
vapen: "Svärd"
spelbar_karaktar: true
---

Content Collections är nyckeln

Astro’s content collections-system har varit avgörande. Vi definierar ett schema för alla FF7-sidor som validerar all data vid byggtid:

const ff7Pages = defineCollection({
  type: 'content',
  schema: z.object({
    title: z.string(),
    template: z.enum(['boss', 'character-boxes', 'character-onebox', 
                      'character-simple', 'anchormenu', 'childlist', 'default']),
    parent: z.string().optional(),
    menuOrder: z.number().optional(),
    
    // Boss fields
    hp: z.string().optional(),
    mp: z.string().optional(),
    level: z.string().optional(),
    svagheter: z.string().optional(),
    relatedBosses: z.array(z.object({
      name: z.string(),
      hp: z.string().optional(),
      // ... more fields
    })).optional(),
    
    // Character fields
    ålder: z.string().optional(),
    langd_i_cm: z.string().optional(),
    // ... 15+ more Swedish fields
  }),
});

Detta ger oss TypeScript-autocompletions, build-time validering, och säkerhet att all data är korrekt strukturerad.

Vad händer härnäst?

Med FF7-guiden migrerad har vi nu en beprövad migrations-pipeline som vi kan applicera på alla andra guider:

  1. FF7 - 190 sidor, 7 mallar → KLART!
  2. 🔜 FF8 - Liknande struktur som FF7, ca 150 sidor
  3. 🔜 FF9 - Medium komplexitet, ca 120 sidor
  4. 🔜 FF10 - Stor guide med många bilder
  5. … och så vidare för alla 21 guider

Blueprint för framtida migrationer

FF7-migrationen etablerar mönstret:

  1. Exportera WordPress XML
  2. Analysera alla PHP-mallar och ACF-fält
  3. Skapa Astro layouts som matchar originalet
  4. Bygg parser med PHP-deserialisering
  5. Generera markdown med komplett frontmatter
  6. Kopiera och organisera bilder
  7. Implementera dynamisk routing
  8. Testa alla malltyper
  9. Validera URL-struktur bevarad

Teknisk stack sammanfattning

  • Astro 5.16.16 - Ramverk för innehållsrika sajter
  • Content Collections - Type-safe content management
  • Node.js med xml2js - XML-parsing
  • Custom PHP deserializer - ACF-data extraktion
  • Catch-all routing - Hierarkisk URL-struktur
  • TypeScript - Type safety
  • Zod - Schema validering
  • Markdown + YAML frontmatter - Content format

Resultat

Migrationen är produktionsklar! Vi har verifierat:

  • ✅ Alla 7 malltyper renderar korrekt
  • ✅ Boss-sidor visar stats + related bosses
  • ✅ Karaktärs-sidor har alla varianter
  • ✅ URL-struktur bevarad från WordPress
  • ✅ Parent/child-relationer fungerar
  • ✅ Alla 350 bilder laddas korrekt
  • ✅ MenuOrder-sortering bevarad
  • ✅ Build på 2.16 sekunder

Framåt och uppåt! 🚀

Detta är början på något stort. Med FF7-guiden som blueprint har vi visat att det är fullt möjligt att migrera hela FFUniverse-nätverket till modern arkitektur. Varje guide vi migrerar gör nästa enklare eftersom vi kan återanvända layouts, komponenter, och parser-logik.

Nästa steg är att börja med FF8-guiden som har liknande struktur. Vi räknar med att kunna öka takten rejält nu när vi har ett beprövat system.

Håll utkik för fler uppdateringar här på bloggen!