Repository: wagtail-nest/wagtail-modeladmin (language: python)

Issue:
Wagtail 6.2
This builds on the work done here: https://github.com/wagtail-nest/wagtail-modeladmin/pull/40

# Wagtail 6.2 upgrade check list
Add a link to the commit or file for each consideration if you made any code changes.
## Code reviewing a consideration.
Use the tick box to indicate a consideration has been code reviewed as OK
### Changes affecting all projects
  - [ ] [Specifying a dict of distribution ids for cloudfront cache invalidation is deprecated](https://docs.wagtail.org/en/stable/releases/6.2.html##specifying-a-dict-of-distribution-ids-for-cloudfront-cache-invalidation-is-deprecated)
  - [ ] [Changes to permissions registration for models with modelviewset and snippetviewset](https://docs.wagtail.org/en/stable/releases/6.2.html##changes-to-permissions-registration-for-models-with-modelviewset-and-snippetviewset)
  - [ ] [Deprecation of wagtail_user_edit_form, wagtail_user_creation_form, and wagtail_user_custom_fields settings](https://docs.wagtail.org/en/stable/releases/6.2.html##deprecation-of-wagtail-user-edit-form-wagtail-user-creation-form-and-wagtail-user-custom-fields-settings)
### Changes affecting wagtail customisations
  - [ ] [Changes to report views with the new universal listings ui](https://docs.wagtail.org/en/stable/releases/6.2.html##changes-to-report-views-with-the-new-universal-listings-ui)
### Changes to undocumented internals
  - [ ] [Deprecation of window.activateworkflowactionsfordashboard and window.activateworkflowactionsforeditview](https://docs.wagtail.org/en/stable/releases/6.2.html##deprecation-of-window-activateworkflowactionsfordashboard-and-window-activateworkflowactionsforeditview)


Discussion / hints:

Fix patch:
diff --git a/.github/scripts/report_nightly_build_failure.py b/.github/scripts/report_nightly_build_failure.py
index c89c519..5429115 100644
--- a/.github/scripts/report_nightly_build_failure.py
+++ b/.github/scripts/report_nightly_build_failure.py
@@ -3,6 +3,7 @@
 
 This reports an error to the #nightly-build-failures Slack channel.
 """
+
 import os
 
 import requests
diff --git a/.github/workflows/nightly.yml b/.github/workflows/nightly.yml
index c41a845..884108b 100644
--- a/.github/workflows/nightly.yml
+++ b/.github/workflows/nightly.yml
@@ -13,8 +13,8 @@ jobs:
       WEBHOOK_EXISTS: ${{ secrets.SLACK_WEBHOOK_URL != '' }}
 
     steps:
-      - uses: actions/checkout@v3
-      - uses: actions/setup-python@v4
+      - uses: actions/checkout@v4
+      - uses: actions/setup-python@v5
         with:
           python-version: '3.11'
 
diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml
index 7afbad6..ccfafaa 100644
--- a/.github/workflows/publish.yml
+++ b/.github/workflows/publish.yml
@@ -18,12 +18,12 @@ jobs:
     permissions:
       id-token: write
     steps:
-      - uses: actions/checkout@v3
+      - uses: actions/checkout@v4
         with:
           fetch-depth: 0
 
       - name: Set up Python 3.8
-        uses: actions/setup-python@v4
+        uses: actions/setup-python@v5
         with:
           python-version: '3.8'
 
diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml
index 74e34d9..0bafffe 100644
--- a/.pre-commit-config.yaml
+++ b/.pre-commit-config.yaml
@@ -19,7 +19,7 @@ repos:
       - id: end-of-file-fixer
       - id: trailing-whitespace
   - repo: https://github.com/psf/black
-    rev: 23.3.0
+    rev: 24.4.2
     hooks:
       - id: black
         language_version: python3
@@ -63,7 +63,7 @@ repos:
           - 'stylelint@15.6.1'
           - '@wagtail/stylelint-config-wagtail@0.6.0'
   - repo: https://github.com/adamchainz/blacken-docs
-    rev: 1.13.0
+    rev: 1.16.0
     hooks:
       - id: blacken-docs
-        additional_dependencies: [black==23.3.0]
+        additional_dependencies: [black==24.4.2]
diff --git a/CHANGELOG.md b/CHANGELOG.md
index af66568..0379357 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -5,6 +5,19 @@ All notable changes to this project will be documented in this file.
 The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
 and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
 
+## Unreleased
+
+### Added
+
+- Wagtail 6.1 and 6.2 support
+- Provisional support for Wagtail 6.3
+- Django 5.1 support
+- Python 3.13 support
+
+### Removed
+
+- Drop Python 3.8 from the testing matrix
+
 ## [2.0.0] - 2024-02-05
 
 ### Added
diff --git a/README.md b/README.md
index 1734f04..9a3a90b 100644
--- a/README.md
+++ b/README.md
@@ -18,9 +18,9 @@ This package is in maintenance mode and will not receive new features. Consider
 
 ## Supported versions
 
-- Python 3.8, 3.9, 3.10, 3.11, 3.12
-- Django 4.2, 5.0
-- Wagtail 5.2, 6.0
+- Python 3.8 (Wagtail 5.2 only), 3.9, 3.10, 3.11, 3.12, 3.13
+- Django 4.2, 5.0, 5.1
+- Wagtail 5.2, 6.1, 6.2, 6.3
 
 ## Installation
 
diff --git a/docs/primer.md b/docs/primer.md
index 2d1afff..773f16e 100644
--- a/docs/primer.md
+++ b/docs/primer.md
@@ -177,8 +177,7 @@ from wagtail_modeladmin.options import ModelAdmin, modeladmin_register
 from .models import MyModel
 
 
-class MyURLHelper(AdminURLHelper):
-    ...
+class MyURLHelper(AdminURLHelper): ...
 
 
 class MyModelAdmin(ModelAdmin):
@@ -215,8 +214,7 @@ from wagtail_modeladmin.options import ModelAdmin, modeladmin_register
 from .models import MyModel
 
 
-class MyPermissionHelper(PermissionHelper):
-    ...
+class MyPermissionHelper(PermissionHelper): ...
 
 
 class MyModelAdmin(ModelAdmin):
@@ -268,14 +266,11 @@ class MyButtonHelper(ButtonHelper):
             "title": _("Add a new %s") % self.verbose_name,
         }
 
-    def inspect_button(self, pk, classnames_add=None, classnames_exclude=None):
-        ...
+    def inspect_button(self, pk, classnames_add=None, classnames_exclude=None): ...
 
-    def edit_button(self, pk, classnames_add=None, classnames_exclude=None):
-        ...
+    def edit_button(self, pk, classnames_add=None, classnames_exclude=None): ...
 
-    def delete_button(self, pk, classnames_add=None, classnames_exclude=None):
-        ...
+    def delete_button(self, pk, classnames_add=None, classnames_exclude=None): ...
 
 
 class MyModelAdmin(ModelAdmin):
diff --git a/pyproject.toml b/pyproject.toml
index be433a5..453fda4 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -20,9 +20,11 @@ classifiers = [
     "Programming Language :: Python :: 3.10",
     "Programming Language :: Python :: 3.11",
     "Programming Language :: Python :: 3.12",
+    "Programming Language :: Python :: 3.13",
     "Framework :: Django",
     "Framework :: Django :: 4.2",
     "Framework :: Django :: 5.0",
+    "Framework :: Django :: 5.1",
     "Framework :: Wagtail",
     "Framework :: Wagtail :: 5",
     "Framework :: Wagtail :: 6",
@@ -30,7 +32,7 @@ classifiers = [
 dynamic = ["version"]
 requires-python = ">=3.8"
 dependencies = [
-    "Wagtail>=5.2"
+    "Wagtail>=5.2"  # Completely drop Python 3.8 support when we bump this to 6.3
 ]
 [project.optional-dependencies]
 testing = [
@@ -42,7 +44,7 @@ docs = [
     "myst_parser>=0.18.1,<1.0",
     "Sphinx>=6.0",
     "sphinx-autobuild>=0.6.0",
-    "sphinx-wagtail-theme==6.2.0",
+    "sphinx-wagtail-theme==6.3.0",
     "sphinxcontrib-spelling>=8.0,<9.0",
     "sphinx_copybutton>=0.5"
 ]
diff --git a/tox.ini b/tox.ini
index 8a92734..2d0e8d1 100644
--- a/tox.ini
+++ b/tox.ini
@@ -3,27 +3,28 @@ skipsdist = True
 usedevelop = True
 
 envlist =
-    python{3.8,3.9,3.10,3.11}-django{4.2,5.0}-wagtail{5.2,main}
-    python3.12-djangomain-wagtailmain
+    python{3.9,3.10,3.11}-django{4.2,5.0,main}-wagtail{5.2,6.1,6.2,main}
+    python{3.10,3.11,3.12}-django{5.0,main}-wagtail{5.2,6.1,6.2,main}
+    python3.13-django{5.1,main}-wagtail{6.3,main}
 
 [gh]
 python =
-    3.8 = python3.8-django{4.2}-wagtail{5.2}
     3.9 = python3.9-django{4.2}-wagtail{5.2,main}
-    3.10 = python3.10-django{4.2,5.0}-wagtail{5.2,6.0,main}
-    3.11 = python3.11-django{4.2,5.0}-wagtail{6.0,main}
-    3.12 = python3.12-djangomain-wagtailmain
+    3.10 = python3.10-django{4.2,5.0}-wagtail{5.2,6.1,6.2,main}
+    3.11 = python3.11-django{4.2,5.0}-wagtail{6.1,6.2,main}
+    3.12 = python3.12-django{4.2,5.0}-wagtail{6.1,6.2,main}
+    3.13 = python3.13-django{5.1,main}-wagtail{6.3,main}
 
 [testenv]
 install_command = pip install -e ".[testing]" -U {opts} {packages}
 commands = coverage run testmanage.py test --deprecation all {posargs: -v 2}
 
 basepython =
-    python3.8: python3.8
     python3.9: python3.9
     python3.10: python3.10
     python3.11: python3.11
     python3.12: python3.12
+    python3.13: python3.13
 
 deps =
     coverage
@@ -33,7 +34,9 @@ deps =
     djangomain: git+https://github.com/django/django.git@main#egg=Django
 
     wagtail5.2: wagtail>=5.2,<6.0
-    wagtail6.0: git+https://github.com/wagtail/wagtail.git@stable/6.0.x#egg=wagtail
+    wagtail6.1: wagtail>=6.1,<6.2
+    wagtail6.2: wagtail>=6.2,<6.3
+    wagtail6.3: git+https://github.com/wagtail/wagtail.git@stable/6.3.x#egg=wagtail
     wagtailmain: git+https://github.com/wagtail/wagtail.git#egg=wagtail
 
     postgres: psycopg2>=2.8.4
diff --git a/wagtail_modeladmin/static/wagtail_modeladmin/css/modeladmin.css b/wagtail_modeladmin/static/wagtail_modeladmin/css/modeladmin.css
index d0c6afc..3b27777 100644
--- a/wagtail_modeladmin/static/wagtail_modeladmin/css/modeladmin.css
+++ b/wagtail_modeladmin/static/wagtail_modeladmin/css/modeladmin.css
@@ -178,3 +178,9 @@
     width: 77.5%;
   }
 }
+
+.w-header .w-header__description {
+  /* Removed in Wagtail 6.3+ */
+  font-size: 1.125rem;
+  font-weight: 400;
+}
diff --git a/wagtail_modeladmin/templates/modeladmin/create.html b/wagtail_modeladmin/templates/modeladmin/create.html
index ac4f638..71d113c 100644
--- a/wagtail_modeladmin/templates/modeladmin/create.html
+++ b/wagtail_modeladmin/templates/modeladmin/create.html
@@ -34,7 +34,7 @@
         {% block footer %}
             <footer class="footer">
                 <ul>
-                    <li class="actions footer__container">
+                    <li class="actions actions--primary footer__container">
                         {% block form_actions %}
                             {% fragment as default_action_item %}
                                 <button
diff --git a/wagtail_modeladmin/templates/modeladmin/includes/header.html b/wagtail_modeladmin/templates/modeladmin/includes/header.html
new file mode 100644
index 0000000..f25bef7
--- /dev/null
+++ b/wagtail_modeladmin/templates/modeladmin/includes/header.html
@@ -0,0 +1,92 @@
+{# Copied from Wagtail before 6.3 #}
+{% load i18n wagtailadmin_tags %}
+{% comment "text/markdown" %}
+
+    Variables accepted by this template:
+
+    - `classname` - if present, adds classname to the header class list
+    - `title` - Displayed as `h1`
+    - `subtitle` - Within the `h1` tag but smaller
+    - `description` - if present, displayed as a small text below the `h1` tag title
+    - `search_url` - if present, display a search box. This is a URL route name (taking no parameters) to be used as the action for that search box
+    - `search_form` - form object for the search form. Required if search_url is passed
+    - `search_results_url` - URL to be used for async requests to search results, if not provided, the form's action URL will be used
+    - `search_target` - A selector string to be used as the target for the search results to be swapped into. Defaults to '#listing-results'
+    - `search_disable_async` - If True, the default header async search functionality will not be used
+    - `query_parameters` - a query string (without the '?') to be placed after the search URL
+    - `icon` - name of an icon to place against the title
+    - `avatar` - if present, display an 'avatar' in place of icon. This is the URL to be used as the img src for avatar
+    - `merged` - if true, add the classname 'w-header--merged'
+    - `action_url` - if present, display an 'action' button. This is the URL to be used as the link URL for the button
+    - `action_text` - text for the 'action' button
+    - `action_icon` - icon for the 'action' button, default is 'plus'
+    - `base_actions` - base actions to appear before the main action
+    - `extra_actions` - extra action buttons for the header. This is the HTML to be used for the extra buttons
+    - `heading` - Replaces the header `h1` completely with custom variable content
+    - `search` - An alternative search content variable displayed if provided and search_url url is not present
+    - `extra_rows` - Shown at the end of the header container
+
+{% endcomment %}
+<header class="{% classnames "w-header" classname merged|yesno:"w-header--merged," search_form|yesno:"w-header--hasform," %}">
+    <div class="row">
+        <div class="left">
+            <div class="col">
+                {% if heading %}
+                    {{ heading }}
+                {% else %}
+                    <h1 class="w-header__title" id="header-title">
+                        {% if icon %}
+                            {% icon classname="w-header__glyph" name=icon %}
+                        {% elif avatar %}
+                            <div class="w-header__glyph avatar large"><img src="{{ avatar }}" alt="" /></div>
+                        {% endif %}
+                        {{ title }}{% if subtitle %} <span class="w-header__subtitle">{{ subtitle }}</span>{% endif %}
+                    </h1>
+                {% endif %}
+                {% if description %}<div class="w-header__description">{{ description }}</div>{% endif %}
+            </div>
+            {% if search_url %}
+                <form
+                    class="col search-form"
+                    action="{% url search_url %}{% if query_parameters %}?{{ query_parameters }}{% endif %}"
+                    method="get"
+                    novalidate
+                    role="search"
+                    {% if not search_disable_async %}
+                        data-controller="w-swap"
+                        data-action="change->w-swap#searchLazy input->w-swap#searchLazy"
+                        {% if search_results_url %}data-w-swap-src-value="{{ search_results_url }}"{% endif %}
+                        {% if search_target %}data-w-swap-target-value="{{ search_target }}"{% endif %}
+                    {% endif %}
+                >
+                    {% for field in search_form %}
+                        {% formattedfield field=field classname="w-mb-0 -w-mt-2.5" sr_only_label=True icon="search" %}
+                    {% endfor %}
+                    {% comment %}Add an initial disabled & hidden submit button so that pressing 'enter' will not submit form. Reload not required as the content is dynamically loaded.{% endcomment %}
+                    <div class="w-sr-only"><input disabled type="submit" aria-hidden="true"/></div>
+                    <div class="submit w-sr-only"><input type="submit" value="Search" class="button" /></div>
+                </form>
+            {% elif search %}
+                {{ search }}
+            {% endif %}
+        </div>
+        <div class="{% block right_column_classname %}right{% endblock %}">
+            {% if base_actions %}
+                {{ base_actions }}
+            {% endif %}
+            {% block right_column %}
+                {% if action_url %}
+                    <div class="actionbutton">
+                        {% with action_icon|default:'plus' as action_icon_name %}
+                            <a href="{{ action_url }}" class="button bicolor button--icon">{% icon name=action_icon_name wrapped=1 %}{{ action_text|capfirst }}</a>
+                        {% endwith %}
+                    </div>
+                {% endif %}
+            {% endblock %}
+            {% if extra_actions %}
+                {{ extra_actions }}
+            {% endif %}
+        </div>
+    </div>
+    {% block extra_rows %}{{ extra_rows }}{% endblock %}
+</header>
diff --git a/wagtail_modeladmin/templates/modeladmin/index.html b/wagtail_modeladmin/templates/modeladmin/index.html
index c998ba6..26beedc 100644
--- a/wagtail_modeladmin/templates/modeladmin/index.html
+++ b/wagtail_modeladmin/templates/modeladmin/index.html
@@ -19,6 +19,7 @@
     {% block header %}
         {% fragment as breadcrumb %}{% block breadcrumb %}{% endblock %}{% endfragment %}
         {% fragment as heading %}{% block h1 %}{% endblock %}{% endfragment %}
+        {# Support for the description fragment is removed in Wagtail 6.3 #}
         {% fragment as description %}{% include 'modeladmin/includes/result_count.html' %}{% endfragment %}
         {% fragment as extra_actions %}
             {% block header_extra %}
@@ -32,7 +33,9 @@
         {% endfragment %}
         {% fragment as search %}{% block search %}{% search_form %}{% endblock %}{% endfragment %}
         {% fragment as extra_rows %}{% block extra_rows %}{% endblock %}{% endfragment %}
-        {% include 'wagtailadmin/shared/header.html' with classname="w-header--hasform" breadcrumb=breadcrumb heading=heading title=view.get_page_title subtitle=view.get_page_subtitle icon=view.header_icon description=description search=search extra_actions=extra_actions extra_rows=extra_rows %}
+        {% wagtail_version 6 3 as wagtail63 %}
+        {% fragment as header_template_name %}{% if wagtail63 %}modeladmin/includes/header.html{% else %}wagtailadmin/shared/header.html{% endif %}{% endfragment %}
+        {% include header_template_name with classname="w-header--hasform" breadcrumb=breadcrumb heading=heading title=view.get_page_title subtitle=view.get_page_subtitle icon=view.header_icon description=description search=search extra_actions=extra_actions extra_rows=extra_rows %}
     {% endblock %}
 
     {% block content_main %}


Test patch:
diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml
index 7804c47..c6137cd 100644
--- a/.github/workflows/test.yml
+++ b/.github/workflows/test.yml
@@ -19,28 +19,26 @@ jobs:
   lint:
     runs-on: ubuntu-latest
     steps:
-      - uses: actions/checkout@v3
+      - uses: actions/checkout@v4
         with:
           fetch-depth: 0
-      - name: Set up Python 3.8
-        uses: actions/setup-python@v4
+      - name: Set up Python 3.13
+        uses: actions/setup-python@v5
         with:
-          python-version: '3.8'
-      - uses: pre-commit/action@v2.0.3
-        with:
-          token: ${{ secrets.GITHUB_TOKEN }}
+          python-version: '3.13'
+      - uses: pre-commit/action@v3.0.1
 
   test-sqlite:
     runs-on: ubuntu-latest
     needs: lint
     strategy:
       matrix:
-        python: ['3.8', '3.9', '3.10', '3.11', '3.12']
+        python: ['3.9', '3.10', '3.11', '3.12', '3.13']
 
     steps:
-      - uses: actions/checkout@v3
+      - uses: actions/checkout@v4
       - name: Set up Python ${{ matrix.python }}
-        uses: actions/setup-python@v4
+        uses: actions/setup-python@v5
         with:
           python-version: ${{ matrix.python }}
       - name: Install Tox
@@ -57,12 +55,14 @@ jobs:
     needs: lint
     strategy:
       matrix:
-        python: ['3.8', '3.9', '3.10']
+        python: ['3.9', '3.10']
         include:
           - python: '3.11'
             postgres: '12'
           - python: '3.12'
             postgres: '13'
+          - python: '3.13'
+            postgres: '17'
 
     services:
       postgres:
@@ -74,9 +74,9 @@ jobs:
         options: --health-cmd pg_isready --health-interval 10s --health-timeout 5s --health-retries 5
 
     steps:
-      - uses: actions/checkout@v3
+      - uses: actions/checkout@v4
       - name: Set up Python ${{ matrix.python }}
-        uses: actions/setup-python@v4
+        uses: actions/setup-python@v5
         with:
           python-version: ${{ matrix.python }}
       - name: Install Tox
diff --git a/wagtail_modeladmin/test/migrations/0002_customimage_description_and_more.py b/wagtail_modeladmin/test/migrations/0002_customimage_description_and_more.py
new file mode 100644
index 0000000..d430016
--- /dev/null
+++ b/wagtail_modeladmin/test/migrations/0002_customimage_description_and_more.py
@@ -0,0 +1,101 @@
+# Generated by Django 4.2.3 on 2024-10-23 10:36
+
+from django.db import migrations, models
+from wagtail import VERSION as WAGTAIL_VERSION
+import django.db.models.deletion
+
+
+class Migration(migrations.Migration):
+    dependencies = [
+        ("wagtailcore", "0094_alter_page_locale"),
+        ("modeladmintest", "0001_initial"),
+    ]
+
+    operations = [
+        migrations.AddField(
+            model_name="customimage",
+            name="description",
+            field=models.CharField(
+                blank=True, default="", max_length=255, verbose_name="description"
+            ),
+        ),
+        migrations.AlterField(
+            model_name="customdocument",
+            name="file_size",
+            field=models.PositiveBigIntegerField(editable=False, null=True),
+        ),
+        migrations.AlterField(
+            model_name="eventcategory",
+            name="locale",
+            field=models.ForeignKey(
+                editable=False,
+                on_delete=django.db.models.deletion.PROTECT,
+                related_name="+",
+                to="wagtailcore.locale",
+                verbose_name="locale",
+            ),
+        ),
+        migrations.AlterField(
+            model_name="eventpagecarouselitem",
+            name="locale",
+            field=models.ForeignKey(
+                editable=False,
+                on_delete=django.db.models.deletion.PROTECT,
+                related_name="+",
+                to="wagtailcore.locale",
+                verbose_name="locale",
+            ),
+        ),
+        migrations.AlterField(
+            model_name="eventpagerelatedlink",
+            name="locale",
+            field=models.ForeignKey(
+                editable=False,
+                on_delete=django.db.models.deletion.PROTECT,
+                related_name="+",
+                to="wagtailcore.locale",
+                verbose_name="locale",
+            ),
+        ),
+        migrations.AlterField(
+            model_name="eventpagespeaker",
+            name="locale",
+            field=models.ForeignKey(
+                editable=False,
+                on_delete=django.db.models.deletion.PROTECT,
+                related_name="+",
+                to="wagtailcore.locale",
+                verbose_name="locale",
+            ),
+        ),
+        migrations.AlterField(
+            model_name="eventpagespeakeraward",
+            name="locale",
+            field=models.ForeignKey(
+                editable=False,
+                on_delete=django.db.models.deletion.PROTECT,
+                related_name="+",
+                to="wagtailcore.locale",
+                verbose_name="locale",
+            ),
+        ),
+        migrations.AlterField(
+            model_name="translatablebook",
+            name="locale",
+            field=models.ForeignKey(
+                editable=False,
+                on_delete=django.db.models.deletion.PROTECT,
+                related_name="+",
+                to="wagtailcore.locale",
+                verbose_name="locale",
+            ),
+        ),
+    ]
+
+
+if WAGTAIL_VERSION < (6, 3):
+
+    class Migration(migrations.Migration):
+        dependencies = [
+            ("modeladmintest", "0001_initial"),
+        ]
diff --git a/wagtail_modeladmin/test/models.py b/wagtail_modeladmin/test/models.py
index 3b5708a..97b0470 100644
--- a/wagtail_modeladmin/test/models.py
+++ b/wagtail_modeladmin/test/models.py
@@ -11,6 +11,7 @@
     MultiFieldPanel,
     ObjectList,
     TabbedInterface,
+    TitleFieldPanel,
 )
 from wagtail.documents.models import AbstractDocument, Document
 from wagtail.fields import RichTextField
@@ -62,7 +63,7 @@ class SimplePage(Page):
     page_description = "A simple page description"
 
     content_panels = [
-        FieldPanel("title", classname="title"),
+        TitleFieldPanel("title", classname="title"),
         FieldPanel("content"),
     ]
 
@@ -304,7 +305,7 @@ def get_cached_paths(self):
         return super().get_cached_paths() + ["/past/"]
 
     content_panels = [
-        FieldPanel("title", classname="title"),
+        TitleFieldPanel("title", classname="title"),
         FieldPanel("intro"),
     ]
 
@@ -357,7 +358,7 @@ class EventPage(Page):
     base_form_class = EventPageForm
 
     content_panels = [
-        FieldPanel("title", classname="title"),
+        TitleFieldPanel("title", classname="title"),
         FieldPanel("date_from"),
         FieldPanel("date_to"),
         FieldPanel("time_from"),
diff --git a/wagtail_modeladmin/test/tests/test_page_modeladmin.py b/wagtail_modeladmin/test/tests/test_page_modeladmin.py
index 3be40c6..b98f3b5 100644
--- a/wagtail_modeladmin/test/tests/test_page_modeladmin.py
+++ b/wagtail_modeladmin/test/tests/test_page_modeladmin.py
@@ -375,10 +375,18 @@ def setUp(self):
             Permission.objects.get(codename="access_admin")
         )
         GroupPagePermission.objects.create(
-            group=business_editors, page=business_index, permission_type="add"
+            group=business_editors,
+            page=business_index,
+            permission=Permission.objects.get(
+                content_type__app_label="wagtailcore", codename="add_page"
+            ),
         )
         GroupPagePermission.objects.create(
-            group=business_editors, page=another_business_index, permission_type="add"
+            group=business_editors,
+            page=another_business_index,
+            permission=Permission.objects.get(
+                content_type__app_label="wagtailcore", codename="add_page"
+            ),
         )
 
         user = self.create_user(username="test2", password="password")