Skip to content

Commit 825d151

Browse files
tushortzluketowellphill-stanley
authored
CMS: Landing Page Header Updates (#3027)
* CMS: Landing Page Header Updates * CMS: Update tests and landing page related files --------- Co-authored-by: Luke Towell <luke.towell@ukhsa.gov.uk> Co-authored-by: phill-stanley <139551113+phill-stanley@users.noreply.github.com>
1 parent 020a39d commit 825d151

File tree

9 files changed

+189
-67
lines changed

9 files changed

+189
-67
lines changed

cms/common/models.py

Lines changed: 2 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,6 @@
22
from modelcluster.fields import ParentalKey
33
from wagtail.admin.panels import FieldPanel, InlinePanel, ObjectList, TabbedInterface
44
from wagtail.api import APIField
5-
from wagtail.fields import RichTextField
6-
from wagtail.models import Orderable
75
from wagtail.search import index
86

97
from cms.common.managers import CommonPageManager
@@ -12,8 +10,8 @@
1210
RelatedLinksLayoutEnum,
1311
)
1412
from cms.dashboard.models import (
15-
MAXIMUM_URL_FIELD_LENGTH,
1613
UKHSAPage,
14+
UKHSAPageRelatedLink,
1715
)
1816
from cms.dynamic_content import help_texts
1917
from cms.dynamic_content.announcements import Announcement
@@ -66,27 +64,10 @@ def is_previewable(cls) -> bool:
6664
return False
6765

6866

69-
class CommonPageRelatedLink(Orderable):
67+
class CommonPageRelatedLink(UKHSAPageRelatedLink):
7068
page = ParentalKey(
7169
CommonPage, on_delete=models.SET_NULL, null=True, related_name="related_links"
7270
)
73-
title = models.CharField(max_length=255)
74-
url = models.URLField(verbose_name="URL", max_length=MAXIMUM_URL_FIELD_LENGTH)
75-
body = RichTextField(features=[])
76-
77-
# Sets which panels to show on the editing view
78-
panels = [
79-
FieldPanel("title"),
80-
FieldPanel("url"),
81-
FieldPanel("body"),
82-
]
83-
84-
# Sets which fields to expose on the API
85-
api_fields = [
86-
APIField("title"),
87-
APIField("url"),
88-
APIField("body"),
89-
]
9071

9172

9273
class CommonPageAnnouncement(Announcement):

cms/composite/models.py

Lines changed: 2 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -6,16 +6,14 @@
66
from wagtail.admin.panels import FieldPanel, InlinePanel, ObjectList, TabbedInterface
77
from wagtail.api import APIField
88
from wagtail.fields import RichTextField
9-
from wagtail.models import Orderable
109
from wagtail.search import index
1110

12-
from cms.common.models import MAXIMUM_URL_FIELD_LENGTH
1311
from cms.composite.managers import CompositePageManager
1412
from cms.dashboard.enums import (
1513
DEFAULT_RELATED_LINKS_LAYOUT_FIELD_LENGTH,
1614
RelatedLinksLayoutEnum,
1715
)
18-
from cms.dashboard.models import UKHSAPage
16+
from cms.dashboard.models import UKHSAPage, UKHSAPageRelatedLink
1917
from cms.dynamic_content import help_texts
2018
from cms.dynamic_content.access import ALLOWABLE_BODY_CONTENT_COMPOSITE
2119
from cms.dynamic_content.announcements import Announcement
@@ -118,31 +116,15 @@ def last_updated_at(self) -> datetime.datetime:
118116
return max(timestamps)
119117

120118

121-
class CompositeRelatedLink(Orderable):
119+
class CompositeRelatedLink(UKHSAPageRelatedLink):
122120
page = ParentalKey(
123121
CompositePage,
124122
on_delete=models.SET_NULL,
125123
null=True,
126124
related_name="related_links",
127125
)
128-
title = models.CharField(max_length=255)
129-
url = models.URLField(verbose_name="URL", max_length=MAXIMUM_URL_FIELD_LENGTH)
130126
body = RichTextField(features=[], blank=True)
131127

