It's important to note that there is no documented method for utilizing Wagtail admin modals as they are.
However, by delving into the source code, you can harness the modal workflow to create your own custom modals. In Wagtail, this involves providing a server-side template response with render_modal_workflow
.
On the client side, there is a function available called ModalWorkflow
. This function calls a URL asynchronously and renders the HTML content within the modal upon response, expecting a response formatted by the aforementioned render_modal_workflow
helper.
With these fundamentals in place, you can incorporate open behavior via a button trigger, handle errors, execute render callbacks, and define callbacks based on values retrieved from within the modal.
Below is a basic example demonstrating how to render a modal in the admin using this approach.
Example
1. Render some HTML content with a button trigger
- For demonstration purposes, let's render a modal on the Wagtail home (dashboard) page.
- Using the
construct_homepage_panels
, we can add HTML to a panel partway down the page.
wagtail_hooks.py
from django.utils.safestring import mark_safe
from wagtail.core import hooks
class WelcomePanel:
order = 110
def render(self):
return mark_safe("""
<section class="panel summary nice-padding">
<h3>Dashboard Panel Section Title</h3>
<button data-modal-trigger="some-param">Open Modal</button>
</section>
""")
@hooks.register('construct_homepage_panels')
def add_another_welcome_panel(request, panels):
panels.append(WelcomePanel())
2. Ensure the modal-workflow JS script is loaded
- By default, only pages handling editing have the modal-workflow script loaded.
- To include it on this specific page, override the
wagtailadmin/home.html
template.
- Add jQuery to identify elements with the
data-modal-trigger
attribute and attach an onClick
listener to call our ModalWorkflow
function. Data passed back to the modal view can include any specific information.
templates/wagtailadmin/home.html
{% extends "wagtailadmin/home.html" %}
{% load wagtailadmin_tags %}
{% comment %}
Javascript declaration added to bring in the modal loader, by default it is only available on edit pages
example of usage - wagtail/search/templates/wagtailsearch/queries/chooser_field.js
{% endcomment %}
{% block extra_js %}
{{ block.super }}
<script src="{% versioned_static 'wagtailadmin/js/modal-workflow.js' %}"></script>
<script type="text/javascript">
$(function() {
$('[data-modal-trigger]').on('click', function(element) {
/* options passed in 'opts':
'url' (required): initial
'responses' (optional): dict of callbacks for when the modal content
calls modal.respond(callbackName, params)
'onload' (optional): dict of callbacks for loading steps of the workflow.
The 'step' field in the response identifies the callback to call, passing the
modal object and response data as arguments
*/
ModalWorkflow({
onError: function(error) { console.log('error', error); },
url: '/admin/modal/?trigger=' + element.target.dataset.modalTrigger
});
});
});
</script>
{% endblock %}
3. Create a view and URL to manage the modal requests
- Ensure there is an
admin/...
URL for requesting the modal content.
- This URL should lead to a view returning a response based on
render_modal_workflow
.
- You can initialize data on the client side alongside using a typical Django template response for the server-side rendered modal content.
views.py
from django.template.response import TemplateResponse
from wagtail.admin.modal_workflow import render_modal_workflow
def modal_view(request):
return render_modal_workflow(
request,
'base/modal.html', # html template
None, # js template
{'trigger': request.GET.get('trigger')}, # html template vars
json_data={'some': 'data'} # js template data
)
urls.py
from django.conf.urls import url
from .views import modal_view
urlpatterns = [
url(r'^admin/modal/', modal_view, name='modal'),
url(r'^admin/', include(wagtailadmin_urls)),
# ...
]
4. Set up your template to display the modal content
- All modals utilize the same shared header template to ensure consistency.
templates/base/modal.html
{% include "wagtailadmin/shared/header.html" with title="Modal Title" icon="no-view" %}
<div class="nice-padding">
<p>Modal Triggered by {{ trigger }}</p>
</div>