0
# Administration
1
2
Admin interfaces and components for managing menus through Wagtail's admin interface. WagtailMenus provides comprehensive admin integration with inline panels for menu items, custom form classes, and admin views that integrate seamlessly with Wagtail's interface.
3
4
## Capabilities
5
6
### Admin Classes
7
8
Main admin classes for managing menus in the Wagtail admin interface.
9
10
```python { .api }
11
class MainMenuAdmin:
12
"""
13
Admin interface for main menus.
14
15
Provides the administrative interface for managing site-wide
16
main navigation menus through Wagtail's admin panel.
17
"""
18
19
model = 'MainMenu'
20
menu_label = 'Main menus'
21
menu_icon = 'list-ul'
22
list_display = ['site', 'max_levels']
23
list_filter = ['site']
24
25
class FlatMenuAdmin:
26
"""
27
Admin interface for flat menus.
28
29
Provides the administrative interface for managing custom
30
flat menus (footer, sidebar, etc.) through Wagtail's admin panel.
31
"""
32
33
model = 'FlatMenu'
34
menu_label = 'Flat menus'
35
menu_icon = 'list-ul'
36
list_display = ['title', 'handle', 'site']
37
list_filter = ['site']
38
search_fields = ['title', 'handle']
39
```
40
41
### Admin Views
42
43
Specialized admin views for different menu operations.
44
45
```python { .api }
46
class MainMenuIndexView:
47
"""Index view for main menus showing all site main menus."""
48
49
template_name = 'wagtailmenus/admin/mainmenu_index.html'
50
51
class MainMenuEditView:
52
"""Edit view for main menu configuration and items."""
53
54
template_name = 'wagtailmenus/admin/mainmenu_edit.html'
55
56
class FlatMenuIndexView:
57
"""Index view for flat menus showing all flat menus."""
58
59
template_name = 'wagtailmenus/admin/flatmenu_index.html'
60
61
class FlatMenuCreateView:
62
"""Create view for new flat menus."""
63
64
template_name = 'wagtailmenus/admin/flatmenu_create.html'
65
```
66
67
### Inline Panels
68
69
Inline panel classes for managing menu items within menu admin interfaces.
70
71
```python { .api }
72
class MenuItemInlinePanel:
73
"""
74
Base inline panel for menu items.
75
76
Provides the foundation for inline editing of menu items
77
within menu admin interfaces.
78
"""
79
80
panels = [
81
# Standard menu item editing panels
82
]
83
84
class MainMenuItemsInlinePanel(MenuItemInlinePanel):
85
"""
86
Inline panel for main menu items.
87
88
Allows editing of main menu items directly within
89
the main menu admin interface.
90
"""
91
92
model = 'MainMenuItem'
93
heading = 'Menu items'
94
95
class FlatMenuItemsInlinePanel(MenuItemInlinePanel):
96
"""
97
Inline panel for flat menu items.
98
99
Allows editing of flat menu items directly within
100
the flat menu admin interface.
101
"""
102
103
model = 'FlatMenuItem'
104
heading = 'Menu items'
105
```
106
107
### Panel Configurations
108
109
Pre-configured panel layouts for different menu types and components.
110
111
```python { .api }
112
# Main menu panel configurations
113
main_menu_content_panels: list
114
"""Content panels for main menu editing interface."""
115
116
flat_menu_content_panels: list
117
"""Content panels for flat menu editing interface."""
118
119
menu_settings_panels: list
120
"""Settings panels for menu configuration options."""
121
122
# Page-related panel configurations
123
linkpage_edit_handler: object
124
"""Edit handler for link pages in admin interface."""
125
126
menupage_settings_panels: list
127
"""Settings panels for menu-enabled pages."""
128
```
129
130
### Form Classes
131
132
Custom form classes for menu administration with validation and enhanced functionality.
133
134
```python { .api }
135
class FlatMenuAdminForm:
136
"""
137
Admin form for flat menus.
138
139
Provides validation and custom functionality for flat menu
140
creation and editing in the admin interface.
141
"""
142
143
class Meta:
144
model = 'FlatMenu'
145
fields = '__all__'
146
147
def clean_handle(self):
148
"""Validate flat menu handle uniqueness and format."""
149
150
def clean(self):
151
"""Perform cross-field validation for flat menu data."""
152
153
class LinkPageAdminForm:
154
"""
155
Admin form for link pages.
156
157
Provides validation for link pages ensuring proper URL
158
formatting and required field completion.
159
"""
160
161
class Meta:
162
model = 'AbstractLinkPage'
163
fields = '__all__'
164
165
def clean_link_url(self):
166
"""Validate link URL format and accessibility."""
167
168
class SiteSwitchForm:
169
"""
170
Form for switching between sites in multi-site setups.
171
172
Allows administrators to switch context between different
173
sites when managing menus in multi-site installations.
174
"""
175
176
site: 'Site' # Site selection field
177
178
def __init__(self, *args, **kwargs):
179
"""Initialize form with available sites."""
180
```
181
182
## Usage Examples
183
184
### Registering Menu Admin
185
186
```python
187
# In your wagtail_hooks.py or similar
188
from wagtail import hooks
189
from wagtailmenus.menuadmin import MainMenuAdmin, FlatMenuAdmin
190
191
# Admin classes are automatically registered by wagtailmenus
192
# But you can customize them:
193
194
@hooks.register('register_admin_menu_item')
195
def register_custom_menu_admin():
196
return MainMenuAdmin()
197
```
198
199
### Custom Menu Admin
200
201
```python
202
from wagtailmenus.menuadmin import FlatMenuAdmin
203
from wagtailmenus.models import FlatMenu
204
205
class CustomFlatMenuAdmin(FlatMenuAdmin):
206
"""Custom flat menu admin with additional functionality."""
207
208
list_display = ['title', 'handle', 'site', 'created_at']
209
list_filter = ['site', 'created_at']
210
search_fields = ['title', 'handle', 'heading']
211
212
def get_queryset(self, request):
213
"""Filter menus based on user permissions."""
214
qs = super().get_queryset(request)
215
216
if not request.user.is_superuser:
217
# Limit to current site for non-superusers
218
current_site = request.site
219
qs = qs.filter(site=current_site)
220
221
return qs
222
```
223
224
### Custom Inline Panels
225
226
```python
227
from wagtailmenus.panels import MenuItemInlinePanel
228
from wagtail.admin.panels import FieldPanel, InlinePanel
229
230
class CustomMenuItemInlinePanel(MenuItemInlinePanel):
231
"""Custom menu item inline with additional fields."""
232
233
panels = [
234
FieldPanel('link_text'),
235
FieldPanel('link_page'),
236
FieldPanel('link_url'),
237
FieldPanel('allow_subnav'),
238
FieldPanel('custom_css_class'), # Additional custom field
239
FieldPanel('icon'), # Additional custom field
240
]
241
242
extra = 0
243
min_num = 1
244
245
# Use in your menu model
246
class CustomFlatMenu(AbstractFlatMenu):
247
content_panels = [
248
FieldPanel('title'),
249
FieldPanel('handle'),
250
FieldPanel('heading'),
251
InlinePanel('menu_items', panels=CustomMenuItemInlinePanel.panels),
252
]
253
```
254
255
### Form Customization
256
257
```python
258
from wagtailmenus.forms import FlatMenuAdminForm
259
from django import forms
260
261
class CustomFlatMenuForm(FlatMenuAdminForm):
262
"""Custom form with additional validation."""
263
264
def clean_handle(self):
265
"""Custom handle validation."""
266
handle = self.cleaned_data.get('handle')
267
268
if handle:
269
# Ensure handle follows custom naming convention
270
if not handle.startswith('custom-'):
271
raise forms.ValidationError(
272
"Handle must start with 'custom-'"
273
)
274
275
# Check for conflicts with other handles
276
if handle in ['reserved', 'admin', 'api']:
277
raise forms.ValidationError(
278
"This handle is reserved and cannot be used"
279
)
280
281
return handle
282
283
def clean(self):
284
"""Cross-field validation."""
285
cleaned_data = super().clean()
286
title = cleaned_data.get('title')
287
handle = cleaned_data.get('handle')
288
289
if title and handle:
290
# Ensure handle relates to title
291
if not any(word in handle for word in title.lower().split()):
292
self.add_error('handle',
293
'Handle should relate to the menu title')
294
295
return cleaned_data
296
297
# Use custom form in admin
298
class CustomFlatMenuAdmin(FlatMenuAdmin):
299
form = CustomFlatMenuForm
300
```
301
302
### Panel Configuration Examples
303
304
```python
305
from wagtail.admin.panels import FieldPanel, InlinePanel, TabbedInterface, ObjectList
306
307
# Custom panel layout for main menus
308
custom_main_menu_panels = [
309
FieldPanel('site'),
310
FieldPanel('max_levels'),
311
FieldPanel('use_specific_templates'),
312
InlinePanel('menu_items', panels=[
313
FieldPanel('link_text'),
314
FieldPanel('link_page'),
315
FieldPanel('link_url'),
316
FieldPanel('allow_subnav'),
317
]),
318
]
319
320
# Tabbed interface for complex menus
321
class AdvancedFlatMenu(AbstractFlatMenu):
322
edit_handler = TabbedInterface([
323
ObjectList(flat_menu_content_panels, heading='Content'),
324
ObjectList(menu_settings_panels, heading='Settings'),
325
ObjectList([
326
FieldPanel('seo_title'),
327
FieldPanel('search_description'),
328
], heading='SEO'),
329
])
330
```
331
332
### Site Switching in Multi-Site Setup
333
334
```python
335
from wagtailmenus.forms import SiteSwitchForm
336
from django.shortcuts import render, redirect
337
338
def admin_menu_view(request):
339
"""Admin view with site switching capability."""
340
341
if request.method == 'POST':
342
form = SiteSwitchForm(request.POST)
343
if form.is_valid():
344
selected_site = form.cleaned_data['site']
345
# Store selected site in session
346
request.session['admin_site_id'] = selected_site.id
347
return redirect('wagtailmenus_mainmenu_index')
348
else:
349
# Initialize with current site
350
current_site = getattr(request, 'site', None)
351
form = SiteSwitchForm(initial={'site': current_site})
352
353
return render(request, 'admin/site_switch.html', {
354
'form': form,
355
'current_site': current_site,
356
})
357
```
358
359
## Types
360
361
```python { .api }
362
# Admin class attributes
363
class AdminTypes:
364
model: str | type
365
menu_label: str
366
menu_icon: str
367
list_display: list[str]
368
list_filter: list[str]
369
search_fields: list[str]
370
371
# Panel configuration types
372
class PanelTypes:
373
main_menu_content_panels: list
374
flat_menu_content_panels: list
375
menu_settings_panels: list
376
linkpage_edit_handler: object
377
menupage_settings_panels: list
378
379
# Form field types
380
class FormTypes:
381
handle: str
382
link_url: str
383
site: 'Site'
384
```