132-
# Sets which panels to show on the editing view
133-
panels = [
134-
FieldPanel("title"),
135-
FieldPanel("url"),
136-
FieldPanel("body"),
137-
]
138-
139-
# Sets which fields to expose on the API
140-
api_fields = [
141-
APIField("title"),
142-
APIField("url"),
143-
APIField("body"),
144-
]
145-
146128

147129
class CompositePageAnnouncement(Announcement):
148130
page = ParentalKey(

cms/dashboard/management/commands/build_cms_site_helpers/pages.py

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
)
1616
from cms.forms.models import FormField, FormPage
1717
from cms.home.models import LandingPage
18+
from cms.home.models.landing_page import LandingPageRelatedLink
1819
from cms.snippets.data_migrations.operations import (
1920
get_or_create_download_button_internal_button_snippet,
2021
)
@@ -57,13 +58,21 @@ def create_landing_page(*, parent_page: Page) -> LandingPage:
5758
page = LandingPage(
5859
title=data["title"],
5960
sub_title=data["sub_title"],
61+
page_description=data["page_description"],
6062
body=landing_page_body,
63+
related_links_layout=data["related_links_layout"],
6164
slug=data["meta"]["slug"],
6265
seo_title=data["meta"]["seo_title"],
6366
search_description=data["meta"]["search_description"],
6467
)
6568
_add_page_to_parent(page=page, parent_page=parent_page)
6669

70+
_create_related_links(
71+
related_link_class=LandingPageRelatedLink,
72+
response_data=data,
73+
page=page,
74+
)
75+
6776
return page
6877

6978

cms/dashboard/models.py

Lines changed: 35 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
from wagtail.admin.panels import FieldPanel, InlinePanel, MultiFieldPanel
99
from wagtail.api import APIField
1010
from wagtail.fields import RichTextField
11-
from wagtail.models import Page, SiteRootPath
11+
from wagtail.models import Orderable, Page, SiteRootPath
1212

1313
from cms import seo
1414

@@ -163,3 +163,37 @@ def active_announcements(self) -> list[dict[str, str | int]]:
163163
.order_by("-banner_type")
164164
.values("id", "title", "body", "banner_type")
165165
)
166+
167+
168+
class UKHSAPageRelatedLink(Orderable):
169+
"""
170+
Abstract base class for all page types related links.
171+
172+
When a page type extends this class, it will need to include the `page` field e.g.
173+
174+
page = ParentalKey(
175+
<PAGE_TYPE>, on_delete=models.SET_NULL, null=True, related_name="related_links"
176+
)
177+
"""
178+
179+
title = models.CharField(max_length=255)
180+
url = models.URLField(verbose_name="URL", max_length=MAXIMUM_URL_FIELD_LENGTH)
181+
body = RichTextField(features=[])
182+
183+
# Sets which panels to show on the editing view
184+
panels = [
185+
FieldPanel("title"),
186+
FieldPanel("url"),
187+
FieldPanel("body"),
188+
]
189+
190+
# Sets which fields to expose on the API
191+
api_fields = [
192+
APIField("title"),
193+
APIField("url"),
194+
APIField("body"),
195+
]
196+
197+
class Meta:
198+
abstract = True
199+
ordering = ["sort_order"]

