diff --git a/common-docs/content/_index.md b/common-docs/content/_index.md
index 6d75a9ab7..4d09bdd89 100644
--- a/common-docs/content/_index.md
+++ b/common-docs/content/_index.md
@@ -1,6 +1,6 @@
+++
title="Help us doc!"
description="This is a [π
·ππ
Άπ
Ύ](https://gohugo.io/)-based platform called [π±common](https://github.com/CodeYourFuture/curriculum/tree/main/common-theme)"
-map=["theme", "content", "community"]
+menus_to_map=["theme", "content", "community"]
menu=["syllabus"]
+++
diff --git a/common-docs/content/common-theme/front-matter/_index.md b/common-docs/content/common-theme/front-matter/_index.md
index fe89c9a7d..f6d8ea565 100644
--- a/common-docs/content/common-theme/front-matter/_index.md
+++ b/common-docs/content/common-theme/front-matter/_index.md
@@ -20,8 +20,11 @@ src="common-theme/front-matter/blocks/blocks"
name="Emoji"
src="common-theme/front-matter/blocks/emoji"
[[blocks]]
-name="Map"
-src="common-theme/front-matter/blocks/map"
+name="Taxonomy map"
+src="common-theme/front-matter/blocks/taxonomy-map"
+[[blocks]]
+name="Menu map"
+src="common-theme/front-matter/blocks/menu-map"
[[blocks]]
name="Menus, menu_level"
src="common-theme/front-matter/blocks/menu"
diff --git a/common-docs/content/common-theme/front-matter/blocks/map/index.md b/common-docs/content/common-theme/front-matter/blocks/map/index.md
index 5f4a250ad..e69de29bb 100644
--- a/common-docs/content/common-theme/front-matter/blocks/map/index.md
+++ b/common-docs/content/common-theme/front-matter/blocks/map/index.md
@@ -1,17 +0,0 @@
-+++
-title = 'Map'
-time = 2
-emoji= 'πΊοΈ'
-[build]
- render = 'never'
- list = 'local'
- publishResources = false
-+++
-
-A map is an ordered slice of menus. It's to show a "map" view of the syllabus, broken down into grouped modules. As with everything in this design, the point is to clarify what happens and in what order.
-
-It's just for the index page, and the front matter is a list of the menu names that should be included in the map, in the order they should appear.
-
-```toml
-map = ["menuName", "menuName"]
-```
diff --git a/common-docs/content/common-theme/front-matter/blocks/menu-map/index.md b/common-docs/content/common-theme/front-matter/blocks/menu-map/index.md
new file mode 100644
index 000000000..3f581bbd1
--- /dev/null
+++ b/common-docs/content/common-theme/front-matter/blocks/menu-map/index.md
@@ -0,0 +1,19 @@
++++
+title = 'Menu map'
+time = 2
+emoji= 'πΊοΈ'
+[build]
+ render = 'never'
+ list = 'local'
+ publishResources = false
++++
+
+A menu map is an ordered slice of menus. It's to show a "map" view of the syllabus, broken down into grouped modules. As with everything in this design, the point is to clarify what happens and in what order.
+
+It's just for the index page, and the front matter is a list of the menu names that should be included in the map, in the order they should appear.
+
+If you want to attach metadata to each menu item (e.g. to add a description), you probably want a Taxonomy map.
+
+```toml
+menus_to_map = ["menuName", "menuName"]
+```
diff --git a/common-docs/content/common-theme/front-matter/blocks/taxonomy-map/index.md b/common-docs/content/common-theme/front-matter/blocks/taxonomy-map/index.md
new file mode 100644
index 000000000..79439f906
--- /dev/null
+++ b/common-docs/content/common-theme/front-matter/blocks/taxonomy-map/index.md
@@ -0,0 +1,17 @@
++++
+title = 'Taxonomy map'
+time = 2
+emoji= 'πΊοΈ'
+[build]
+ render = 'never'
+ list = 'local'
+ publishResources = false
++++
+
+A taxonomy map is an ordered slice of terms within a taxonomy. It's to show a "map" view of the syllabus, broken down into grouped modules, with extra per-module metadata attached to the term. As with everything in this design, the point is to clarify what happens and in what order.
+
+It's just for the index page, and the front matter is a list of the menu names that should be included in the map, in the order they should appear.
+
+```toml
+taxonomy_to_map = "modules"
+```
diff --git a/common-theme/layouts/index.html b/common-theme/layouts/index.html
index 2589c97be..01d585cbe 100644
--- a/common-theme/layouts/index.html
+++ b/common-theme/layouts/index.html
@@ -9,8 +9,12 @@
{{ . }}
{{ end }}
- {{ if .Params.map }}
+ {{ if .Params.menus_to_map }}
+ {{ partial "map-menu.html" .Params.menus_to_map }}
+ {{ else if .Params.map }}
{{ partial "map.html" . }}
+ {{ else if .Params.taxonomy_to_map }}
+ {{ partial "map-taxonomy.html" .Params.taxonomy_to_map }}
{{ else }}
{{- range site.Menus.syllabus }}
diff --git a/common-theme/layouts/partials/card.html b/common-theme/layouts/partials/card.html
index 5e57f0dbc..328186ad9 100644
--- a/common-theme/layouts/partials/card.html
+++ b/common-theme/layouts/partials/card.html
@@ -1,5 +1,5 @@
{{ $BaseURL := .Page.Parent.Permalink }}
-
+
{{ .Name }}
{{ with .Page.Description }}
{{ . }}
diff --git a/common-theme/layouts/partials/map-common.html b/common-theme/layouts/partials/map-common.html
new file mode 100644
index 000000000..d14b96ec8
--- /dev/null
+++ b/common-theme/layouts/partials/map-common.html
@@ -0,0 +1,34 @@
+{{/*
+Expects a slice[dict] param containing an ordered list of dicts with the following keys, one per section in the map to render:
+* title (string) - The heading to display for the section.
+* values (slice[Page]) - A slice of Pages, one per page in the section which should be listed.
+*/}}
+
+
+
ππΎ
+{{ range $i, $section := index . "sections" }}
+ {{ $sectionTitle := index $section "title" }}
+ {{ $sectionValues := index $section "values" }}
+
+
+ π{{ $i }}:
+ {{ $sectionTitle }}
+
+
+ {{/* Check if a menu for the current map section exists */}}
+ {{ if $sectionValues }}
+ {{/* Range over the items in the menu */}}
+ {{ range $iterator, $module := $sectionValues }}
+ -
+ {{ partial "card.html" $module }}
+
+ {{ end }}
+ {{ else }}
+ - No items found for {{ $sectionTitle }}
+ {{ end }}
+
+
+{{ end }}
+
diff --git a/common-theme/layouts/partials/map-menu.html b/common-theme/layouts/partials/map-menu.html
new file mode 100644
index 000000000..66610f94c
--- /dev/null
+++ b/common-theme/layouts/partials/map-menu.html
@@ -0,0 +1,12 @@
+{{/* Expects slice[string] param which is the name of the menus to render as sections. */}}
+
+{{ $sections := slice }}
+
+{{ range $menuName := . }}
+ {{ $section := dict "title" $menuName "values" (index site.Menus $menuName) }}
+ {{ $sections = append $section $sections }}
+{{ end }}
+
+{{ $params := dict "sections" $sections }}
+
+{{ partial "map-common.html" $params }}
diff --git a/common-theme/layouts/partials/map-taxonomy.html b/common-theme/layouts/partials/map-taxonomy.html
new file mode 100644
index 000000000..decfe8ceb
--- /dev/null
+++ b/common-theme/layouts/partials/map-taxonomy.html
@@ -0,0 +1,20 @@
+{{/* Expects string param which is the (plural) name of the taxonomy to render. */}}
+
+{{ $taxonomy_to_map := . }}
+
+{{ $sections := slice }}
+
+{{/* You can't ask for a taxonomy to be sorted by weight, so we need to get weights and iterate ourselves - see https://discourse.gohugo.io/t/list-custom-taxonomy-terms-in-a-specific-order-not-alphabetical/18145/5 */}}
+{{ $terms := site.GetPage (printf "/%s" $taxonomy_to_map) }}
+{{ range $termPage := $terms.Pages.ByWeight }}
+ {{ $termID := path.BaseName $termPage.Path }}
+ {{ $termTitle := $termPage.Title }}
+ {{ $values := index (index site.Taxonomies $taxonomy_to_map) $termID }}
+
+ {{ $section := dict "title" $termTitle "values" $values }}
+ {{ $sections = append $section $sections }}
+{{ end }}
+
+{{ $params := dict "sections" $sections }}
+
+{{ partial "map-common.html" $params }}
diff --git a/common-theme/layouts/partials/map.html b/common-theme/layouts/partials/map.html
index 004835227..0c09f1087 100644
--- a/common-theme/layouts/partials/map.html
+++ b/common-theme/layouts/partials/map.html
@@ -1,29 +1,5 @@
-{{ with .Params.map }}
-
-
ππΎ
- {{ range $i, $currentMapSectionName := . }}
- {{ $currentMapSectionModules := index site.Menus $currentMapSectionName }}
-
-
- π{{ $i }}:
- {{ $currentMapSectionName }}
-
-
- {{/* Check if a menu for the current map section exists */}}
- {{ if $currentMapSectionModules }}
- {{/* Range over the items in the menu */}}
- {{ range $iterator, $module := $currentMapSectionModules }}
- -
- {{ partial "card.html" $module }}
-
- {{ end }}
- {{ else }}
- - No items found for {{ $currentMapSectionName }}
- {{ end }}
-
-
- {{ end }}
-
-{{ end }}
+{{/* Expects Page as a param, and that the page will have a .Params.map which contains a slice[string] of menus to render as sections. */}}
+
+{{/* This is legacy support which we will deprecate at some point. */}}
+{{ warnf "Using the map param is deprecated - rename this param to menus_to_map" }}
+{{ partial "map-menu.html" .Params.map }}
diff --git a/org-cyf-guides/content/_index.md b/org-cyf-guides/content/_index.md
index 087331969..bee2b444b 100644
--- a/org-cyf-guides/content/_index.md
+++ b/org-cyf-guides/content/_index.md
@@ -4,5 +4,5 @@ description = 'A collection of guides, references, resources that do not belong
emoji= 'π'
menu=["syllabus"]
weight=1
-map=['volunteers', 'learners', 'everyone']
+menus_to_map=['volunteers', 'learners', 'everyone']
+++
diff --git a/org-cyf-guides/content/contributing/minutes/index.md b/org-cyf-guides/content/contributing/minutes/index.md
index 2d4ac9be1..fa8b9db4c 100644
--- a/org-cyf-guides/content/contributing/minutes/index.md
+++ b/org-cyf-guides/content/contributing/minutes/index.md
@@ -104,7 +104,7 @@ Some things that came up:
* Unclear what the balance will be of the slower folks between "need a bit of extra time to get going" vs "just need a bit more time for everything" vs "not actually getting things".
* People re-taking the course seem to be thriving - getting the culture, reviewing code, etc.
* Fundamentals was really useful at culture-setting, we probably want to try re-framing the first ITP module as fundamentals.
-* Sally wants to release the curriculum platform with the DPG team in December.
+* Sally wants to release the curriculum platform with the [DPG](https://github.com/dpgalliance) [team](https://github.com/orgs/CodeYourFuture/teams/dpg-team) in December.
### βActions
diff --git a/org-cyf-itd/content/_index.md b/org-cyf-itd/content/_index.md
index ec9d29927..57ec627ab 100644
--- a/org-cyf-itd/content/_index.md
+++ b/org-cyf-itd/content/_index.md
@@ -2,5 +2,5 @@
title="Intro to Digital"
description="How to participate in the Intro to Digital programme as a learner or teacher"
menu="main"
-map=['start here', 'steps', 'workshops']
+menus_to_map=['start here', 'steps', 'workshops']
+++
diff --git a/org-cyf-itp/content/_index.md b/org-cyf-itp/content/_index.md
index d996435a5..43c943bac 100644
--- a/org-cyf-itp/content/_index.md
+++ b/org-cyf-itp/content/_index.md
@@ -1,6 +1,6 @@
+++
title="Intro to Programming"
-map=["start here", "programming", "next steps"]
+menus_to_map=["start here", "programming", "next steps"]
description="New? Lost? [Quickstart](how-this-works/prep/#overview)"
emoji= "π§πΏβπ«"
+++
diff --git a/org-cyf-piscine/content/_index.md b/org-cyf-piscine/content/_index.md
index 910d7a577..aaabe0705 100644
--- a/org-cyf-piscine/content/_index.md
+++ b/org-cyf-piscine/content/_index.md
@@ -4,5 +4,5 @@ description = 'In teams and on your own, build working software with tests. Expl
layout = 'module'
emoji= 'π '
menu = ['syllabus', 'next steps']
-map=['entry', 'sprints', 'assessment']
+menus_to_map=['entry', 'sprints', 'assessment']
+++
diff --git a/org-cyf-sdc/content/_index.md b/org-cyf-sdc/content/_index.md
index 3ea959ab3..64cdedafc 100644
--- a/org-cyf-sdc/content/_index.md
+++ b/org-cyf-sdc/content/_index.md
@@ -1,6 +1,6 @@
+++
title="Software Development Course"
-map=["start here", "SDC", "tracks"]
+menus_to_map=["start here", "SDC", "tracks"]
description="Alert: this course is not yet available. Content is incomplete."
emoji= "π§πΎβπ§"
+++
diff --git a/org-cyf-tracks/content/_index.md b/org-cyf-tracks/content/_index.md
index 3cf6881a0..0e3156dd5 100644
--- a/org-cyf-tracks/content/_index.md
+++ b/org-cyf-tracks/content/_index.md
@@ -1,6 +1,6 @@
+++
title="Tracks"
-map=["start here", "from itp", "from sdc"]
+taxonomy_to_map = "track_kinds"
description="Short, focused courses walking you towards specific careers"
emoji= "π£"
+++
diff --git a/org-cyf-tracks/content/cloud/_index.md b/org-cyf-tracks/content/cloud/_index.md
index c14e641ac..410852d37 100644
--- a/org-cyf-tracks/content/cloud/_index.md
+++ b/org-cyf-tracks/content/cloud/_index.md
@@ -3,5 +3,5 @@ title = 'Cloud'
description = 'Deploy and manage cloud infrastructure; explore containers, pipelines, load balancing, traffic, integration and security; define infrastructure as code'
layout = 'module'
emoji= 'βοΈ'
-menu = 'from sdc'
+track_kinds = ["jobs-after-sdc"]
+++
diff --git a/org-cyf-tracks/content/coming-soon/_index.md b/org-cyf-tracks/content/coming-soon/_index.md
index 03c0088fd..6c71a02a1 100644
--- a/org-cyf-tracks/content/coming-soon/_index.md
+++ b/org-cyf-tracks/content/coming-soon/_index.md
@@ -3,7 +3,7 @@ title = 'Coming Soon'
description = 'ITP tracks are coming soon...'
layout = 'module'
emoji= 'π·π½ββοΈ'
-menu = "from itp"
+track_kinds = ["jobs-after-itp"]
+++
## In development:
diff --git a/org-cyf-tracks/content/portfolio/_index.md b/org-cyf-tracks/content/portfolio/_index.md
index 5c5da0fc2..fae1f9f0f 100644
--- a/org-cyf-tracks/content/portfolio/_index.md
+++ b/org-cyf-tracks/content/portfolio/_index.md
@@ -3,5 +3,5 @@ title = 'Portfolio'
description = 'Build great projects; work in teams; polish our profiles; get great jobs in tech'
layout = 'module'
emoji= 'π§πΎβπ'
-menu = 'from sdc'
+track_kinds = ["jobs-after-sdc"]
+++
diff --git a/org-cyf-tracks/content/react/_index.md b/org-cyf-tracks/content/react/_index.md
index aa3d15e0b..3fb1c13d5 100644
--- a/org-cyf-tracks/content/react/_index.md
+++ b/org-cyf-tracks/content/react/_index.md
@@ -3,6 +3,6 @@ title = 'React'
description = 'Explore frameworks, libraries, and declarative programming with React; Develop unit testing with Testing Library; Build a dynamic web application in an Agile team'
layout = 'module'
emoji= 'πͺ'
-menu = 'from sdc'
+track_kinds = ["self-study"]
weight='6'
+++
diff --git a/org-cyf-tracks/content/track_kinds/jobs-after-itp/_index.md b/org-cyf-tracks/content/track_kinds/jobs-after-itp/_index.md
new file mode 100644
index 000000000..998bd08e8
--- /dev/null
+++ b/org-cyf-tracks/content/track_kinds/jobs-after-itp/_index.md
@@ -0,0 +1,4 @@
++++
+title = "Jobs after ITP"
+weight = 2
++++
diff --git a/org-cyf-tracks/content/track_kinds/jobs-after-sdc/_index.md b/org-cyf-tracks/content/track_kinds/jobs-after-sdc/_index.md
new file mode 100644
index 000000000..0559014e1
--- /dev/null
+++ b/org-cyf-tracks/content/track_kinds/jobs-after-sdc/_index.md
@@ -0,0 +1,4 @@
++++
+title = "Jobs after SDC"
+weight = 3
++++
diff --git a/org-cyf-tracks/content/track_kinds/self-study/_index.md b/org-cyf-tracks/content/track_kinds/self-study/_index.md
new file mode 100644
index 000000000..14db613ed
--- /dev/null
+++ b/org-cyf-tracks/content/track_kinds/self-study/_index.md
@@ -0,0 +1,4 @@
++++
+title = "Self-study"
+weight = 1
++++
diff --git a/org-cyf-tracks/hugo.toml b/org-cyf-tracks/hugo.toml
index 7b1336e03..dee1b1de5 100644
--- a/org-cyf-tracks/hugo.toml
+++ b/org-cyf-tracks/hugo.toml
@@ -20,3 +20,6 @@ baseURL = "https://tracks.codeyourfuture.io/"
[[module.imports.mounts]]
source = "content"
target = "content/how-this-works"
+
+[taxonomies]
+ track_kind = "track_kinds"
diff --git a/org-cyf/content/_index.md b/org-cyf/content/_index.md
index 258b269ec..7d1377801 100644
--- a/org-cyf/content/_index.md
+++ b/org-cyf/content/_index.md
@@ -1,6 +1,6 @@
+++
title="Our Courses"
-map=["start here", "selection", "trainees", "fellowships"]
+menus_to_map=["start here", "selection", "trainees", "fellowships"]
description="Free training for good jobs in tech [π
2024/25](https://docs.google.com/spreadsheets/d/1qNxf44_vbNKU1KeFozGX7Kt1QxmTtU6Bf9tOh1sTUuc/edit?gid=1346767713#gid=1346767713)"
emoji= "π§πΏβπ«π¨π½βπ"
+++