I have some custom logic (complex unique constraint validation) I would like to check when a user attempts to copy (or move) a certain type of Page in Wagtail. I would also like to give the user an opportunity to change the fields associated with the validation check.
I am aware of the fact that Wagtail exposes a way of customizing the copy (and move) experiences through hooks (http://docs.wagtail.io/en/stable/reference/hooks.html#before-copy-page), but the best I can come up with using that tool is to create a completely new interface and return it in a HttpResponse. Is there a way to merely customize the existing copy (and move) interface for a specific page type?
@hooks.register('before-copy-page')
def before-copy-page(request, page):
return HttpResponse("New copy interface", content_type="text/plain")
These three approaches get you deeper into a customisation for the Wagtail page copy view and validation. You may not need to do all three but the example code below assumes all changes have been done to some extent.
There might be better ways to do the exact thing you want but hopefully this gives you a few ways to customise parts of the entire copy view/form interaction.
These approaches should work for the move pages interaction but that has a few more forms and views.
templates/wagtailadmin/pages/copy.html
will override the copy page form template.{% extends "wagtailadmin/pages/copy.html" %}
at the top, this saves us having to copy/past most of the page and only customise the blocks we need.{{ block.super }}
could come in handy here if you only wanted to add something to the start or end of a block within the template.admin/
urls, this will be accessed first.url(r'^admin/pages/(\d+)/copy/$', base_views.customCopy, name='copy'),
, this will direct the admin copy page to our customCopy
view.CopyForm
CopyForm
and customise its __init__
or clean
methods (or any others as needed).CopyForm
to see what you need to modify, if you wanted to add fields to the form, this (along with the template changes) will be needed.{% extends "wagtailadmin/pages/copy.html" %}
{% load i18n %}
{% block content %}
{% comment %} source - wagtail/admin/templates/wagtailadmin/pages/copy.html {% endcomment %}
{% trans "Copy" as copy_str %}
{% include "wagtailadmin/shared/header.html" with title=copy_str subtitle=page.get_admin_display_title icon="doc-empty-inverse" %}
<div class="nice-padding">
<form action="{% url 'wagtailadmin_pages:copy' page.id %}" method="POST" novalidate>
{% csrf_token %}
<input type="hidden" name="next" value="{{ next }}" />
<ul class="fields">
{% include "wagtailadmin/shared/field_as_li.html" with field=form.new_title %}
{% include "wagtailadmin/shared/field_as_li.html" with field=form.new_slug %}
{% include "wagtailadmin/shared/field_as_li.html" with field=form.new_parent_page %}
{% if form.copy_subpages %}
{% include "wagtailadmin/shared/field_as_li.html" with field=form.copy_subpages %}
{% endif %}
{% if form.publish_copies %}
{% include "wagtailadmin/shared/field_as_li.html" with field=form.publish_copies %}
{% endif %}
{% comment %} BEGIN CUSTOM CONTENT {% endcomment %}
{% include "wagtailadmin/shared/field_as_li.html" with field=form.other %}
{% comment %} END CUSTOM CONTENT {% endcomment %}
</ul>
<input type="submit" value="{% trans 'Copy this page' %}" class="button">
</form>
</div>
{% endblock %}
from django.conf.urls import include, url
from django.contrib import admin
from wagtail.admin import urls as wagtailadmin_urls
from wagtail.admin.views import pages
from wagtail.documents import urls as wagtaildocs_urls
from wagtail.core import urls as wagtail_urls
from myapp.base import views as base_views # added
urlpatterns = [
url(r'^django-admin/', admin.site.urls),
url(r'^admin/pages/(\d+)/copy/$', base_views.customCopy, name='copy'), # added
url(r'^admin/', include(wagtailadmin_urls)),
url(r'^documents/', include(wagtaildocs_urls)),
url(r'', include(wagtail_urls)),
]
from django import forms
from django.core.exceptions import PermissionDenied
from wagtail.admin.forms.pages import CopyForm
from wagtail.admin.views import pages
from wagtail.core.models import Page
# BEGIN monkey patch of CopyForm
# See: wagtail/admin/forms/pages.py
original_form_init = CopyForm.__init__
original_form_clean = CopyForm.clean
def custom_form_init(self, *args, **kwargs):
# note - the template will need to be overridden to show additional fields
original_form_init(self, *args, **kwargs)
self.fields['other'] = forms.CharField(initial="will fail", label="Other", required=False)
def custom_form_clean(self):
cleaned_data = original_form_clean(self)
other = cleaned_data.get('other')
if other == 'will fail':
self._errors['other'] = self.error_class(["This field failed due to custom form validation"])
del cleaned_data['other']
return cleaned_data
CopyForm.__init__ = custom_form_init
CopyForm.clean = custom_form_clean
# END monkey patch of CopyForm
def customCopy(request, page_id):
"""
here we can inject any custom code for the response as a whole
the template is a view function so we cannot easily customise it
we can respond to POST or GET with any customisations though
See: wagtail/admin/views/pages.py
"""
page = Page.objects.get(id=page_id)
# Parent page defaults to parent of source page
parent_page = page.get_parent()
# Check if the user has permission to publish subpages on the parent
can_publish = parent_page.permissions_for_user(request.user).can_publish_subpage()
# Create the form
form = CopyForm(request.POST or None, user=request.user, page=page, can_publish=can_publish)
if request.method == 'POST':
if form.is_valid():
# if the form has been validated (using the form clean above)
# we get another chance here to fail the request, or redirect to another page
# we can also easily access the specific page's model for any Page model methods
try:
if not page.specific.can_copy_check():
raise PermissionDenied
except AttributeError:
# continue through to the normal behaviour
pass
response = pages.copy(request, page_id)
return response
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With