cms/dashboard/templates/cms_starting_pages/landing_page.json

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,10 @@
2222
},
2323
"title": "Landing page",
2424
"sub_title": "showing public health data across England",
25+
"page_description": "",
2526
"body": "",
27+
"related_links": [],
28+
"related_links_layout": "Footer",
2629
"last_published_at": "2024-09-20T14:04:30.332316+01:00",
2730
"last_updated_at": "2024-09-24T16:40:55.228390+01:00",
2831
"seo_change_frequency": 5,
Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
# Generated by Django 5.2.9 on 2026-02-25 12:31
2+
3+
import django.db.models.deletion
4+
import modelcluster.fields
5+
import wagtail.fields
6+
from django.db import migrations, models
7+
8+
9+
class Migration(migrations.Migration):
10+
11+
dependencies = [
12+
("home", "0027_alter_landingpage_new_chart_row_blocks"),
13+
]
14+
15+
operations = [
16+
migrations.AddField(
17+
model_name="landingpage",
18+
name="page_description",
19+
field=wagtail.fields.RichTextField(
20+
blank=True,
21+
help_text="\nAn optional body of text which will be rendered at the top of the page. \nThis text will be displayed after the title of the page and before any of the main content.\n",
22+
null=True,
23+
),
24+
),
25+
migrations.AddField(
26+
model_name="landingpage",
27+
name="related_links_layout",
28+
field=models.CharField(
29+
choices=[("Sidebar", "Sidebar"), ("Footer", "Footer")],
30+
default="Footer",
31+
help_text="\nThis dictates where the related links for this page will be positioned.\n",
32+
max_length=10,
33+
verbose_name="Layout",
34+
),
35+
),
36+
migrations.AlterField(
37+
model_name="landingpage",
38+
name="sub_title",
39+
field=models.CharField(blank=True, max_length=255, null=True),
40+
),
41+
migrations.CreateModel(
42+
name="LandingPageRelatedLink",
43+
fields=[
44+
(
45+
"id",
46+
models.BigAutoField(
47+
auto_created=True,
48+
primary_key=True,
49+
serialize=False,
50+
verbose_name="ID",
51+
),
52+
),
53+
(
54+
"sort_order",
55+
models.IntegerField(blank=True, editable=False, null=True),
56+
),
57+
("title", models.CharField(max_length=255)),
58+
("url", models.URLField(max_length=400, verbose_name="URL")),
59+
("body", wagtail.fields.RichTextField()),
60+
(
61+
"page",
62+
modelcluster.fields.ParentalKey(
63+
null=True,
64+
on_delete=django.db.models.deletion.SET_NULL,
65+
related_name="related_links",
66+
to="home.landingpage",
67+
),
68+
),
69+
],
70+
options={
71+
"ordering": ["sort_order"],
72+
"abstract": False,
73+
},
74+
),
75+
]

cms/home/models/landing_page.py

Lines changed: 47 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,20 @@
11
from django.db import models
22
from modelcluster.fields import ParentalKey
3-
from wagtail.admin.panels import FieldPanel, ObjectList, TabbedInterface
3+
from wagtail.admin.panels import FieldPanel, InlinePanel, ObjectList, TabbedInterface
44
from wagtail.api import APIField
5+
from wagtail.fields import RichTextField
56
from wagtail.models import Page
67

7-
from cms.dashboard.models import UKHSAPage
8+
from cms.dashboard.enums import (
9+
DEFAULT_RELATED_LINKS_LAYOUT_FIELD_LENGTH,
10+
RelatedLinksLayoutEnum,
11+
)
12+
from cms.dashboard.models import (
13+
AVAILABLE_RICH_TEXT_FEATURES,
14+
UKHSAPage,
15+
UKHSAPageRelatedLink,
16+
)
17+
from cms.dynamic_content import help_texts
818
from cms.dynamic_content.access import ALLOWABLE_BODY_CONTENT_SECTION_LINK
919
from cms.dynamic_content.announcements import Announcement
1020
from cms.home.managers import LandingPageManager
@@ -13,22 +23,49 @@
1323
class LandingPage(UKHSAPage):
1424
is_creatable = True
1525
max_count = 1
16-
sub_title = models.CharField(max_length=255)
26+
sub_title = models.CharField(max_length=255, null=True, blank=True)
27+
page_description = RichTextField(
28+
features=AVAILABLE_RICH_TEXT_FEATURES,
29+
blank=True,
30+
null=True,
31+
help_text=help_texts.PAGE_DESCRIPTION_FIELD,
32+
)
1733
body = ALLOWABLE_BODY_CONTENT_SECTION_LINK
1834

