1. We need to have custom page_header_buttons
tag to get all the action buttons in different form than as dropdown and not to mess up with the rest of templates:
In /app/templatetags/custom_tags.py
:
from django import template
from wagtail import hooks
from wagtail.admin.templatetags.wagtailadmin_tags import page_header_buttons
register = template.Library()
@register.inclusion_tag(
"wagtailadmin/pages/listing/custom_page_header_buttons.html", takes_context=True
)
def custom_page_header_buttons(context, page, page_perms):
return page_header_buttons(context, page, page_perms)
2. Now let's make custom buttons template in app/wagtailadmin/pages/listing/custom_page_header_buttons.html
(we can use core.css
actionbutton
class to style buttons):
{% load wagtailadmin_tags i18n %}
<nav aria-label="{{ title }}">
{% block content %}
{% for button in buttons %}
<div class="actionbutton mx-2 inline-block">
<a href="{{ button.url }}" aria-label="{{ button.attrs.title }}" class="button bicolor button--icon">
{% if button.icon_name %}
<span class="icon-wrapper">
{% icon name=button.icon_name %}
</span>
{% endif %}
{{ button.label }}
</a>
</div>
{% endfor %}
{% endblock %}
</nav>
3. Let's make breadcrumbs always extended by creating app/templates/wagtailadmin/shared/breadcrumbs.html
and removing button
, is_expanded
conditions and hidden
classes:
{% load i18n wagtailadmin_tags %}
{% comment "text/markdown" %}
The breadcrumb component is reused across all of Wagtail’s headers when the page tree context is needed.
Variables this template accepts:
`pages` - A list of wagtail page objects
`trailing_breadcrumb_title` (string?) - use this for a non linkable last breadcrumb
`classname` - Modifier classes
{% endcomment %}
{% with breadcrumb_link_classes='w-flex w-items-center w-h-full w-text-text-label w-pr-0.5 w-text-14 w-no-underline w-outline-offset-inside hover:w-underline hover:w-text-text-label w-h-full' breadcrumb_item_classes='w-h-full w-flex w-items-center w-overflow-hidden w-transition w-duration-300 w-whitespace-nowrap w-flex-shrink-0 w-font-bold' icon_classes='w-w-4 w-h-4 w-ml-3' %}
{# Breadcrumbs are visible on mobile by default but hidden on desktop #}
<div class="w-breadcrumb w-flex w-flex-row w-items-center w-overflow-x-auto w-overflow-y-hidden w-scrollbar-thin {{ classname }} w-pl-3" data-breadcrumb-next{% if not pages %} hidden{% endif %}>
<div class="w-relative w-h-slim-header w-mr-4 w-top-0 w-z-20 w-flex w-items-center w-flex-row w-flex-1 sm:w-flex-none w-transition w-duration-300">
<nav class="w-flex w-items-center w-flex-row w-h-full"
aria-label="{% trans 'Breadcrumb' %}">
<ol class="w-flex w-flex-row w-justify-start w-items-center w-h-full w-pl-0 w-my-0 w-gap-2 sm:w-gap-0 sm:w-space-x-2">
{% for page in pages %}
{% if page.is_root and url_root_name %}
{% url url_root_name as breadcrumb_url %}
{% else %}
{% url url_name page.id as breadcrumb_url %}
{% endif %}
{% if page.is_root %}
<li
class="{{ breadcrumb_item_classes }}"
data-breadcrumb-item
>
<a
class="{{ breadcrumb_link_classes }}"
href="{{ breadcrumb_url }}{{ querystring_value }}"
>
{% trans "Root" %}
</a>
{% icon name="arrow-right" classname=icon_classes %}
</li>
{% elif forloop.first %}
{# For limited-permission users whose breadcrumb starts further down from the root #}
<li
class="{{ breadcrumb_item_classes }}"
data-breadcrumb-item
>
<a class="{{ breadcrumb_link_classes }}" href="{{ breadcrumb_url }}{{ querystring_value }}">
{% trans "Root" %}
</a>
{% icon name="arrow-right" classname=icon_classes %}
</li>
{% elif forloop.last %}
<li
class="{{ breadcrumb_item_classes }}"
data-breadcrumb-item
>
<a class="{{ breadcrumb_link_classes }}"
href="{{ breadcrumb_url }}{{ querystring_value }}">
{{ page.get_admin_display_title }}
</a>
{% if trailing_breadcrumb_title %}
{% icon name="arrow-right" classname=icon_classes %}
{% endif %}
</li>
{% else %}
<li
class="{{ breadcrumb_item_classes }}"
data-breadcrumb-item
>
<a class="{{ breadcrumb_link_classes }}" href="{{ breadcrumb_url }}{{ querystring_value }}">
{{ page.get_admin_display_title }}
</a>
{% icon name="arrow-right" classname=icon_classes %}
</li>
{% endif %}
{% endfor %}
{% if trailing_breadcrumb_title %}
<li class="{{ breadcrumb_item_classes }}">
<div class="w-flex w-justify-start w-items-center">
{{ trailing_breadcrumb_title }}
</div>
</li>
{% endif %}
</ol>
</nav>
</div>
</div>
{% endwith %}
4. We need to make a new block in slim_header.html
because default ones cannot be used to have full width div with content.
We need to copy & paste wagtailadmin/templates/shared/headers/slim_header.html
file and add a new block at the end. Do not modify anything else, since it's a general template used for many purposes:
app/templates/wagtailadmin/shared/headers/slim_header.html
:
{% load wagtailadmin_tags i18n %}
{% fragment as nav_icon_classes %}w-w-4 w-h-4 group-hover:w-transform group-hover:w-scale-110{% endfragment %}
{% fragment as nav_icon_button_classes %}w-w-slim-header w-h-slim-header w-bg-transparent w-border-transparent w-box-border w-py-3 w-px-3 w-flex w-justify-center w-items-center w-outline-offset-inside w-text-text-meta w-transition w-group hover:w-text-text-label focus:w-text-text-label expanded:w-text-text-label expanded:w-border-y-2 expanded:w-border-b-current w-shrink-0{% endfragment %}
{% fragment as nav_icon_counter_classes %}-w-mr-3 w-py-0.5 w-px-[0.325rem] w-translate-y-[-8px] rtl:w-translate-x-[4px] w-translate-x-[-4px] w-text-[0.5625rem] w-font-bold w-text-text-button w-border w-border-surface-page w-rounded-[1rem]{% endfragment %}
{# Z index 99 to ensure header is always above #}
<style>
// for smaller header bar
.w-slim-header {
height: 50px;
}
// smaller buttons
@media screen { .button {
height: 2rem !important;
line-height: 1.8rem;
}}
</style>
<header class="w-slim-header w-flex w-flex-col sm:w-flex-row w-items-center w-justify-between w-bg-surface-header w-border-b w-border-border-furniture w-px-0 w-py-0 w-mb-0 w-relative w-top-0 w-z-header sm:w-sticky w-min-h-slim-header">
{# Padding left on mobile to give space for navigation toggle, #}
<div class="w-pl-slim-header sm:w-pl-5 w-min-h-slim-header sm:w-pr-2 w-w-full w-flex-1 w-overflow-x-auto w-box-border">
<div class="w-flex w-flex-1 w-items-center w-overflow-hidden">
{% block header_content %}
{% endblock %}
</div>
</div>
<div class="w-w-full sm:w-w-min w-flex sm:w-flex-nowrap sm:w-flex-row w-items-center w-p-0 sm:w-py-0 sm:w-pr-4 sm:w-justify-end">
{% block actions %}
{% endblock %}
</div>
</header>
{% block after_header %}
{% endblock %}
5. Finally we can create copy & paste wagtailadmin/pages/page_listing_header.html
to app/templates/wagtailadmin/pages/page_listing_header.html
and make necessary modifications:
{% extends 'wagtailadmin/shared/headers/slim_header.html' %}
{% load wagtailadmin_tags i18n %}
{# CUSTOM TAG! #}
{% load custom_tags %}
{% block header_content %}
{# Accessible page title #}
<h1 class="w-sr-only">
{{ title }}
</h1>
{# breadcrumbs #}
{% breadcrumbs parent_page 'wagtailadmin_explore' url_root_name='wagtailadmin_explore_root' is_expanded=parent_page.is_root classname='sm:w-py-3 lg:w-py-7' %}
{# Actions divider #}
<div class="w-w-px w-h-[30px] w-ml-auto sm:w-ml-0 w-bg-border-furniture"></div>
{# NOTHING MORE HERE! #}
{% endblock %}
{% block actions %}
{% if not parent_page.is_root %}
{% include "wagtailadmin/shared/side_panel_toggles.html" %}
{# Page history #}
{% if parent_page.get_latest_revision %}
<a href="{% url 'wagtailadmin_pages:history' parent_page.id %}"
class="{{ nav_icon_button_classes }}"
data-tippy-content="{% trans 'History' %}"
data-tippy-offset="[0, 0]"
data-tippy-placement="bottom"
aria-label="{% trans 'History' %}"
>
{% icon name="history" classname=nav_icon_classes %}
</a>
{% endif %}
{% include "wagtailadmin/shared/page_status_tag_new.html" with page=parent_page %}
{% endif %}
{% endblock %}
{% block after_header %}
{# OUR DIV WITH TITLE AND BUTTONS! #}
<div class="under-header w-mx-2 w-my-2">
<h1 class="sr-hidden">{{ title }}</h1>
{% custom_page_header_buttons parent_page page_perms=page_perms %}
</div>
{% endblock %}
This still needs a lot of styling but works. I'll publish full source of ready-to-go when I'll finish it. ;)