diff --git a/district/blocks.py b/district/blocks.py
index aaad95fa2f9918005d0263581a72ff34176ee4f2..469f09a0fef841b820f429df3ec0d6879ede1e6d 100644
--- a/district/blocks.py
+++ b/district/blocks.py
@@ -32,7 +32,6 @@ from shared.blocks import ProgramGroupBlockPopout as SharedProgramGroupBlockPopo
 from shared.blocks import ProgramItemBlock
 from shared.blocks import SecondaryCandidateBlock as SharedSecondaryCandidateBlockMixin
 
-
 # --- BEGIN New blocks ---
 
 
@@ -552,17 +551,23 @@ class CandidateSecondaryListBlock(SharedCandidateSecondaryListBlockMixin):
 class ProgramGroupWithCandidatesBlock(StructBlock):
     title = CharBlock(
         label="Název programu",
-        help_text="Např. 'Krajské volby 2024', 'Evropské volby 2024', ..."
+        help_text="Např. 'Krajské volby 2024', 'Evropské volby 2024', ...",
+    )
+
+    preamble_content = RichTextBlock(
+        label="Preambule",
+        help_text="Text, který se zobrazí před přepínačem mezi kandidáty a programem.",
+        required=False,
     )
 
     primary_candidates = CandidateListBlock(
         label="Osoby na čele kandidátky",
-        help_text="Zobrazí se ve velkých blocích na začátku stránky."
+        help_text="Zobrazí se ve velkých blocích na začátku stránky.",
     )
 
     secondary_candidates = CandidateSecondaryListBlock(
         label="Ostatní osoby na kandidátce",
-        help_text="Zobrazí se v kompaktním seznamu pod čelem kandidátky."
+        help_text="Zobrazí se v kompaktním seznamu pod čelem kandidátky.",
     )
 
     program = StreamBlock(
diff --git a/district/migrations/0218_auto_20240601_1530.py b/district/migrations/0218_auto_20240601_1530.py
index af6e8d45d31f450942e2cb937a172f0329ce0751..85ea20a1ed9c34f7f270952b8225a40de601e8a8 100644
--- a/district/migrations/0218_auto_20240601_1530.py
+++ b/district/migrations/0218_auto_20240601_1530.py
@@ -1,14 +1,32 @@
 # Generated by Django 5.0.4 on 2024-06-01 13:30
 
 from django.db import migrations
+from shared.blocks import SocialLinkBlock
+from district.blocks import ProgramGroupWithCandidatesBlock
 
 
 def migrate_programs(apps, schema_editor):
     # Get the models
     DistrictHomePage = apps.get_model("district", "DistrictHomePage")
+
     DistrictElectionRootPage = apps.get_model("district", "DistrictElectionRootPage")
-    DistrictElectionCampaignPage = apps.get_model("district", "DistrictElectionCampaignPage")
-    Page = apps.get_model("wagtailcore", "Page")
+    DistrictElectionCampaignPage = apps.get_model(
+        "district", "DistrictElectionCampaignPage"
+    )
+
+    DistrictElectionProgramPage = apps.get_model(
+        "district", "DistrictElectionProgramPage"
+    )
+    DistrictPostElectionStrategyPage = apps.get_model(
+        "district", "DistrictPostElectionStrategyPage"
+    )
+
+    DistrictNewProgramPage = apps.get_model(
+        "district", "DistrictNewProgramPage"
+    )
+
+    DistrictPersonPage = apps.get_model("district", "DistrictPersonPage")
+    apps.get_model("wagtailcore", "Page")
 
     # Get the content type for DistrictElectionCampaignPage and DistrictElectionRootPage
     ContentType = apps.get_model("contenttypes", "ContentType")
@@ -19,30 +37,212 @@ def migrate_programs(apps, schema_editor):
         app_label="district", model="districtelectioncampaignpage"
     )
 
+    program_page_content_type = ContentType.objects.get(
+        app_label="district", model="districtelectionprogrampage"
+    )
+    program_post_election_strategy_content_type = ContentType.objects.get(
+        app_label="district", model="districtpostelectionstrategypage"
+    )
+
     # Function to get children of a certain type
