Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
36 changes: 36 additions & 0 deletions bakerydemo/base/blocks.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,15 @@
from wagtail.blocks import (
CharBlock,
ChoiceBlock,
ListBlock,
PageChooserBlock,
RichTextBlock,
StreamBlock,
StructBlock,
TextBlock,
URLBlock,
)
from wagtail.documents.blocks import DocumentChooserBlock
from wagtail.embeds.blocks import EmbedBlock
from wagtail.images import get_image_model
from wagtail.images.blocks import ImageChooserBlock
Expand Down Expand Up @@ -158,3 +162,35 @@ class BaseStreamBlock(StreamBlock):
preview_value="https://www.youtube.com/watch?v=mwrGSfiB1Mg",
description="An embedded video or other media",
)


class PageLinkBlock(StructBlock):
page = PageChooserBlock(required=False)


class DocumentBlock(StructBlock):
document = DocumentChooserBlock(required=False)


class ExternalLinkBlock(StructBlock):
url = URLBlock(required=False)


class LinkStreamBlock(StreamBlock):
page = PageLinkBlock()
document = DocumentBlock()
external_url = ExternalLinkBlock()

class Meta:
min_num = 1
max_num = 1


class MenuItemBlock(StructBlock):
title = CharBlock(required=False)
link = LinkStreamBlock()


class SectionBlock(StructBlock):
heading = CharBlock()
links = ListBlock(MenuItemBlock())
44 changes: 44 additions & 0 deletions bakerydemo/base/migrations/0027_footermenu.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
# Generated by Django 6.0.2 on 2026-03-05 00:43

import django.db.models.deletion
import uuid
import wagtail.fields
import wagtail.models.preview
from django.db import migrations, models


class Migration(migrations.Migration):

dependencies = [
('base', '0026_alter_formpage_body_alter_gallerypage_body_and_more'),
('wagtailcore', '0096_referenceindex_referenceindex_source_object_and_more'),
]

operations = [
migrations.CreateModel(
name='FooterMenu',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('translation_key', models.UUIDField(default=uuid.uuid4, editable=False)),
('live', models.BooleanField(default=True, editable=False, verbose_name='live')),
('has_unpublished_changes', models.BooleanField(default=False, editable=False, verbose_name='has unpublished changes')),
('first_published_at', models.DateTimeField(blank=True, db_index=True, null=True, verbose_name='first published at')),
('last_published_at', models.DateTimeField(editable=False, null=True, verbose_name='last published at')),
('go_live_at', models.DateTimeField(blank=True, null=True, verbose_name='go live date/time')),
('expire_at', models.DateTimeField(blank=True, null=True, verbose_name='expiry date/time')),
('expired', models.BooleanField(default=False, editable=False, verbose_name='expired')),
('name', models.CharField(max_length=255)),
('sections', wagtail.fields.StreamField([('section', 7)], block_lookup={0: ('wagtail.blocks.CharBlock', (), {}), 1: ('wagtail.blocks.CharBlock', (), {'required': False}), 2: ('wagtail.blocks.PageChooserBlock', (), {'required': False}), 3: ('wagtail.blocks.URLBlock', (), {'required': False}), 4: ('wagtail.documents.blocks.DocumentChooserBlock', (), {'required': False}), 5: ('wagtail.blocks.StructBlock', [[('title', 1), ('page', 2), ('external_url', 3), ('document', 4)]], {}), 6: ('wagtail.blocks.ListBlock', (5,), {}), 7: ('wagtail.blocks.StructBlock', [[('heading', 0), ('links', 6)]], {})})),
('latest_revision', models.ForeignKey(blank=True, editable=False, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='+', to='wagtailcore.revision', verbose_name='latest revision')),
('live_revision', models.ForeignKey(blank=True, editable=False, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='+', to='wagtailcore.revision', verbose_name='live revision')),
('locale', models.ForeignKey(editable=False, on_delete=django.db.models.deletion.PROTECT, related_name='+', to='wagtailcore.locale', verbose_name='locale')),
],
options={
'verbose_name': 'footer menu',
'verbose_name_plural': 'footer menus',
'abstract': False,
'unique_together': {('translation_key', 'locale')},
},
bases=(wagtail.models.preview.PreviewableMixin, models.Model),
),
]
19 changes: 19 additions & 0 deletions bakerydemo/base/migrations/0028_alter_footermenu_sections.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
# Generated by Django 6.0.2 on 2026-03-06 22:03

import wagtail.fields
from django.db import migrations


class Migration(migrations.Migration):

dependencies = [
('base', '0027_footermenu'),
]

operations = [
migrations.AlterField(
model_name='footermenu',
name='sections',
field=wagtail.fields.StreamField([('section', 11)], block_lookup={0: ('wagtail.blocks.CharBlock', (), {}), 1: ('wagtail.blocks.CharBlock', (), {'required': False}), 2: ('wagtail.blocks.PageChooserBlock', (), {'required': False}), 3: ('wagtail.blocks.StructBlock', [[('page', 2)]], {}), 4: ('wagtail.documents.blocks.DocumentChooserBlock', (), {'required': False}), 5: ('wagtail.blocks.StructBlock', [[('document', 4)]], {}), 6: ('wagtail.blocks.URLBlock', (), {'required': False}), 7: ('wagtail.blocks.StructBlock', [[('url', 6)]], {}), 8: ('wagtail.blocks.StreamBlock', [[('page', 3), ('document', 5), ('external_url', 7)]], {}), 9: ('wagtail.blocks.StructBlock', [[('title', 1), ('link', 8)]], {}), 10: ('wagtail.blocks.ListBlock', (9,), {}), 11: ('wagtail.blocks.StructBlock', [[('heading', 0), ('links', 10)]], {})}),
),
]
31 changes: 30 additions & 1 deletion bakerydemo/base/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@
)
from wagtail.search import index