19-
content_panels = Page.content_panels + [FieldPanel("sub_title"), FieldPanel("body")]
35+
related_links_layout = models.CharField(
36+
verbose_name="Layout",
37+
help_text=help_texts.RELATED_LINKS_LAYOUT_FIELD,
38+
default=RelatedLinksLayoutEnum.Footer.value,
39+
max_length=DEFAULT_RELATED_LINKS_LAYOUT_FIELD_LENGTH,
40+
choices=RelatedLinksLayoutEnum.choices(),
41+
)
42+
43+
sidebar_content_panels = [
44+
FieldPanel("related_links_layout"),
45+
InlinePanel("related_links", heading="Related links", label="Related link"),
46+
]
47+
48+
content_panels = Page.content_panels + [
49+
FieldPanel("sub_title"),
50+
FieldPanel("page_description"),
51+
FieldPanel("body"),
52+
]
2053

2154
api_fields = UKHSAPage.api_fields + [
2255
APIField("title"),
2356
APIField("sub_title"),
57+
APIField("page_description"),
2458
APIField("body"),
59+
APIField("related_links_layout"),
60+
APIField("related_links"),
2561
APIField("search_description"),
2662
APIField("last_published_at"),
2763
]
2864

2965
edit_handler = TabbedInterface(
3066
[
3167
ObjectList(content_panels, heading="Content"),
68+
ObjectList(sidebar_content_panels, heading="Related Links"),
3269
ObjectList(UKHSAPage.announcement_content_panels, heading="Announcements"),
3370
ObjectList(UKHSAPage.promote_panels, heading="Promote"),
3471
]
@@ -81,3 +118,9 @@ class LandingPageAnnouncement(Announcement):
81118
null=True,
82119
related_name="announcements",
83120
)
121+
122+
123+
class LandingPageRelatedLink(UKHSAPageRelatedLink):
124+
page = ParentalKey(
125+
LandingPage, on_delete=models.SET_NULL, null=True, related_name="related_links"
126+
)

cms/topic/models.py

Lines changed: 2 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@
55
from wagtail.admin.panels import FieldPanel, InlinePanel, ObjectList, TabbedInterface
66
from wagtail.api import APIField
77
from wagtail.fields import RichTextField
8-
from wagtail.models import Orderable
98
from wagtail.search import index
109

1110
from cms.dashboard.enums import (
@@ -14,8 +13,8 @@
1413
)
1514
from cms.dashboard.models import (
1615
AVAILABLE_RICH_TEXT_FEATURES,
17-
MAXIMUM_URL_FIELD_LENGTH,
1816
UKHSAPage,
17+
UKHSAPageRelatedLink,
1918
)
2019
from cms.dynamic_content import help_texts
2120
from cms.dynamic_content.access import ALLOWABLE_BODY_CONTENT
@@ -204,27 +203,10 @@ def last_updated_at(self) -> datetime.datetime:
204203
return max(timestamps)
205204

206205

207-
class TopicPageRelatedLink(Orderable):
206+
class TopicPageRelatedLink(UKHSAPageRelatedLink):
208207
page = ParentalKey(
209208
TopicPage, on_delete=models.SET_NULL, null=True, related_name="related_links"
210209
)
211-
title = models.CharField(max_length=255)
212-
url = models.URLField(verbose_name="URL", max_length=MAXIMUM_URL_FIELD_LENGTH)
213-
body = RichTextField(features=[])
214-
215-
# Sets which panels to show on the editing view
216-
panels = [
217-
FieldPanel("title"),
218-
FieldPanel("url"),
219-
FieldPanel("body"),
220-
]
221-
222-
# Sets which fields to expose on the API
223-
api_fields = [
224-
APIField("title"),
225-
APIField("url"),
226-
APIField("body"),
227-
]
228210

229211

230212
class TopicPageAnnouncement(Announcement):

0 commit comments

Comments
 (0)