0
# Page Integration
1
2
Mixins and base classes for integrating Wagtail pages with the WagtailMenus system. These components enable pages to participate in navigation structures, control their menu behavior, and provide specialized page types for menu functionality.
3
4
## Capabilities
5
6
### Menu Page Mixin
7
8
A mixin class that adds menu-related functionality to any Wagtail page, providing settings and behavior for controlling how pages appear in menus.
9
10
```python { .api }
11
class MenuPageMixin:
12
"""
13
Mixin for pages with menu functionality.
14
15
Adds menu-related fields and methods to control how pages
16
participate in menu structures and navigation.
17
"""
18
19
# Menu behavior fields
20
repeat_in_subnav: models.BooleanField # Whether to repeat in sub-navigation
21
repeated_item_text: models.CharField # Custom text for repeated items
22
23
# Menu settings panels for admin
24
menu_settings_panels: list
25
26
def modify_submenu_items(
27
self, menu_items, current_page, current_ancestor_ids, current_site,
28
allow_repeating_parents, apply_active_classes, original_menu_tag,
29
menu_instance=None, request=None, use_absolute_page_urls=False
30
):
31
"""
32
Modify menu items for sub-menu display.
33
34
Args:
35
menu_items: List of menu items to modify
36
current_page: The current page being viewed
37
current_ancestor_ids: IDs of current page ancestors
38
current_site: Current site object
39
allow_repeating_parents (bool): Whether to show repeating parent items
40
apply_active_classes (bool): Whether to apply active CSS classes
41
original_menu_tag (str): Name of original menu tag ('main_menu', etc.)
42
menu_instance: Menu instance calling this method
43
request: HTTP request object
44
use_absolute_page_urls (bool): Whether to use absolute URLs
45
46
Returns:
47
Modified menu items list
48
"""
49
50
def has_submenu_items(self, current_page, allow_repeating_parents,
51
original_menu_tag, menu_instance=None, request=None):
52
"""
53
Check if this page has items for sub-menu display.
54
55
Args:
56
current_page: The current page being viewed
57
allow_repeating_parents (bool): Allow parent items in sub-menus
58
current_site: Current site object
59
check_for_children (bool): Whether to check for child pages
60
61
Returns:
62
bool: True if page has sub-menu items
63
"""
64
```
65
66
### Menu Page
67
68
An abstract page class that combines MenuPageMixin with Wagtail's Page model, providing a complete base for pages that participate in menu systems.
69
70
```python { .api }
71
class MenuPage(MenuPageMixin, Page):
72
"""
73
Abstract page with menu functionality.
74
75
Extends Wagtail's Page model with menu-related fields and methods.
76
Use as a base class for pages that need menu integration.
77
"""
78
79
class Meta:
80
abstract = True
81
```
82
83
### Link Page
84
85
An abstract page type specifically designed for menu items that link to external URLs or provide redirects.
86
87
```python { .api }
88
class AbstractLinkPage:
89
"""
90
Base class for link pages that redirect to external URLs.
91
92
Provides functionality for pages that exist primarily to
93
link to external resources or redirect to other locations.
94
"""
95
96
link_url: str # External URL to redirect to
97
link_text: str # Display text for the link
98
99
def get_sitemap_urls(self, request=None):
100
"""
101
Return empty list as link pages shouldn't appear in sitemaps.
102
103
Args:
104
request: HTTP request object
105
106
Returns:
107
list: Empty list (link pages not included in sitemaps)
108
"""
109
110
def serve(self, request):
111
"""
112
Serve a redirect to the external URL.
113
114
Args:
115
request: HTTP request object
116
117
Returns:
118
HttpResponseRedirect: Redirect to link_url
119
"""
120
```
121
122
### Sub-Menu Template Mixin
123
124
A mixin for pages that need to define custom templates for their sub-menu rendering.
125
126
```python { .api }
127
class DefinesSubMenuTemplatesMixin:
128
"""
129
Mixin for sub-menu template handling.
130
131
Allows pages to specify custom templates for rendering
132
their sub-menus at different levels.
133
"""
134
135
def get_sub_menu_template_names(self, current_level=1):
136
"""
137
Get template names for sub-menu rendering at specific levels.
138
139
Args:
140
current_level (int): Current menu depth level
141
142
Returns:
143
list: Template names for sub-menu rendering
144
"""
145
```
146
147
## Usage Examples
148
149
### Creating Menu-Enabled Pages
150
151
```python
152
from wagtailmenus.models import MenuPageMixin
153
from wagtail.models import Page
154
from wagtail.fields import RichTextField
155
from wagtail.admin.panels import FieldPanel
156
157
class CustomPage(MenuPageMixin, Page):
158
"""Custom page with menu functionality."""
159
160
body = RichTextField()
161
162
content_panels = Page.content_panels + [
163
FieldPanel('body'),
164
]
165
166
# Add menu settings to the settings tab
167
settings_panels = Page.settings_panels + MenuPageMixin.menu_settings_panels
168
```
169
170
### Using MenuPage Base Class
171
172
```python
173
from wagtailmenus.models import MenuPage
174
from wagtail.fields import RichTextField
175
from wagtail.admin.panels import FieldPanel
176
177
class ArticlePage(MenuPage):
178
"""Article page with built-in menu functionality."""
179
180
body = RichTextField()
181
author = models.CharField(max_length=100)
182
183
content_panels = Page.content_panels + [
184
FieldPanel('body'),
185
FieldPanel('author'),
186
]
187
188
# menu_settings_panels are automatically included
189
```
190
191
### Creating Link Pages
192
193
```python
194
from wagtailmenus.models import AbstractLinkPage
195
from wagtail.models import Page
196
from wagtail.admin.panels import FieldPanel
197
from django.db import models
198
199
class ExternalLinkPage(AbstractLinkPage, Page):
200
"""Page that redirects to external URLs."""
201
202
# Additional fields beyond AbstractLinkPage
203
description = models.TextField(blank=True)
204
205
content_panels = Page.content_panels + [
206
FieldPanel('link_url'),
207
FieldPanel('link_text'),
208
FieldPanel('description'),
209
]
210
211
def get_link_text(self):
212
"""Get display text for menu items."""
213
return self.link_text or self.title
214
```
215
216
### Customizing Menu Behavior
217
218
```python
219
class SpecialPage(MenuPageMixin, Page):
220
"""Page with custom menu behavior."""
221
222
def modify_submenu_behaviour(self, menu_items, current_page,
223
current_ancestor_ids, current_site,
224
check_for_children=True):
225
"""Custom sub-menu behavior."""
226
227
# Add custom menu items
228
custom_items = self.get_custom_menu_items()
229
menu_items.extend(custom_items)
230
231
# Filter items based on user permissions
232
if hasattr(current_page, 'request'):
233
user = getattr(current_page.request, 'user', None)
234
if user and not user.is_staff:
235
menu_items = [item for item in menu_items
236
if not getattr(item, 'staff_only', False)]
237
238
return menu_items
239
240
def has_submenu_items(self, current_page, allow_repeating_parents=True,
241
current_site=None, check_for_children=True):
242
"""Check for custom sub-menu items."""
243
244
# Always return True if we have custom items
245
if self.get_custom_menu_items():
246
return True
247
248
# Otherwise use default behavior
249
return super().has_submenu_items(
250
current_page, allow_repeating_parents,
251
current_site, check_for_children
252
)
253
```
254
255
### Working with Sub-Menu Templates
256
257
```python
258
from wagtailmenus.models import DefinesSubMenuTemplatesMixin
259
260
class CategoryPage(DefinesSubMenuTemplatesMixin, MenuPageMixin, Page):
261
"""Page with custom sub-menu templates."""
262
263
category_type = models.CharField(max_length=50, choices=[
264
('products', 'Products'),
265
('services', 'Services'),
266
('resources', 'Resources'),
267
])
268
269
def get_sub_menu_template_names(self, current_level=1):
270
"""Return category-specific sub-menu templates."""
271
272
templates = []
273
274
if self.category_type == 'products':
275
templates.append('menus/product_submenu.html')
276
elif self.category_type == 'services':
277
templates.append('menus/service_submenu.html')
278
279
# Add level-specific templates
280
templates.append(f'menus/submenu_level_{current_level}.html')
281
templates.append('menus/submenu.html') # Fallback
282
283
return templates
284
```
285
286
### Menu Integration in Templates
287
288
```django
289
<!-- Check if current page supports menu functionality -->
290
{% if page.show_in_menus %}
291
<nav class="page-navigation">
292
{% children_menu parent_page=page max_levels=1 %}
293
</nav>
294
{% endif %}
295
296
<!-- Show sub-navigation if page has menu items -->
297
{% if page.has_submenu_items %}
298
<aside class="subnav">
299
{% section_menu show_section_root=False %}
300
</aside>
301
{% endif %}
302
```
303
304
### Page Settings Configuration
305
306
```python
307
# In your page models, configure menu settings
308
class MyPage(MenuPageMixin, Page):
309
# ... other fields
310
311
settings_panels = Page.settings_panels + [
312
# Menu settings are added via MenuPageMixin.menu_settings_panels
313
FieldPanel('show_in_menus'),
314
FieldPanel('repeat_in_subnav'),
315
] + MenuPageMixin.menu_settings_panels
316
```
317
318
## Types
319
320
```python { .api }
321
# Page integration field types
322
class PageIntegrationTypes:
323
show_in_menus: bool
324
repeat_in_subnav: bool
325
link_url: str
326
link_text: str
327
menu_settings_panels: list
328
329
# Method parameter and return types
330
class PageMethodTypes:
331
menu_items: list
332
current_page: 'Page'
333
current_ancestor_ids: list[int]
334
current_site: 'Site'
335
check_for_children: bool
336
allow_repeating_parents: bool
337
current_level: int
338
```