from .blocks import BaseStreamBlock
from .blocks import BaseStreamBlock, SectionBlock

# Allow filtering by collection
Image.api_fields = [APIField("collection")]
Expand Down Expand Up @@ -226,6 +226,35 @@ class Meta(TranslatableMixin.Meta):
verbose_name_plural = "footer text"


class FooterMenu(
DraftStateMixin,
RevisionMixin,
PreviewableMixin,
TranslatableMixin,
models.Model,
):
name = models.CharField(max_length=255)
sections = StreamField([("section", SectionBlock())])

panels = [
FieldPanel("name"),
FieldPanel("sections"),
]

def __str__(self):
return self.name

def get_preview_template(self, request, mode_name):
return "base.html"

def get_preview_context(self, request, mode_name):
return {"footer_menu": self}

class Meta(TranslatableMixin.Meta):
verbose_name = "footer menu"
verbose_name_plural = "footer menus"


class StandardPage(Page):
"""
A generic content page. On this demo site we use it for an about page but
Expand Down
16 changes: 15 additions & 1 deletion bakerydemo/base/templatetags/navigation_tags.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
from django import template
from wagtail.models import Page, Site

from bakerydemo.base.models import FooterText
from bakerydemo.base.models import FooterMenu, FooterText

register = template.Library()
# https://docs.djangoproject.com/en/stable/howto/custom-template-tags/
Expand Down Expand Up @@ -75,3 +75,17 @@ def get_footer_text(context):
return {
"footer_text": footer_text,
}


@register.inclusion_tag("base/include/footer_menu.html", takes_context=True)
def get_footer_menu(context):

footer_menu = context.get("footer_menu", None)

if not footer_menu:
instance = FooterMenu.objects.filter(live=True).first()
footer_menu = instance if instance else None

return {
"footer_menu": footer_menu,
}
8 changes: 6 additions & 2 deletions bakerydemo/base/wagtail_hooks.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
from wagtail.snippets.views.snippets import SnippetViewSet, SnippetViewSetGroup

from bakerydemo.base.filters import RevisionFilterSetMixin
from bakerydemo.base.models import FooterText, Person
from bakerydemo.base.models import FooterMenu, FooterText, Person

"""
N.B. To see what icons are available for use in Wagtail menus and StreamField block types,
Expand Down Expand Up @@ -82,11 +82,15 @@ class FooterTextViewSet(SnippetViewSet):
filterset_class = FooterTextFilterSet


class FooterMenuViewSet(SnippetViewSet):
model = FooterMenu


class BakerySnippetViewSetGroup(SnippetViewSetGroup):
menu_label = "Bakery Misc"
menu_icon = "utensils" # change as required
menu_order = 300 # will put in 4th place (000 being 1st, 100 2nd)
items = (PersonViewSet, FooterTextViewSet)
items = (PersonViewSet, FooterTextViewSet, FooterMenuViewSet)


# When using a SnippetViewSetGroup class to group several SnippetViewSet classes together,
Expand Down
29 changes: 29 additions & 0 deletions bakerydemo/templates/base/include/footer_menu.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
{% load wagtailcore_tags %}

{% if footer_menu %}
<div style="display: flex; justify-content: center; gap: 40px;">
{% for section in footer_menu.sections %}
<div style="text-align: center;">
<h2>{{ section.value.heading }}</h2>
<ul style="list-style: none; padding: 0;">
{% for item in section.value.links %}
<li>
<a href="{% for block in item.link %}{% if block.block_type == 'page' %}{% pageurl block.value.page %}{% elif block.block_type == 'external_url' %}{{ block.value.url }}{% elif block.block_type == 'document' %}{{ block.value.document.url }}{% endif %}{% endfor %}">
{% if item.title %}
{{ item.title }}
{% else %}
{% for block in item.link %}
{% if block.block_type == "page" %}{{ block.value.page.title }}
{% elif block.block_type == "external_url" %}{{ block.value.url }}
{% elif block.block_type == "document" %}{{ block.value.document.title }}
{% endif %}
{% endfor %}
{% endif %}
</a>
</li>
{% endfor %}
</ul>
</div>
{% endfor %}
</div>
{% endif %}
3 changes: 2 additions & 1 deletion bakerydemo/templates/includes/footer.html
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@
<footer class="container">
<div class="row">
<div class="col-sm-12">
{% get_footer_menu %}
{% get_footer_text %}
{% with mastodon_url=settings.base.GenericSettings.mastodon_url github_url=settings.base.GenericSettings.github_url organisation_url=settings.base.GenericSettings.organisation_url %}
{% if mastodon_url or github_url or organisation_url %}
<ul class="list-inline">
Expand Down Expand Up @@ -30,7 +32,6 @@
</ul>
{% endif %}
{% endwith %}
{% get_footer_text %}
</div>
</div>
</footer>