diff --git a/docs/core_components/pages/editing_api.rst b/docs/core_components/pages/editing_api.rst
index 3c5c790d0..a228421ea 100644
--- a/docs/core_components/pages/editing_api.rst
+++ b/docs/core_components/pages/editing_api.rst
@@ -376,6 +376,40 @@ For more on ``django-modelcluster``, visit `the django-modelcluster github proje
.. _the django-modelcluster github project page: https://github.com/torchbox/django-modelcluster
+.. _customising_the_tabbed_interface:
+
+Customising the tabbed interface
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+.. versionadded:: 0.9
+
+As standard, Wagtail organises panels into three tabs: 'Content', 'Promote' and 'Settings'. Depending on the requirements of your site, you may wish to customise this for specific page types - for example, adding an additional tab for sidebar content. This can be done by specifying an ``edit_handler`` property on the page model. For example:
+
+.. code-block:: python
+
+ from wagtail.wagtailadmin.edit_handlers import TabbedInterface, ObjectList
+
+ class BlogPage(Page):
+ # field definitions omitted
+
+ BlogPage.content_panels = [
+ FieldPanel('title', classname="full title"),
+ FieldPanel('date'),
+ FieldPanel('body', classname="full"),
+ ]
+ BlogPage.sidebar_content_panels = [
+ SnippetChooserPanel('advert', Advert),
+ InlinePanel('related_links', label="Related links"),
+ ]
+
+ BlogPage.edit_handler = TabbedInterface([
+ ObjectList(BlogPage.content_panels, heading='Content'),
+ ObjectList(BlogPage.sidebar_content_panels, heading='Sidebar content'),
+ ObjectList(BlogPage.promote_panels, heading='Promote'),
+ ObjectList(BlogPage.settings_panels, heading='Settings', classname="settings"),
+ ])
+
+
.. _extending_wysiwyg:
Extending the WYSIWYG Editor (hallo.js)
diff --git a/wagtail/tests/models.py b/wagtail/tests/models.py
index 59c20d4e5..bb6f5f007 100644
--- a/wagtail/tests/models.py
+++ b/wagtail/tests/models.py
@@ -14,7 +14,7 @@ from modelcluster.tags import ClusterTaggableManager
from wagtail.wagtailcore.models import Page, Orderable
from wagtail.wagtailcore.fields import RichTextField
-from wagtail.wagtailadmin.edit_handlers import FieldPanel, MultiFieldPanel, InlinePanel, PageChooserPanel
+from wagtail.wagtailadmin.edit_handlers import FieldPanel, MultiFieldPanel, InlinePanel, PageChooserPanel, TabbedInterface, ObjectList
from wagtail.wagtailimages.edit_handlers import ImageChooserPanel
from wagtail.wagtaildocs.edit_handlers import DocumentChooserPanel
from wagtail.wagtailforms.models import AbstractEmailForm, AbstractFormField
@@ -393,15 +393,27 @@ class StandardIndex(Page):
parent_page_types = []
+# A custom panel setup where all Promote fields are placed in the Content tab instead;
+# we use this to test that the 'promote' tab is left out of the output when empty
StandardIndex.content_panels = [
FieldPanel('title', classname="full title"),
+ FieldPanel('seo_title'),
+ FieldPanel('slug'),
InlinePanel('advert_placements', label="Adverts"),
]
+StandardIndex.promote_panels = []
class StandardChild(Page):
pass
+# Test overriding edit_handler with a custom one
+StandardChild.edit_handler = TabbedInterface([
+ ObjectList(StandardChild.content_panels, heading='Content'),
+ ObjectList(StandardChild.promote_panels, heading='Promote'),
+ ObjectList(StandardChild.settings_panels, heading='Settings', classname='settings'),
+ ObjectList([], heading='Dinosaurs'),
+])
class BusinessIndex(Page):
""" Can be placed anywhere, can only have Business children """
diff --git a/wagtail/wagtailadmin/tests/test_pages_views.py b/wagtail/wagtailadmin/tests/test_pages_views.py
index de8b2fb2b..be6cc6a26 100644
--- a/wagtail/wagtailadmin/tests/test_pages_views.py
+++ b/wagtail/wagtailadmin/tests/test_pages_views.py
@@ -158,6 +158,27 @@ class TestPageCreation(TestCase, WagtailTestUtils):
def test_create_simplepage(self):
response = self.client.get(reverse('wagtailadmin_pages_create', args=('tests', 'simplepage', self.root_page.id)))
self.assertEqual(response.status_code, 200)
+ self.assertContains(response, 'Content')
+ self.assertContains(response, 'Promote')
+
+ def test_create_page_without_promote_tab(self):
+ """
+ Test that the Promote tab is not rendered for page classes that define it as empty
+ """
+ response = self.client.get(reverse('wagtailadmin_pages_create', args=('tests', 'standardindex', self.root_page.id)))
+ self.assertEqual(response.status_code, 200)
+ self.assertContains(response, 'Content')
+ self.assertNotContains(response, 'Promote')
+
+ def test_create_page_with_custom_tabs(self):
+ """
+ Test that custom edit handlers are rendered
+ """
+ response = self.client.get(reverse('wagtailadmin_pages_create', args=('tests', 'standardchild', self.root_page.id)))
+ self.assertEqual(response.status_code, 200)
+ self.assertContains(response, 'Content')
+ self.assertContains(response, 'Promote')
+ self.assertContains(response, 'Dinosaurs')
def test_create_simplepage_bad_permissions(self):
# Remove privileges from user
diff --git a/wagtail/wagtailadmin/views/pages.py b/wagtail/wagtailadmin/views/pages.py
index a9c5c6fe5..f4c5c675d 100644
--- a/wagtail/wagtailadmin/views/pages.py
+++ b/wagtail/wagtailadmin/views/pages.py
@@ -707,11 +707,24 @@ PAGE_EDIT_HANDLERS = {}
def get_page_edit_handler(page_class):
if page_class not in PAGE_EDIT_HANDLERS:
- PAGE_EDIT_HANDLERS[page_class] = TabbedInterface([
- ObjectList(page_class.content_panels, heading='Content'),
- ObjectList(page_class.promote_panels, heading='Promote'),
- ObjectList(page_class.settings_panels, heading='Settings', classname="settings")
- ]).bind_to_model(page_class)
+ if hasattr(page_class, 'edit_handler'):
+ # use the edit handler specified on the page class
+ edit_handler = page_class.edit_handler
+ else:
+ # construct a TabbedInterface made up of content_panels, promote_panels
+ # and settings_panels, skipping any which are empty
+ tabs = []
+
+ if page_class.content_panels:
+ tabs.append(ObjectList(page_class.content_panels, heading='Content'))
+ if page_class.promote_panels:
+ tabs.append(ObjectList(page_class.promote_panels, heading='Promote'))
+ if page_class.settings_panels:
+ tabs.append(ObjectList(page_class.settings_panels, heading='Settings', classname="settings"))
+
+ edit_handler = TabbedInterface(tabs)
+
+ PAGE_EDIT_HANDLERS[page_class] = edit_handler.bind_to_model(page_class)
return PAGE_EDIT_HANDLERS[page_class]