-    def get_children_of_type(parent_page, content_type):
-        return Page.objects.filter(
-            path__startswith=parent_page.path, depth=parent_page.depth + 1,
-            content_type=content_type
+    def get_children_of_type(model, parent_page, content_type):
+        return model.objects.filter(
+            path__startswith=parent_page.path,
+            depth=parent_page.depth + 1,
+            content_type=content_type,
         )
 
     for home_page in DistrictHomePage.objects.all():
-        election_data = {}
+        election_data = {
+            # Title
+            "title": "",  # Done
+            "order": 0,
 
-        print(f"Processing DistrictHomePage: {home_page}")
+            # Candidate / program lists
+            "candidate_pages": [],  
+            "candidate_blocks": [],
+            "program_points": [],
+            "post_election_strategies": [],
 
-        # Iterate over all child DistrictElectionRootPage instances
-        for election_root_page in get_children_of_type(home_page, root_page_content_type):
-            print(f"  Processing DistrictElectionRootPage: {election_root_page} with title: {election_root_page.title}")
+            # Candidates
+            "candidate_list_number": "",
+            "candidate_list_title": "",
+
+            # Program
+            "program_title": "",
+            "program_is_inline": False,
+            "program_content_before": "",  # Done
+            
+            "funding_info": "",
+        }
 
+        # Iterate over all child DistrictElectionRootPage instances
+        for election_root_page in get_children_of_type(
+            DistrictElectionRootPage, home_page, root_page_content_type
+        ):
             # Get the children of type DistrictElectionCampaignPage
-            campaign_pages = get_children_of_type(election_root_page, campaign_page_content_type)
+            campaign_pages = get_children_of_type(
+                DistrictElectionCampaignPage,
+                election_root_page,
+                campaign_page_content_type,
+            )
 
             for campaign_page in campaign_pages:
-                print(f"    Found campaign page: {campaign_page} with title: {campaign_page.title}")
-                
-                election_data["title"] = election_root_page.title
-                
+                election_data["title"] = (
+                    election_root_page.title
+                    if election_root_page.title
+                    else campaign_page.title
+                )
+
+                election_data["order"] = campaign_page.order
+
+                election_data["candidate_list_number"] = campaign_page.number
+                election_data[
+                    "candidate_list_title"
+                ] = campaign_page.candidate_list_title
+
+                election_data[
+                    "program_title"
+                ] = campaign_page.program_point_list_title
+                election_data[
+                    "program_is_inline"
+                ] = campaign_page.show_program_points_inline
+                election_data["program_content_before"] = campaign_page.content
+
+                election_data["funding_info"] = campaign_page.campaign_funding_info
+
+                for candidate_list_block in campaign_page.candidates.get_prep_value():
+                    candidate_list = candidate_list_block["value"]
+
+                    for position, candidate in enumerate(
+                        candidate_list["candidate_list"]
+                    ):
+                        position = position + 1
+
+                        if candidate["type"] == "person_page":
+                            election_data["candidate_pages"].append(
+                                {
+                                    "position": position,
+                                    "page": DistrictPersonPage.objects.filter(
+                                        id=candidate["value"]
+                                    ).first(),
+                                }
+                            )
+                            continue
+
+                        if candidate["type"] == "person_blocks":
+                            election_data["candidate_blocks"].append(
+                                {"position": position, "data": candidate["value"]}
+                            )
+
+                program_pages = get_children_of_type(
+                    DistrictElectionProgramPage,
+                    election_root_page,
+                    program_page_content_type,
+                )
+
+                for program_page in program_pages:
+                    election_data["program_points"].append(
+                        {
+                            "guarantor_page": program_page.guarantor,
+                            "image": program_page.image,
+                            "perex": program_page.perex,
+                            "content": program_page.content,
+                            "funding_info": program_page.campaign_funding_info,
+                        }
+                    )
+
+                post_election_strategy_pages = get_children_of_type(
+                    DistrictPostElectionStrategyPage,
+                    election_root_page,
+                    program_post_election_strategy_content_type,
+                )
+
+                for post_election_strategy_page in post_election_strategy_pages:
+                    election_data["post_election_strategies"].append(
+                        {
+                            "perex": post_election_strategy_page.perex,
+                            "content": post_election_strategy_page.content,
+                        }
+                    )
+
+        if len(election_data["candidate_pages"]) == 0 and len(election_data["candidate_blocks"]) == 0 and len(election_data["program_points"]) == 0:
+            continue  # Do nothing for these
+
+        # Create corresponding pages for the candidate blocks
+        for candidate_block in election_data["candidate_blocks"]:
+            social_links = []
+
+            if candidate_block["value"]["facebook_url"]:
+                social_links.append(
+                    SocialLinkBlock().to_python({
+                        "icon": "ico--facebook",
+                        "text": "Facebook",
+                        "link": candidate_block["value"]["facebook_url"]
+                    })
+                )
+
+            if candidate_block["value"]["instagram_url"]:
+                social_links.append(
+                    SocialLinkBlock().to_python({
+                        "icon": "ico--instagram",
+                        "text": "Instagram",
+                        "link": candidate_block["value"]["instagram_url"]
+                    })
+                )
+
+            if candidate_block["value"]["twitter_url"]:
+                social_links.append(
+                    SocialLinkBlock().to_python({
+                        "icon": "ico--twitter",
+                        "text": "Twitter",
+                        "link": candidate_block["value"]["twitter_url"]
+                    })
+                )
+
+            if candidate_block["value"]["youtube_url"]:
+                social_links.append(
+                    SocialLinkBlock().to_python({
+                        "icon": "ico--youtube",
+                        "text": "YouTube",
+                        "link": candidate_block["value"]["youtube_url"]
+                    })
+                )
+
+            if candidate_block["value"]["flickr_url"]:
+                social_links.append(
+                    SocialLinkBlock().to_python({
+                        "icon": "ico--flickr",
+                        "text": "Flickr",
+                        "link": candidate_block["value"]["flickr_url"]
+                    })
+                )
+
+            candidate_page = DistrictPersonPage(
+                title=candidate_block["data"]["title"],
+                job=candidate_block["data"]["job"],
+                profile_image_id=candidate_block["data"]["profile_photo"],
+                email=candidate_block["data"]["email"],
+                city=candidate_block["data"]["city"],
+                age=candidate_block["data"]["age"],
+                is_pirate=candidate_block["data"]["is_pirate"],
+                other_party=candidate_block["data"]["other_party"],
+                other_party_logo_id=candidate_block["data"]["other_party_logo"],
+                social_links=social_links,
+            )
+
+            candidate_page.save()
+
+            new_program_page = DistrictNewProgramPage(
+                title="Programy"
+            )
+            new_program_page.save()
+
+            new_program_block = ProgramGroupWithCandidatesBlock().to_python({
+                "title": election_data["title"],
+                "preamble_content": election_data["program_content_before"],
+
+            })
 
         print(election_data)
 
@@ -51,11 +251,8 @@ def migrate_programs(apps, schema_editor):
 
 
 class Migration(migrations.Migration):
-
     dependencies = [
-        ('district', '0217_alter_districthomepage_menu'),
+        ("district", "0217_alter_districthomepage_menu"),
     ]
 
-    operations = [
-        migrations.RunPython(migrate_programs)
-    ]
+    operations = [migrations.RunPython(migrate_programs)]
diff --git a/main/blocks.py b/main/blocks.py
index 0f1d243d2f278b90d3716e81ae4842ac7adcccef..d295932a65e4d3da77bb3b4dd325ce4d2110b860 100644
--- a/main/blocks.py
+++ b/main/blocks.py
@@ -212,7 +212,7 @@ class TeamBlock(StructBlock):
 class ElectionsProgramBlock(StructBlock):
     title = CharBlock(
         label="Název programu",
-        help_text="Např. 'Krajské volby 2024', 'Evropské volby 2024', ..."
+        help_text="Např. 'Krajské volby 2024', 'Evropské volby 2024', ...",
     )
 
     program_page = PageChooserBlock(
diff --git a/shared/blocks/main.py b/shared/blocks/main.py
index cc5adf39d7dd0bccbcb5b7096809474984156b2d..ac8117bec4c8fc09aa5f970d46353ef72573a0d1 100644
--- a/shared/blocks/main.py
+++ b/shared/blocks/main.py
@@ -11,7 +11,6 @@ from wagtail.blocks import (
 from wagtail.documents.blocks import DocumentChooserBlock
 from wagtail.images.blocks import ImageChooserBlock
 
-
 # Mixins (or used as such)
 
 
@@ -256,7 +255,7 @@ class PeopleOverviewBlock(StructBlock):
 class ProgramGroupBlockMixin(StructBlock):
     title = CharBlock(
         label="Název programu",
-        help_text="Např. 'Krajské volby 2024', 'Evropské volby 2024', ..."
+        help_text="Např. 'Krajské volby 2024', 'Evropské volby 2024', ...",
     )
     # point_list = ListBlock(ProgramBlock(), label="Jednotlivé články programu")