Jelajahi Sumber

documentation - update reference/contrib content to markdown

LB Johnston 2 tahun lalu
induk
melakukan
1849122e5f

+ 200 - 234
docs/reference/contrib/frontendcache.md

@@ -1,167 +1,149 @@
-.. _frontend_cache_purging:
+(frontend_cache_purging)=
 
-Frontend cache invalidator
-==========================
+# Frontend cache invalidator
 
 Many websites use a frontend cache such as Varnish, Squid, Cloudflare or CloudFront to gain extra performance. The downside of using a frontend cache though is that they don't respond well to updating content and will often keep an old version of a page cached after it has been updated.
 
 This document describes how to configure Wagtail to purge old versions of pages from a frontend cache whenever a page gets updated.
 
+## Setting it up
 
-Setting it up
--------------
+Firstly, add `"wagtail.contrib.frontend_cache"` to your `INSTALLED_APPS`:
 
-Firstly, add ``"wagtail.contrib.frontend_cache"`` to your INSTALLED_APPS:
-
-.. code-block:: python
-
-    INSTALLED_APPS = [
-      ...
-
-      "wagtail.contrib.frontend_cache"
-    ]
-
-The ``wagtailfrontendcache`` module provides a set of signal handlers which will automatically purge the cache whenever a page is published or deleted. These signal handlers are automatically registered when the ``wagtail.contrib.frontend_cache`` app is loaded.
+```python
+INSTALLED_APPS = [
+    ...
 
+    "wagtail.contrib.frontend_cache"
+]
+```
 
-Varnish/Squid
-^^^^^^^^^^^^^
+The `wagtailfrontendcache` module provides a set of signal handlers which will automatically purge the cache whenever a page is published or deleted. These signal handlers are automatically registered when the `wagtail.contrib.frontend_cache` app is loaded.
 
-Add a new item into the ``WAGTAILFRONTENDCACHE`` setting and set the ``BACKEND`` parameter to ``wagtail.contrib.frontend_cache.backends.HTTPBackend``. This backend requires an extra parameter ``LOCATION`` which points to where the cache is running (this must be a direct connection to the server and cannot go through another proxy).
+### Varnish/Squid
 
-.. code-block:: python
+Add a new item into the `WAGTAILFRONTENDCACHE` setting and set the `BACKEND` parameter to `wagtail.contrib.frontend_cache.backends.HTTPBackend`. This backend requires an extra parameter `LOCATION` which points to where the cache is running (this must be a direct connection to the server and cannot go through another proxy).
 
-    # settings.py
+```python
+# settings.py
 
-    WAGTAILFRONTENDCACHE = {
-        'varnish': {
-            'BACKEND': 'wagtail.contrib.frontend_cache.backends.HTTPBackend',
-            'LOCATION': 'http://localhost:8000',
-        },
-    }
-    WAGTAILFRONTENDCACHE_LANGUAGES = []
+WAGTAILFRONTENDCACHE = {
+    'varnish': {
+        'BACKEND': 'wagtail.contrib.frontend_cache.backends.HTTPBackend',
+        'LOCATION': 'http://localhost:8000',
+    },
+}
+WAGTAILFRONTENDCACHE_LANGUAGES = []
+```
 
-
-Set ``WAGTAILFRONTENDCACHE_LANGUAGES`` to a list of languages (typically equal to ``[l[0] for l in settings.LANGUAGES]``) to also purge the urls for each language of a purging url. This setting needs ``settings.USE_I18N`` to be ``True`` to work. Its default is an empty list.
+Set `WAGTAILFRONTENDCACHE_LANGUAGES` to a list of languages (typically equal to `[l[0] for l in settings.LANGUAGES]`) to also purge the urls for each language of a purging url. This setting needs `settings.USE_I18N` to be `True` to work. Its default is an empty list.
 
 Finally, make sure you have configured your frontend cache to accept PURGE requests:
 
-- `Varnish <https://www.varnish-cache.org/docs/3.0/tutorial/purging.html>`_
-- `Squid <https://wiki.squid-cache.org/SquidFaq/OperatingSquid#How_can_I_purge_an_object_from_my_cache.3F>`_
-
+-   [Varnish](https://www.varnish-cache.org/docs/3.0/tutorial/purging.html)
+-   [Squid](https://wiki.squid-cache.org/SquidFaq/OperatingSquid#How_can_I_purge_an_object_from_my_cache.3F)
 
-.. _frontendcache_cloudflare:
+(frontendcache_cloudflare)=
 
-Cloudflare
-^^^^^^^^^^
+### Cloudflare
 
-Firstly, you need to register an account with Cloudflare if you haven't already got one. You can do this here: `Cloudflare Sign up <https://www.cloudflare.com/sign-up>`_
+Firstly, you need to register an account with Cloudflare if you haven't already got one. You can do this here: [Cloudflare Sign up](https://www.cloudflare.com/sign-up).
 
-Add an item into the ``WAGTAILFRONTENDCACHE`` and set the ``BACKEND`` parameter to ``wagtail.contrib.frontend_cache.backends.CloudflareBackend``.
+Add an item into the `WAGTAILFRONTENDCACHE` and set the `BACKEND` parameter to `wagtail.contrib.frontend_cache.backends.CloudflareBackend`.
 
 This backend can be configured to use an account-wide API key, or an API token with restricted access.
 
-To use an account-wide API key, find the key `as described in the Cloudflare documentation <https://support.cloudflare.com/hc/en-us/articles/200167836-Managing-API-Tokens-and-Keys#12345682>`_ and specify ``EMAIL`` and ``API_KEY`` parameters.
+To use an account-wide API key, find the key [as described in the Cloudflare documentation](https://support.cloudflare.com/hc/en-us/articles/200167836-Managing-API-Tokens-and-Keys#12345682) and specify `EMAIL` and `API_KEY` parameters.
 
-To use a limited API token, `create a token <https://support.cloudflare.com/hc/en-us/articles/200167836-Managing-API-Tokens-and-Keys#12345680>`_ configured with the 'Zone, Cache Purge' permission and specify the ``BEARER_TOKEN`` parameter.
+To use a limited API token, [create a token](https://support.cloudflare.com/hc/en-us/articles/200167836-Managing-API-Tokens-and-Keys#12345680) configured with the 'Zone, Cache Purge' permission and specify the `BEARER_TOKEN` parameter.
 
-A ``ZONEID`` parameter will need to be set for either option. To find the ``ZONEID`` for your domain, read the `Cloudflare API Documentation <https://developers.cloudflare.com/fundamentals/get-started/basic-tasks/find-account-and-zone-ids/>`_.
+A `ZONEID` parameter will need to be set for either option. To find the `ZONEID` for your domain, read the [Cloudflare API Documentation](https://developers.cloudflare.com/fundamentals/get-started/basic-tasks/find-account-and-zone-ids/).
 
 With an API key:
 
-.. code-block:: python
+```python
+# settings.py
 
-    # settings.py
-
-    WAGTAILFRONTENDCACHE = {
-        'cloudflare': {
-            'BACKEND': 'wagtail.contrib.frontend_cache.backends.CloudflareBackend',
-            'EMAIL': 'your-cloudflare-email-address@example.com',
-            'API_KEY': 'your cloudflare api key',
-            'ZONEID': 'your cloudflare domain zone id',
-        },
-    }
+WAGTAILFRONTENDCACHE = {
+    'cloudflare': {
+        'BACKEND': 'wagtail.contrib.frontend_cache.backends.CloudflareBackend',
+        'EMAIL': 'your-cloudflare-email-address@example.com',
+        'API_KEY': 'your cloudflare api key',
+        'ZONEID': 'your cloudflare domain zone id',
+    },
+}
+```
 
 With an API token:
 
-.. code-block:: python
-
-    # settings.py
+```python
+# settings.py
 
-    WAGTAILFRONTENDCACHE = {
-        'cloudflare': {
-            'BACKEND': 'wagtail.contrib.frontend_cache.backends.CloudflareBackend',
-            'BEARER_TOKEN': 'your cloudflare bearer token',
-            'ZONEID': 'your cloudflare domain zone id',
-        },
-    }
-
-.. _frontendcache_aws_cloudfront:
+WAGTAILFRONTENDCACHE = {
+    'cloudflare': {
+        'BACKEND': 'wagtail.contrib.frontend_cache.backends.CloudflareBackend',
+        'BEARER_TOKEN': 'your cloudflare bearer token',
+        'ZONEID': 'your cloudflare domain zone id',
+    },
+}
+```
 
-Amazon CloudFront
-^^^^^^^^^^^^^^^^^
+(frontendcache_aws_cloudfront)=
 
-Within Amazon Web Services you will need at least one CloudFront web distribution. If you don't have one, you can get one here: `CloudFront getting started <https://aws.amazon.com/cloudfront/>`_
+### Amazon CloudFront
 
-Add an item into the ``WAGTAILFRONTENDCACHE`` and set the ``BACKEND`` parameter to ``wagtail.contrib.frontend_cache.backends.CloudfrontBackend``. This backend requires one extra parameter, ``DISTRIBUTION_ID`` (your CloudFront generated distribution id).
+Within Amazon Web Services you will need at least one CloudFront web distribution. If you don't have one, you can get one here: [CloudFront getting started](https://aws.amazon.com/cloudfront/)
 
-.. code-block:: python
+Add an item into the `WAGTAILFRONTENDCACHE` and set the `BACKEND` parameter to `wagtail.contrib.frontend_cache.backends.CloudfrontBackend`. This backend requires one extra parameter, `DISTRIBUTION_ID` (your CloudFront generated distribution id).
 
-    WAGTAILFRONTENDCACHE = {
-        'cloudfront': {
-            'BACKEND': 'wagtail.contrib.frontend_cache.backends.CloudfrontBackend',
-            'DISTRIBUTION_ID': 'your-distribution-id',
-        },
-    }
+```python
+WAGTAILFRONTENDCACHE = {
+    'cloudfront': {
+        'BACKEND': 'wagtail.contrib.frontend_cache.backends.CloudfrontBackend',
+        'DISTRIBUTION_ID': 'your-distribution-id',
+    },
+}
+```
 
-Configuration of credentials can done in multiple ways. You won't need to store them in your Django settings file. You can read more about this here: `Boto 3 Docs <https://boto3.readthedocs.org/en/latest/guide/configuration.html>`_
+Configuration of credentials can done in multiple ways. You won't need to store them in your Django settings file. You can read more about this here: [Boto 3 Docs](https://boto3.readthedocs.org/en/latest/guide/configuration.html).
 
 In case you run multiple sites with Wagtail and each site has its CloudFront distribution, provide a mapping instead of a single distribution. Make sure the mapping matches with the hostnames provided in your site settings.
 
-.. code-block:: python
-
-    WAGTAILFRONTENDCACHE = {
-        'cloudfront': {
-            'BACKEND': 'wagtail.contrib.frontend_cache.backends.CloudfrontBackend',
-            'DISTRIBUTION_ID': {
-                'www.wagtail.org': 'your-distribution-id',
-                'www.madewithwagtail.org': 'your-distribution-id',
-            },
+```python
+WAGTAILFRONTENDCACHE = {
+    'cloudfront': {
+        'BACKEND': 'wagtail.contrib.frontend_cache.backends.CloudfrontBackend',
+        'DISTRIBUTION_ID': {
+            'www.wagtail.org': 'your-distribution-id',
+            'www.madewithwagtail.org': 'your-distribution-id',
         },
-    }
+    },
+}
+```
 
-.. note::
-    In most cases, absolute URLs with ``www`` prefixed domain names should be used in your mapping. Only drop the ``www`` prefix if you're absolutely sure you're not using it (for example a subdomain).
+```{note}
+In most cases, absolute URLs with ``www`` prefixed domain names should be used in your mapping. Only drop the ``www`` prefix if you're absolutely sure you're not using it (for example a subdomain).
+```
 
-Azure CDN
-^^^^^^^^^
+### Azure CDN
 
-With `Azure CDN <https://azure.microsoft.com/en-gb/services/cdn/>`_ you will need a CDN profile with an endpoint configured.
-
-.. _azure-mgmt-cdn: https://pypi.org/project/azure-mgmt-cdn/
-.. _azure-identity: https://pypi.org/project/azure-identity/
-.. _azure-mgmt-resource: https://pypi.org/project/azure-mgmt-resource/
+With [Azure CDN](https://azure.microsoft.com/en-gb/services/cdn/) you will need a CDN profile with an endpoint configured.
 
 The third-party dependencies of this backend are:
 
-+-------------------------+-----------+---------------------------------------------------------------------------------------------------------------------------------------+
-| PyPI Package            | Essential | Reason                                                                                                                                |
-+=========================+===========+=======================================================================================================================================+
-| azure-mgmt-cdn_         | Yes       | Interacting with the CDN service.                                                                                                     |
-+-------------------------+-----------+---------------------------------------------------------------------------------------------------------------------------------------+
-| azure-identity_         | No        | Obtaining credentials. It's optional if you want to specify your own credential using a ``CREDENTIALS`` setting (more details below). |
-+-------------------------+-----------+---------------------------------------------------------------------------------------------------------------------------------------+
-| azure-mgmt-resource_    | No        | For obtaining the subscription ID. Redundant if you want to explicitly specify a ``SUBSCRIPTION_ID`` setting (more details below).    |
-+-------------------------+-----------+---------------------------------------------------------------------------------------------------------------------------------------+
-
-Add an item into the ``WAGTAILFRONTENDCACHE`` and set the ``BACKEND`` parameter to ``wagtail.contrib.frontend_cache.backends.AzureCdnBackend``. This backend requires the following settings to be set:
+| PyPI Package                                                           | Essential | Reason                                                                                                                              |
+| ---------------------------------------------------------------------- | --------- | ----------------------------------------------------------------------------------------------------------------------------------- |
+| [`azure-mgmt-cdn`](https://pypi.org/project/azure-mgmt-cdn/)           | Yes       | Interacting with the CDN service.                                                                                                   |
+| [`azure-identity`](https://pypi.org/project/azure-identity/)           | No        | Obtaining credentials. It's optional if you want to specify your own credential using a `CREDENTIALS` setting (more details below). |
+| [`azure-mgmt-resource`](https://pypi.org/project/azure-mgmt-resource/) | No        | For obtaining the subscription ID. Redundant if you want to explicitly specify a `SUBSCRIPTION_ID` setting (more details below).    |
 
-* ``RESOURCE_GROUP_NAME`` - the resource group that your CDN profile is in.
-* ``CDN_PROFILE_NAME`` - the profile name of the CDN service that you want to use.
-* ``CDN_ENDPOINT_NAME`` - the name of the endpoint you want to be purged.
+Add an item into the `WAGTAILFRONTENDCACHE` and set the `BACKEND` parameter to `wagtail.contrib.frontend_cache.backends.AzureCdnBackend`. This backend requires the following settings to be set:
 
-.. code-block:: python
+-   `RESOURCE_GROUP_NAME` - the resource group that your CDN profile is in.
+-   `CDN_PROFILE_NAME` - the profile name of the CDN service that you want to use.
+-   `CDN_ENDPOINT_NAME` - the name of the endpoint you want to be purged.
 
+```python
     WAGTAILFRONTENDCACHE = {
         'azure_cdn': {
             'BACKEND': 'wagtail.contrib.frontend_cache.backends.AzureCdnBackend',
@@ -170,180 +152,163 @@ Add an item into the ``WAGTAILFRONTENDCACHE`` and set the ``BACKEND`` parameter
             'CDN_ENDPOINT_NAME': 'wagtailio-cdn-endpoint-123',
         },
     }
+```
 
-By default the credentials will use ``azure.identity.DefaultAzureCredential``. To modify the credential object used, please use ``CREDENTIALS`` setting. Read about your options on the `Azure documentation <https://docs.microsoft.com/en-us/azure/developer/python/azure-sdk-authenticate>`_.
-
-
-.. code-block:: python
-
-    from azure.common.credentials import ServicePrincipalCredentials
+By default the credentials will use `azure.identity.DefaultAzureCredential`. To modify the credential object used, please use `CREDENTIALS` setting. Read about your options on the [Azure documentation](https://docs.microsoft.com/en-us/azure/developer/python/azure-sdk-authenticate).
 
-    WAGTAILFRONTENDCACHE = {
-        'azure_cdn': {
-            'BACKEND': 'wagtail.contrib.frontend_cache.backends.AzureCdnBackend',
-            'RESOURCE_GROUP_NAME': 'MY-WAGTAIL-RESOURCE-GROUP',
-            'CDN_PROFILE_NAME': 'wagtailio',
-            'CDN_ENDPOINT_NAME': 'wagtailio-cdn-endpoint-123',
-            'CREDENTIALS': ServicePrincipalCredentials(
-                client_id='your client id',
-                secret='your client secret',
-            )
-        },
-    }
+```python
+from azure.common.credentials import ServicePrincipalCredentials
 
-Another option that can be set is ``SUBSCRIPTION_ID``. By default the first encountered subscription will be used, but if your credential has access to more subscriptions, you should set this to an explicit value.
+WAGTAILFRONTENDCACHE = {
+    'azure_cdn': {
+        'BACKEND': 'wagtail.contrib.frontend_cache.backends.AzureCdnBackend',
+        'RESOURCE_GROUP_NAME': 'MY-WAGTAIL-RESOURCE-GROUP',
+        'CDN_PROFILE_NAME': 'wagtailio',
+        'CDN_ENDPOINT_NAME': 'wagtailio-cdn-endpoint-123',
+        'CREDENTIALS': ServicePrincipalCredentials(
+            client_id='your client id',
+            secret='your client secret',
+        )
+    },
+}
+```
 
+Another option that can be set is `SUBSCRIPTION_ID`. By default the first encountered subscription will be used, but if your credential has access to more subscriptions, you should set this to an explicit value.
 
-Azure Front Door
-^^^^^^^^^^^^^^^^
+### Azure Front Door
 
-With `Azure Front Door <https://azure.microsoft.com/en-gb/services/frontdoor/>`_ you will need a Front Door instance with caching enabled.
-
-.. _azure-mgmt-frontdoor: https://pypi.org/project/azure-mgmt-frontdoor/
-.. _azure-identity: https://pypi.org/project/azure-identity/
-.. _azure-mgmt-resource: https://pypi.org/project/azure-mgmt-resource/
+With [Azure Front Door](https://azure.microsoft.com/en-gb/services/frontdoor/) you will need a Front Door instance with caching enabled.
 
 The third-party dependencies of this backend are:
 
-+-------------------------+-----------+---------------------------------------------------------------------------------------------------------------------------------------+
-| PyPI Package            | Essential | Reason                                                                                                                                |
-+=========================+===========+=======================================================================================================================================+
-| azure-mgmt-frontdoor_   | Yes       | Interacting with the Front Door service.                                                                                              |
-+-------------------------+-----------+---------------------------------------------------------------------------------------------------------------------------------------+
-| azure-identity_         | No        | Obtaining credentials. It's optional if you want to specify your own credential using a ``CREDENTIALS`` setting (more details below). |
-+-------------------------+-----------+---------------------------------------------------------------------------------------------------------------------------------------+
-| azure-mgmt-resource_    | No        | For obtaining the subscription ID. Redundant if you want to explicitly specify a ``SUBSCRIPTION_ID`` setting (more details below).    |
-+-------------------------+-----------+---------------------------------------------------------------------------------------------------------------------------------------+
-
-Add an item into the ``WAGTAILFRONTENDCACHE`` and set the ``BACKEND`` parameter to ``wagtail.contrib.frontend_cache.backends.AzureFrontDoorBackend``. This backend requires the following settings to be set:
-
-* ``RESOURCE_GROUP_NAME`` - the resource group that your Front Door instance is part of.
-* ``FRONT_DOOR_NAME`` - your configured Front Door instance name.
-
-.. code-block:: python
-
-    WAGTAILFRONTENDCACHE = {
-        'azure_front_door': {
-            'BACKEND': 'wagtail.contrib.frontend_cache.backends.AzureFrontDoorBackend',
-            'RESOURCE_GROUP_NAME': 'MY-WAGTAIL-RESOURCE-GROUP',
-            'FRONT_DOOR_NAME': 'wagtail-io-front-door',
-        },
-    }
+| PyPI Package                                                             | Essential | Reason                                                                                                                              |
+| ------------------------------------------------------------------------ | --------- | ----------------------------------------------------------------------------------------------------------------------------------- |
+| [`azure-mgmt-frontdoor`](https://pypi.org/project/azure-mgmt-frontdoor/) | Yes       | Interacting with the Front Door service.                                                                                            |
+| [`azure-identity`](https://pypi.org/project/azure-identity/)             | No        | Obtaining credentials. It's optional if you want to specify your own credential using a `CREDENTIALS` setting (more details below). |
+| [`azure-mgmt-resource`](https://pypi.org/project/azure-mgmt-resource/)   | No        | For obtaining the subscription ID. Redundant if you want to explicitly specify a `SUBSCRIPTION_ID` setting (more details below).    |
 
-By default the credentials will use ``azure.identity.DefaultAzureCredential``. To modify the credential object used, please use ``CREDENTIALS`` setting. Read about your options on the `Azure documentation <https://docs.microsoft.com/en-us/azure/developer/python/azure-sdk-authenticate>`_.
+Add an item into the `WAGTAILFRONTENDCACHE` and set the `BACKEND` parameter to `wagtail.contrib.frontend_cache.backends.AzureFrontDoorBackend`. This backend requires the following settings to be set:
 
+-   `RESOURCE_GROUP_NAME` - the resource group that your Front Door instance is part of.
+-   `FRONT_DOOR_NAME` - your configured Front Door instance name.
 
-.. code-block:: python
+```python
+WAGTAILFRONTENDCACHE = {
+    'azure_front_door': {
+        'BACKEND': 'wagtail.contrib.frontend_cache.backends.AzureFrontDoorBackend',
+        'RESOURCE_GROUP_NAME': 'MY-WAGTAIL-RESOURCE-GROUP',
+        'FRONT_DOOR_NAME': 'wagtail-io-front-door',
+    },
+}
+```
 
-    from azure.common.credentials import ServicePrincipalCredentials
+By default the credentials will use `azure.identity.DefaultAzureCredential`. To modify the credential object used, please use `CREDENTIALS` setting. Read about your options on the [Azure documentation](https://docs.microsoft.com/en-us/azure/developer/python/azure-sdk-authenticate).
 
-    WAGTAILFRONTENDCACHE = {
-        'azure_front_door': {
-            'BACKEND': 'wagtail.contrib.frontend_cache.backends.AzureFrontDoorBackend',
-            'RESOURCE_GROUP_NAME': 'MY-WAGTAIL-RESOURCE-GROUP',
-            'FRONT_DOOR_NAME': 'wagtail-io-front-door',
-            'CREDENTIALS': ServicePrincipalCredentials(
-                client_id='your client id',
-                secret='your client secret',
-            )
-        },
-    }
+```python
+from azure.common.credentials import ServicePrincipalCredentials
 
-Another option that can be set is ``SUBSCRIPTION_ID``. By default the first encountered subscription will be used, but if your credential has access to more subscriptions, you should set this to an explicit value.
+WAGTAILFRONTENDCACHE = {
+    'azure_front_door': {
+        'BACKEND': 'wagtail.contrib.frontend_cache.backends.AzureFrontDoorBackend',
+        'RESOURCE_GROUP_NAME': 'MY-WAGTAIL-RESOURCE-GROUP',
+        'FRONT_DOOR_NAME': 'wagtail-io-front-door',
+        'CREDENTIALS': ServicePrincipalCredentials(
+            client_id='your client id',
+            secret='your client secret',
+        )
+    },
+}
+```
 
-Advanced usage
---------------
+Another option that can be set is `SUBSCRIPTION_ID`. By default the first encountered subscription will be used, but if your credential has access to more subscriptions, you should set this to an explicit value.
 
-Invalidating more than one URL per page
-^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+## Advanced usage
 
-By default, Wagtail will only purge one URL per page. If your page has more than one URL to be purged, you will need to override the ``get_cached_paths`` method on your page type.
+### Invalidating more than one URL per page
 
-.. code-block:: python
+By default, Wagtail will only purge one URL per page. If your page has more than one URL to be purged, you will need to override the `get_cached_paths` method on your page type.
 
-    class BlogIndexPage(Page):
-        def get_blog_items(self):
-            # This returns a Django paginator of blog items in this section
-            return Paginator(self.get_children().live().type(BlogPage), 10)
+```python
+class BlogIndexPage(Page):
+    def get_blog_items(self):
+        # This returns a Django paginator of blog items in this section
+        return Paginator(self.get_children().live().type(BlogPage), 10)
 
-        def get_cached_paths(self):
-            # Yield the main URL
-            yield '/'
+    def get_cached_paths(self):
+        # Yield the main URL
+        yield '/'
 
-            # Yield one URL per page in the paginator to make sure all pages are purged
-            for page_number in range(1, self.get_blog_items().num_pages + 1):
-                yield '/?page=' + str(page_number)
+        # Yield one URL per page in the paginator to make sure all pages are purged
+        for page_number in range(1, self.get_blog_items().num_pages + 1):
+            yield '/?page=' + str(page_number)
+```
 
-Invalidating index pages
-^^^^^^^^^^^^^^^^^^^^^^^^
+### Invalidating index pages
 
 Pages that list other pages (such as a blog index) may need to be purged as
 well so any changes to a blog page are also reflected on the index (for example,
 a blog post was added, deleted or its title/thumbnail was changed).
 
 To purge these pages, we need to write a signal handler that listens for
-Wagtail's ``page_published`` and ``page_unpublished`` signals for blog pages
-(note, ``page_published`` is called both when a page is created and updated).
+Wagtail's `page_published` and `page_unpublished` signals for blog pages
+(note, `page_published` is called both when a page is created and updated).
 This signal handler would trigger the invalidation of the index page using the
-``PurgeBatch`` class which is used to construct and dispatch invalidation requests.
+`PurgeBatch` class which is used to construct and dispatch invalidation requests.
 
-.. code-block:: python
+```python
+# models.py
+from django.dispatch import receiver
+from django.db.models.signals import pre_delete
 
-    # models.py
-    from django.dispatch import receiver
-    from django.db.models.signals import pre_delete
+from wagtail.signals import page_published
+from wagtail.contrib.frontend_cache.utils import PurgeBatch
 
-    from wagtail.signals import page_published
-    from wagtail.contrib.frontend_cache.utils import PurgeBatch
-
-    ...
+...
 
-    def blog_page_changed(blog_page):
-        # Find all the live BlogIndexPages that contain this blog_page
-        batch = PurgeBatch()
-        for blog_index in BlogIndexPage.objects.live():
-            if blog_page in blog_index.get_blog_items().object_list:
-                batch.add_page(blog_index)
-
-        # Purge all the blog indexes we found in a single request
-        batch.purge()
+def blog_page_changed(blog_page):
+    # Find all the live BlogIndexPages that contain this blog_page
+    batch = PurgeBatch()
+    for blog_index in BlogIndexPage.objects.live():
+        if blog_page in blog_index.get_blog_items().object_list:
+            batch.add_page(blog_index)
 
+    # Purge all the blog indexes we found in a single request
+    batch.purge()
 
-    @receiver(page_published, sender=BlogPage)
-    def blog_published_handler(instance, **kwargs):
-        blog_page_changed(instance)
 
+@receiver(page_published, sender=BlogPage)
+def blog_published_handler(instance, **kwargs):
+    blog_page_changed(instance)
 
-    @receiver(pre_delete, sender=BlogPage)
-    def blog_deleted_handler(instance, **kwargs):
-        blog_page_changed(instance)
 
+@receiver(pre_delete, sender=BlogPage)
+def blog_deleted_handler(instance, **kwargs):
+    blog_page_changed(instance)
+```
 
-.. _frontend_cache_invalidating_urls:
+(frontend_cache_invalidating_urls)=
 
-Invalidating URLs
-^^^^^^^^^^^^^^^^^
+### Invalidating URLs
 
-The ``PurgeBatch`` class provides a ``.add_url(url)`` and a ``.add_urls(urls)``
+The `PurgeBatch` class provides a `.add_url(url)` and a `.add_urls(urls)`
 for adding individual URLs to the purge batch.
 
 For example, this could be useful for purging a single page on a blog index:
 
-.. code-block:: python
-
-    from wagtail.contrib.frontend_cache.utils import PurgeBatch
-
-    # Purge the first page of the blog index
-    batch = PurgeBatch()
-    batch.add_url(blog_index.url + '?page=1')
-    batch.purge()
+```python
+from wagtail.contrib.frontend_cache.utils import PurgeBatch
 
+# Purge the first page of the blog index
+batch = PurgeBatch()
+batch.add_url(blog_index.url + '?page=1')
+batch.purge()
+```
 
-The ``PurgeBatch`` class
-^^^^^^^^^^^^^^^^^^^^^^^^
+### The `PurgeBatch` class
 
-All of the methods available on ``PurgeBatch`` are listed below:
+All of the methods available on `PurgeBatch` are listed below:
 
+```{eval-rst}
 .. automodule:: wagtail.contrib.frontend_cache.utils
 .. autoclass:: PurgeBatch
 
@@ -356,3 +321,4 @@ All of the methods available on ``PurgeBatch`` are listed below:
     .. automethod:: add_pages
 
     .. automethod:: purge
+```

+ 32 - 56
docs/reference/contrib/index.md

@@ -1,94 +1,70 @@
-Contrib modules
-===============
+# Contrib modules
 
 Wagtail ships with a variety of extra optional modules.
 
-
-.. toctree::
-    :maxdepth: 2
-
-    settings
-    forms/index
-    sitemaps
-    frontendcache
-    routablepage
-    modeladmin/index
-    searchpromotions
-    simple_translation
-    table_block
-    typed_table_block
-    redirects
-    legacy_richtext
-
-
-:doc:`settings`
----------------
+```{toctree}
+---
+maxdepth: 2
+---
+settings
+forms/index
+sitemaps
+frontendcache
+routablepage
+modeladmin/index
+searchpromotions
+simple_translation
+table_block
+typed_table_block
+redirects
+legacy_richtext
+```
+
+## [](settings)
 
 Settings that are editable by administrators within the Wagtail admin - either
 site-specific or generic across all sites.
 
-
-:doc:`forms/index`
-------------------
+## [](forms/index)
 
 Allows forms to be created by admins and provides an interface for browsing form submissions.
 
-
-:doc:`sitemaps`
----------------
+## [](sitemaps)
 
 Provides a view that generates a Google XML sitemap of your public Wagtail content.
 
-
-:doc:`frontendcache`
---------------------
+## [](frontendcache)
 
 A module for automatically purging pages from a cache (Varnish, Squid, Cloudflare or Cloudfront) when their content is changed.
 
-
-:doc:`routablepage`
--------------------
+## [](routablepage)
 
 Provides a way of embedding Django URLconfs into pages.
 
-
-:doc:`modeladmin/index`
------------------------
+## [](modeladmin/index)
 
 A module allowing for more customisable representation and management of custom models in Wagtail's admin area.
 
-
-:doc:`searchpromotions`
------------------------
+## [](searchpromotions)
 
 A module for managing "Promoted Search Results"
 
-
-:doc:`simple_translation`
--------------------------
+## [](simple_translation.md)
 
 A module for copying translatables (pages and snippets) to another language.
 
-
-:doc:`table_block`
------------------------
+## [](table_block)
 
 Provides a TableBlock for adding HTML tables to pages.
 
-
-:doc:`typed_table_block`
-------------------------
+## [](typed_table_block)
 
 Provides a StreamField block for authoring tables, where cells can be any block type including rich text.
 
-
-:doc:`redirects`
------------------------
+## [](redirects.md)
 
 Provides a way to manage redirects.
 
+## [](legacy_richtext)
 
-:doc:`legacy_richtext`
------------------------
-
-Provides the legacy richtext wrapper (``<div class="rich-text"></div>``).
+Provides the legacy richtext wrapper (`<div class="rich-text"></div>`).

+ 139 - 145
docs/reference/contrib/routablepage.md

@@ -1,185 +1,176 @@
-.. _routable_page_mixin:
+(routable_page_mixin)=
 
-=====================
-``RoutablePageMixin``
-=====================
+# `RoutablePageMixin`
 
+```{eval-rst}
 .. module:: wagtail.contrib.routable_page
+```
 
-The ``RoutablePageMixin`` mixin provides a convenient way for a page to respond on multiple sub-URLs with different views. For example, a blog section on a site might provide several different types of index page at URLs like ``/blog/2013/06/``, ``/blog/authors/bob/``, ``/blog/tagged/python/``, all served by the same page instance.
+The `RoutablePageMixin` mixin provides a convenient way for a page to respond on multiple sub-URLs with different views. For example, a blog section on a site might provide several different types of index page at URLs like `/blog/2013/06/`, `/blog/authors/bob/`, `/blog/tagged/python/`, all served by the same page instance.
 
-A ``Page`` using ``RoutablePageMixin`` exists within the page tree like any other page, but URL paths underneath it are checked against a list of patterns. If none of the patterns match, control is passed to subpages as usual (or failing that, a 404 error is thrown).
+A `Page` using `RoutablePageMixin` exists within the page tree like any other page, but URL paths underneath it are checked against a list of patterns. If none of the patterns match, control is passed to subpages as usual (or failing that, a 404 error is thrown).
 
-By default a route for ``r'^$'`` exists, which serves the content exactly like a normal ``Page`` would. It can be overridden by using ``@route(r'^$')`` on any other method of the inheriting class.
+By default a route for `r'^$'` exists, which serves the content exactly like a normal `Page` would. It can be overridden by using `@route(r'^$')` on any other method of the inheriting class.
 
+## Installation
 
-Installation
-============
+Add `"wagtail.contrib.routable_page"` to your `INSTALLED_APPS`:
 
-Add ``"wagtail.contrib.routable_page"`` to your INSTALLED_APPS:
+```python
+INSTALLED_APPS = [
+    ...
 
-.. code-block:: python
+    "wagtail.contrib.routable_page",
+]
+```
 
-    INSTALLED_APPS = [
-      ...
+## The basics
 
-      "wagtail.contrib.routable_page",
-    ]
+To use `RoutablePageMixin`, you need to make your class inherit from both {class}`wagtail.contrib.routable_page.models.RoutablePageMixin` and {class}`wagtail.models.Page`, then define some view methods and decorate them with `wagtail.contrib.routable_page.models.route`. These view methods behave like ordinary Django view functions, and must return an `HttpResponse` object; typically this is done through a call to `django.shortcuts.render`.
 
+Here's an example of an `EventIndexPage` with three views, assuming that an `EventPage` model with an `event_date` field has been defined elsewhere:
 
-The basics
-==========
+```python
+import datetime
+from django.http import JsonResponse
+from wagtail.fields import RichTextField
+from wagtail.models import Page
+from wagtail.contrib.routable_page.models import RoutablePageMixin, route
 
-To use ``RoutablePageMixin``, you need to make your class inherit from both :class:`wagtail.contrib.routable_page.models.RoutablePageMixin` and :class:`wagtail.models.Page`, then define some view methods and decorate them with ``wagtail.contrib.routable_page.models.route``. These view methods behave like ordinary Django view functions, and must return an ``HttpResponse`` object; typically this is done through a call to ``django.shortcuts.render``.
 
-Here's an example of an ``EventIndexPage`` with three views, assuming that an ``EventPage`` model with an ``event_date`` field has been defined elsewhere:
+class EventIndexPage(RoutablePageMixin, Page):
 
-.. code-block:: python
+    # Routable pages can have fields like any other - here we would
+    # render the intro text on a template with {{ page.intro|richtext }}
+    intro = RichTextField()
 
-    import datetime
-    from django.http import JsonResponse
-    from wagtail.fields import RichTextField
-    from wagtail.models import Page
-    from wagtail.contrib.routable_page.models import RoutablePageMixin, route
-
-
-    class EventIndexPage(RoutablePageMixin, Page):
+    @route(r'^$') # will override the default Page serving mechanism
+    def current_events(self, request):
+        """
+        View function for the current events page
+        """
+        events = EventPage.objects.live().filter(event_date__gte=datetime.date.today())
 
-        # Routable pages can have fields like any other - here we would
-        # render the intro text on a template with {{ page.intro|richtext }}
-        intro = RichTextField()
+        # NOTE: We can use the RoutablePageMixin.render() method to render
+        # the page as normal, but with some of the context values overridden
+        return self.render(request, context_overrides={
+            'title': "Current events",
+            'events': events,
+        })
 
-        @route(r'^$') # will override the default Page serving mechanism
-        def current_events(self, request):
-            """
-            View function for the current events page
-            """
-            events = EventPage.objects.live().filter(event_date__gte=datetime.date.today())
+    @route(r'^past/$')
+    def past_events(self, request):
+        """
+        View function for the past events page
+        """
+        events = EventPage.objects.live().filter(event_date__lt=datetime.date.today())
 
-            # NOTE: We can use the RoutablePageMixin.render() method to render
-            # the page as normal, but with some of the context values overridden
-            return self.render(request, context_overrides={
-                'title': "Current events",
+        # NOTE: We are overriding the template here, as well as few context values
+        return self.render(
+            request,
+            context_overrides={
+                'title': "Past events",
                 'events': events,
-            })
-
-        @route(r'^past/$')
-        def past_events(self, request):
-            """
-            View function for the past events page
-            """
-            events = EventPage.objects.live().filter(event_date__lt=datetime.date.today())
-
-            # NOTE: We are overriding the template here, as well as few context values
-            return self.render(
-                request,
-                context_overrides={
-                    'title': "Past events",
-                    'events': events,
-                },
-                template="events/event_index_historical.html",
-            )
-
-        # Multiple routes!
-        @route(r'^year/(\d+)/$')
-        @route(r'^year/current/$')
-        def events_for_year(self, request, year=None):
-            """
-            View function for the events for year page
-            """
-            if year is None:
-                year = datetime.date.today().year
-
-            events = EventPage.objects.live().filter(event_date__year=year)
-
-            return self.render(request, context_overrides={
-                'title': "Events for %d" % year,
-                'events': events,
-            })
-
-        @route(r'^year/(\d+)/count/$')
-        def count_for_year(self, request, year=None):
-            """
-            View function that returns a simple JSON response that
-            includes the number of events scheduled for a specific year
-            """
-            events = EventPage.objects.live().filter(event_date__year=year)
-
-            # NOTE: The usual template/context rendering process is irrelevant
-            # here, so we'll just return a HttpResponse directly
-            return JsonResponse({'count': events.count()})
+            },
+            template="events/event_index_historical.html",
+        )
+
+    # Multiple routes!
+    @route(r'^year/(\d+)/$')
+    @route(r'^year/current/$')
+    def events_for_year(self, request, year=None):
+        """
+        View function for the events for year page
+        """
+        if year is None:
+            year = datetime.date.today().year
 
+        events = EventPage.objects.live().filter(event_date__year=year)
 
-Rendering other pages
-=====================
+        return self.render(request, context_overrides={
+            'title': "Events for %d" % year,
+            'events': events,
+        })
 
-Another way of returning an ``HttpResponse`` is to call the ``serve`` method of another page. (Calling a page's own ``serve`` method within a view method is not valid, as the view method is already being called within ``serve``, and this would create a circular definition).
+    @route(r'^year/(\d+)/count/$')
+    def count_for_year(self, request, year=None):
+        """
+        View function that returns a simple JSON response that
+        includes the number of events scheduled for a specific year
+        """
+        events = EventPage.objects.live().filter(event_date__year=year)
 
-For example, ``EventIndexPage`` could be extended with a ``next/`` route that displays the page for the next event:
+        # NOTE: The usual template/context rendering process is irrelevant
+        # here, so we'll just return a HttpResponse directly
+        return JsonResponse({'count': events.count()})
+```
 
-.. code-block:: python
+### Rendering other pages
 
-    @route(r'^next/$')
-    def next_event(self, request):
-        """
-        Display the page for the next event
-        """
-        future_events = EventPage.objects.live().filter(event_date__gt=datetime.date.today())
-        next_event = future_events.order_by('event_date').first()
+Another way of returning an `HttpResponse` is to call the `serve` method of another page. (Calling a page's own `serve` method within a view method is not valid, as the view method is already being called within `serve`, and this would create a circular definition).
 
-        return next_event.serve(request)
+For example, `EventIndexPage` could be extended with a `next/` route that displays the page for the next event:
 
+```python
+@route(r'^next/$')
+def next_event(self, request):
+    """
+    Display the page for the next event
+    """
+    future_events = EventPage.objects.live().filter(event_date__gt=datetime.date.today())
+    next_event = future_events.order_by('event_date').first()
 
-Reversing URLs
-==============
+    return next_event.serve(request)
+```
 
-:class:`~models.RoutablePageMixin` adds a :meth:`~models.RoutablePageMixin.reverse_subpage` method to your page model which you can use for reversing URLs. For example:
+### Reversing URLs
 
-.. code-block:: python
+{class}`~models.RoutablePageMixin` adds a {meth}`~models.RoutablePageMixin.reverse_subpage` method to your page model which you can use for reversing URLs. For example:
 
+```python
     # The URL name defaults to the view method name.
     >>> event_page.reverse_subpage('events_for_year', args=(2015, ))
     'year/2015/'
+```
 
-This method only returns the part of the URL within the page. To get the full URL, you must append it to the values of either the :attr:`~wagtail.models.Page.url` or the :attr:`~wagtail.models.Page.full_url` attribute on your page:
+This method only returns the part of the URL within the page. To get the full URL, you must append it to the values of either the {attr}`~wagtail.models.Page.url` or the {attr}`~wagtail.models.Page.full_url` attribute on your page:
 
-.. code-block:: python
+```python
+>>> event_page.url + event_page.reverse_subpage('events_for_year', args=(2015, ))
+'/events/year/2015/'
 
-    >>> event_page.url + event_page.reverse_subpage('events_for_year', args=(2015, ))
-    '/events/year/2015/'
+>>> event_page.full_url + event_page.reverse_subpage('events_for_year', args=(2015, ))
+'http://example.com/events/year/2015/'
+```
 
-    >>> event_page.full_url + event_page.reverse_subpage('events_for_year', args=(2015, ))
-    'http://example.com/events/year/2015/'
+### Changing route names
 
-Changing route names
---------------------
+The route name defaults to the name of the view. You can override this name with the `name` keyword argument on `@route`:
 
-The route name defaults to the name of the view. You can override this name with the ``name`` keyword argument on ``@route``:
+```python
+from wagtail.models import Page
+from wagtail.contrib.routable_page.models import RoutablePageMixin, route
 
-.. code-block:: python
 
-    from wagtail.models import Page
-    from wagtail.contrib.routable_page.models import RoutablePageMixin, route
+class EventPage(RoutablePageMixin, Page):
+    ...
 
-
-    class EventPage(RoutablePageMixin, Page):
+    @route(r'^year/(\d+)/$', name='year')
+    def events_for_year(self, request, year):
+        """
+        View function for the events for year page
+        """
         ...
+```
 
-        @route(r'^year/(\d+)/$', name='year')
-        def events_for_year(self, request, year):
-            """
-            View function for the events for year page
-            """
-            ...
+```python
+>>> event_page.url + event_page.reverse_subpage('year', args=(2015, ))
+'/events/year/2015/'
+```
 
-.. code-block:: python
-
-    >>> event_page.url + event_page.reverse_subpage('year', args=(2015, ))
-    '/events/year/2015/'
-
-The ``RoutablePageMixin`` class
-===============================
+## The `RoutablePageMixin` class
 
+```{eval-rst}
 .. automodule:: wagtail.contrib.routable_page.models
 .. autoclass:: RoutablePageMixin
 
@@ -198,27 +189,30 @@ The ``RoutablePageMixin`` class
 
   .. automethod:: reverse_subpage
 
-    Example:
-
-    .. code-block:: python
+```
 
-        url = page.url + page.reverse_subpage('events_for_year', kwargs={'year': '2014'})
+Example:
 
+```python
+url = page.url + page.reverse_subpage('events_for_year', kwargs={'year': '2014'})
+```
 
- .. _routablepageurl_template_tag:
+(routablepageurl_template_tag)=
 
-The ``routablepageurl`` template tag
-====================================
+## The `routablepageurl` template tag
 
+```{eval-rst}
 .. currentmodule:: wagtail.contrib.routable_page.templatetags.wagtailroutablepage_tags
 .. autofunction:: routablepageurl
 
-    Example:
+```
 
-    .. code-block:: html+django
+Example:
 
-        {% load wagtailroutablepage_tags %}
+```html+django
+{% load wagtailroutablepage_tags %}
 
-        {% routablepageurl page "feed" %}
-        {% routablepageurl page "archive" 2014 08 14 %}
-        {% routablepageurl page "food" foo="bar" baz="quux" %}
+{% routablepageurl page "feed" %}
+{% routablepageurl page "archive" 2014 08 14 %}
+{% routablepageurl page "food" foo="bar" baz="quux" %}
+```

+ 2 - 2
docs/reference/contrib/settings.md

@@ -1,5 +1,3 @@
-(site_settings)=
-
 # Settings
 
 The `wagtail.contrib.settings` module allows you to define models that hold
@@ -148,6 +146,8 @@ def view(request):
     ...
 ```
 
+(site_settings)=
+
 #### Site-specific settings
 
 If you require access to a site-specific setting in a view, the

+ 21 - 25
docs/reference/contrib/simple_translation.md

@@ -1,47 +1,43 @@
-.. _simple_translation:
+(simple_translation)=
 
-Simple translation
-==================
+# Simple translation
 
 The simple_translation module provides a user interface that allows users to copy pages and translatable snippets into another language.
 
-- Copies are created in the source language (not translated)
-- Copies of pages are in draft status
+-   Copies are created in the source language (not translated)
+-   Copies of pages are in draft status
 
 Content editors need to translate the content and publish the pages.
 
-.. note::
-   Simple Translation is optional. It can be switched out by third-party packages. Like the more advanced `wagtail-localize <https://github.com/wagtail/wagtail-localize>`_.
+```{note}
+Simple Translation is optional. It can be switched out by third-party packages. Like the more advanced [`wagtail-localize`](https://github.com/wagtail/wagtail-localize).
+```
 
+## Basic configuration
 
-Basic configuration
-~~~~~~~~~~~~~~~~~~~
+Add `"wagtail.contrib.simple_translation"` to `INSTALLED_APPS` in your settings file:
 
-Add ``"wagtail.contrib.simple_translation"`` to INSTALLED_APPS in your settings file:
+```python
+INSTALLED_APPS = [
+    ...
+    "wagtail.contrib.simple_translation",
+]
+```
 
-.. code-block:: python
-
-  INSTALLED_APPS = [
-      ...
-      "wagtail.contrib.simple_translation",
-  ]
-
-Run ``python manage.py migrate`` to create the necessary permissions.
+Run `python manage.py migrate` to create the necessary permissions.
 
 In the Wagtail admin, go to settings and give some users or groups the "Can submit translations" permission.
 
-
-Page tree synchronisation
-~~~~~~~~~~~~~~~~~~~~~~~~~
+## Page tree synchronisation
 
 Depending on your use case, it may be useful to keep the page trees in sync between different locales.
 
 You can enable this feature by setting `WAGTAILSIMPLETRANSLATION_SYNC_PAGE_TREE` to `True`.
 
-.. code-block:: python
-
-  WAGTAILSIMPLETRANSLATION_SYNC_PAGE_TREE = True
+```python
+WAGTAILSIMPLETRANSLATION_SYNC_PAGE_TREE = True
+```
 
 When this feature is turned on, every time an editor creates a page, Wagtail creates an alias for that page under the page trees of all the other locales.
 
-For example, when an editor creates the page "/en/blog/my-blog-post/", Wagtail creates an alias of that page at "/fr/blog/my-blog-post/" and "/de/blog/my-blog-post/".
+For example, when an editor creates the page `"/en/blog/my-blog-post/"`, Wagtail creates an alias of that page at `"/fr/blog/my-blog-post/"` and `"/de/blog/my-blog-post/"`.

+ 63 - 79
docs/reference/contrib/sitemaps.md

@@ -1,124 +1,108 @@
-.. _sitemap_generation:
+(sitemap_generation)=
 
-Sitemap generator
-=================
+# Sitemap generator
 
 This document describes how to create XML sitemaps for your Wagtail website
-using the ``wagtail.contrib.sitemaps`` module.
+using the `wagtail.contrib.sitemaps` module.
 
+```{note}
+As of Wagtail 1.10 the Django contrib sitemap app is used to generate
+sitemaps.  However since Wagtail requires the Site instance to be available
+during the sitemap generation you will have to use the views from the
+`wagtail.contrib.sitemaps.views` module instead of the views
+provided by Django (`django.contrib.sitemaps.views`).
 
-.. note::
+The usage of these views is otherwise identical, which means that
+customisation and caching of the sitemaps are done using the default Django
+patterns.  See the Django documentation for in-depth information.
+```
 
-    As of Wagtail 1.10 the Django contrib sitemap app is used to generate
-    sitemaps.  However since Wagtail requires the Site instance to be available
-    during the sitemap generation you will have to use the views from the
-    ``wagtail.contrib.sitemaps.views`` module instead of the views
-    provided by Django (``django.contrib.sitemaps.views``).
+## Basic configuration
 
-    The usage of these views is otherwise identical, which means that
-    customisation and caching of the sitemaps are done using the default Django
-    patterns.  See the Django documentation for in-depth information.
-
-
-Basic configuration
-~~~~~~~~~~~~~~~~~~~
-
-
-You firstly need to add ``"django.contrib.sitemaps"`` to INSTALLED_APPS in your
+You firstly need to add `"django.contrib.sitemaps"` to INSTALLED_APPS in your
 Django settings file:
 
-.. code-block:: python
+```python
+INSTALLED_APPS = [
+    ...
 
-  INSTALLED_APPS = [
-      ...
+    "django.contrib.sitemaps",
+]
+```
 
-      "django.contrib.sitemaps",
-  ]
-
-
-Then, in ``urls.py``, you need to add a link to the
-``wagtail.contrib.sitemaps.views.sitemap`` view which generates the
+Then, in `urls.py`, you need to add a link to the
+`wagtail.contrib.sitemaps.views.sitemap` view which generates the
 sitemap:
 
-.. code-block:: python
-
-    from wagtail.contrib.sitemaps.views import sitemap
-
-    urlpatterns = [
-        ...
+```python
+from wagtail.contrib.sitemaps.views import sitemap
 
-        path('sitemap.xml', sitemap),
+urlpatterns = [
+    ...
 
-        ...
+    path('sitemap.xml', sitemap),
 
-        # Ensure that the 'sitemap' line appears above the default Wagtail page serving route
-        re_path(r'', include(wagtail_urls)),
-    ]
+    ...
 
+    # Ensure that the 'sitemap' line appears above the default Wagtail page serving route
+    re_path(r'', include(wagtail_urls)),
+]
+```
 
-You should now be able to browse to ``/sitemap.xml`` and see the sitemap
+You should now be able to browse to `/sitemap.xml` and see the sitemap
 working. By default, all published pages in your website will be added to the
 site map.
 
-
-Setting the hostname
-~~~~~~~~~~~~~~~~~~~~
+## Setting the hostname
 
 By default, the sitemap uses the hostname defined in the Wagtail Admin's
-``Sites`` area. If your default site is called ``localhost``, then URLs in the
+`Sites` area. If your default site is called `localhost`, then URLs in the
 sitemap will look like:
 
-.. code-block:: xml
-
-  <url>
-      <loc>http://localhost/about/</loc>
-      <lastmod>2015-09-26</lastmod>
-  </url>
-
+```xml
+<url>
+    <loc>http://localhost/about/</loc>
+    <lastmod>2015-09-26</lastmod>
+</url>
+```
 
 For tools like Google Search Tools to properly index your site, you need to set
 a valid, crawlable hostname. If you change the site's hostname from
-``localhost`` to ``mysite.com``, ``sitemap.xml`` will contain the correct URLs:
-
-.. code-block:: xml
+`localhost` to `mysite.com`, `sitemap.xml` will contain the correct URLs:
 
-  <url>
-      <loc>http://mysite.com/about/</loc>
-      <lastmod>2015-09-26</lastmod>
-  </url>
+```xml
+<url>
+    <loc>http://mysite.com/about/</loc>
+    <lastmod>2015-09-26</lastmod>
+</url>
+```
 
+If you change the site's port to `443`, the `https` scheme will be used.
+Find out more about [working with Sites](site_model_ref).
 
-If you change the site's port to ``443``, the ``https`` scheme will be used.
-Find out more about :ref:`working with Sites<site_model_ref>`.
+## Customising
 
+### URLs
 
-Customising
-~~~~~~~~~~~
-
-URLs
-----
-
-The ``Page`` class defines a ``get_sitemap_urls`` method which you can
-override to customise sitemaps per ``Page`` instance. This method must accept
+The `Page` class defines a `get_sitemap_urls` method which you can
+override to customise sitemaps per `Page` instance. This method must accept
 a request object and return a list of dictionaries, one dictionary per URL
 entry in the sitemap. You can exclude pages from the sitemap by returning an
 empty list.
 
 Each dictionary can contain the following:
 
-- **location** (required) - This is the full URL path to add into the sitemap.
-- **lastmod** - A python date or datetime set to when the page was last modified.
-- **changefreq**
-- **priority**
+-   **location** (required) - This is the full URL path to add into the sitemap.
+-   **lastmod** - A python date or datetime set to when the page was last modified.
+-   **changefreq**
+-   **priority**
 
 You can add more but you will need to override the
-``sitemap.xml`` template in order for them to be displayed in the sitemap.
-
+`sitemap.xml` template in order for them to be displayed in the sitemap.
 
-Serving multiple sitemaps
-~~~~~~~~~~~~~~~~~~~~~~~~~
+## Serving multiple sitemaps
 
 If you want to support the sitemap indexes from Django then you will need to
-use the index view from ``wagtail.contrib.sitemaps.views`` instead of the index
-view from ``django.contrib.sitemaps.views``.  Please see the Django
+use the index view from `wagtail.contrib.sitemaps.views` instead of the index
+view from `django.contrib.sitemaps.views`. Please see the Django
 documentation for further details.

+ 141 - 157
docs/reference/contrib/table_block.md

@@ -1,181 +1,165 @@
+# TableBlock
 
-TableBlock
-==========
+The TableBlock module provides an HTML table block type for StreamField. This module uses [handsontable 6.2.2](https://handsontable.com/) to provide users with the ability to create and edit HTML tables in Wagtail. Table blocks provides a caption field for accessibility.
 
-The TableBlock module provides an HTML table block type for StreamField. This module uses `handsontable 6.2.2 <https://handsontable.com/>`_ to provide users with the ability to create and edit HTML tables in Wagtail. Table blocks provides a caption field for accessibility.
+![](../../_static/images/screen40_table_block.png)
 
-.. image:: ../../_static/images/screen40_table_block.png
+## Installation
 
+Add `"wagtail.contrib.table_block"` to your INSTALLED_APPS:
 
-Installation
-------------
+```python
+INSTALLED_APPS = [
+    ...
 
-Add ``"wagtail.contrib.table_block"`` to your INSTALLED_APPS:
+    "wagtail.contrib.table_block",
+]
+```
 
-.. code-block:: python
-
-    INSTALLED_APPS = [
-      ...
-
-      "wagtail.contrib.table_block",
-    ]
-
-
-Basic Usage
------------
+## Basic Usage
 
 After installation, the TableBlock module can be used in a similar fashion to other StreamField blocks in the Wagtail core.
 
-Import the TableBlock ``from wagtail.contrib.table_block.blocks import TableBlock`` and add it to your StreamField declaration.
-
-.. code-block:: python
-
-  class DemoStreamBlock(StreamBlock):
-      ...
-      table = TableBlock()
+Import the TableBlock `from wagtail.contrib.table_block.blocks import TableBlock` and add it to your StreamField declaration.
 
+```python
+class DemoStreamBlock(StreamBlock):
+    ...
+    table = TableBlock()
+```
 
-Then, on your page template, the ``{% include_block %}`` tag (called on either the individual block, or the StreamField value as a whole) will render any table blocks it encounters as an HTML ``<table>`` element:
+Then, on your page template, the `{% include_block %}` tag (called on either the individual block, or the StreamField value as a whole) will render any table blocks it encounters as an HTML `<table>` element:
 
-.. code-block:: html+django
+```html+django
+{% load wagtailcore_tags %}
 
-    {% load wagtailcore_tags %}
-
-    {% include_block page.body %}
+{% include_block page.body %}
+```
 
 Or:
 
-.. code-block:: html+django
-
-    {% load wagtailcore_tags %}
-
-    {% for block in page.body %}
-        {% if block.block_type == 'table' %}
-            {% include_block block %}
-        {% else %}
-            {# rendering for other block types #}
-        {% endif %}
-    {% endfor %}
-
-
-Advanced Usage
---------------
-
-Default Configuration
-^^^^^^^^^^^^^^^^^^^^^
-
-When defining a TableBlock, Wagtail provides the ability to pass an optional ``table_options`` dictionary. The default TableBlock dictionary looks like this:
-
-.. code-block:: python
-
-  default_table_options = {
-      'minSpareRows': 0,
-      'startRows': 3,
-      'startCols': 3,
-      'colHeaders': False,
-      'rowHeaders': False,
-      'contextMenu': [
-          'row_above',
-          'row_below',
-          '---------',
-          'col_left',
-          'col_right',
-          '---------',
-          'remove_row',
-          'remove_col',
-          '---------',
-          'undo',
-          'redo'
-      ],
-      'editor': 'text',
-      'stretchH': 'all',
-      'height': 108,
-      'language': language,
-      'renderer': 'text',
-      'autoColumnSize': False,
-  }
-
-
-Configuration Options
-^^^^^^^^^^^^^^^^^^^^^
-
-Every key in the ``table_options`` dictionary maps to a `handsontable <https://handsontable.com/>`_ option. These settings can be changed to alter the behaviour of tables in Wagtail. The following options are available:
-
-* `minSpareRows <https://handsontable.com/docs/6.2.2/Options.html#minSpareRows>`_ - The number of rows to append to the end of an empty grid. The default setting is 0.
-* `startRows <https://handsontable.com/docs/6.2.2/Options.html#startRows>`_ - The default number of rows for a new table.
-* `startCols <https://handsontable.com/docs/6.2.2/Options.html#startCols>`_ - The default number of columns for new tables.
-* `colHeaders <https://handsontable.com/docs/6.2.2/Options.html#colHeaders>`_ - Can be set to ``True`` or ``False``. This setting designates if new tables should be created with column headers. **Note:** this only sets the behaviour for newly created tables. Page editors can override this by checking the the “Column header” checkbox in the table editor in the Wagtail admin.
-* `rowHeaders <https://handsontable.com/docs/6.2.2/Options.html#rowHeaders>`_ - Operates the same as ``colHeaders`` to designate if new tables should be created with the first column as a row header. Just like ``colHeaders`` this option can be overridden by the page editor in the Wagtail admin.
-* `contextMenu <https://handsontable.com/docs/6.2.2/Options.html#contextMenu>`_ - Enables or disables the Handsontable right-click menu. By default this is set to ``True``. Alternatively you can provide a list or a dictionary with [specific options](https://handsontable.com/docs/6.2.2/demo-context-menu.html#page-specific).
-* `editor <https://handsontable.com/docs/6.2.2/Options.html#editor>`_ - Defines the editor used for table cells. The default setting is text.
-* `stretchH <https://handsontable.com/docs/6.2.2/Options.html#stretchH>`_ - Sets the default horizontal resizing of tables. Options include, 'none', 'last', and 'all'. By default TableBlock uses 'all' for the even resizing of columns.
-* `height <https://handsontable.com/docs/6.2.2/Options.html#height>`_ - The default height of the grid. By default TableBlock sets the height to ``108`` for the optimal appearance of new tables in the editor. This is optimized for tables with ``startRows`` set to ``3``. If you change the number of ``startRows`` in the configuration, you might need to change the ``height`` setting to improve the default appearance in the editor.
-* `language <https://handsontable.com/docs/6.2.2/Options.html#language>`_ - The default language setting. By default TableBlock tries to get the language from ``django.utils.translation.get_language``. If needed, this setting can be overridden here.
-* `renderer <https://handsontable.com/docs/6.2.2/Options.html#renderer>`_ - The default setting Handsontable uses to render the content of table cells.
-* `autoColumnSize <https://handsontable.com/docs/6.2.2/Options.html#autoColumnSize>`_ - Enables or disables the ``autoColumnSize`` plugin. The TableBlock default setting is ``False``.
-
-A `complete list of handsontable options <https://handsontable.com/docs/6.2.2/Options.html>`_ can be found on the Handsontable website.
-
-
-Changing the default table_options
-^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+```html+django
+{% load wagtailcore_tags %}
+
+{% for block in page.body %}
+    {% if block.block_type == 'table' %}
+        {% include_block block %}
+    {% else %}
+        {# rendering for other block types #}
+    {% endif %}
+{% endfor %}
+```
+
+## Advanced Usage
+
+### Default Configuration
+
+When defining a TableBlock, Wagtail provides the ability to pass an optional `table_options` dictionary. The default TableBlock dictionary looks like this:
+
+```python
+default_table_options = {
+    'minSpareRows': 0,
+    'startRows': 3,
+    'startCols': 3,
+    'colHeaders': False,
+    'rowHeaders': False,
+    'contextMenu': [
+        'row_above',
+        'row_below',
+        '---------',
+        'col_left',
+        'col_right',
+        '---------',
+        'remove_row',
+        'remove_col',
+        '---------',
+        'undo',
+        'redo'
+    ],
+    'editor': 'text',
+    'stretchH': 'all',
+    'height': 108,
+    'language': language,
+    'renderer': 'text',
+    'autoColumnSize': False,
+}
+```
+
+### Configuration Options
+
+Every key in the `table_options` dictionary maps to a [handsontable](https://handsontable.com/) option. These settings can be changed to alter the behaviour of tables in Wagtail. The following options are available:
+
+-   [minSpareRows](https://handsontable.com/docs/6.2.2/Options.html#minSpareRows) - The number of rows to append to the end of an empty grid. The default setting is 0.
+-   [startRows](https://handsontable.com/docs/6.2.2/Options.html#startRows) - The default number of rows for a new table.
+-   [startCols](https://handsontable.com/docs/6.2.2/Options.html#startCols) - The default number of columns for new tables.
+-   [colHeaders](https://handsontable.com/docs/6.2.2/Options.html#colHeaders) - Can be set to `True` or `False`. This setting designates if new tables should be created with column headers. **Note:** this only sets the behaviour for newly created tables. Page editors can override this by checking the the “Column header” checkbox in the table editor in the Wagtail admin.
+-   [rowHeaders](https://handsontable.com/docs/6.2.2/Options.html#rowHeaders) - Operates the same as `colHeaders` to designate if new tables should be created with the first column as a row header. Just like `colHeaders` this option can be overridden by the page editor in the Wagtail admin.
+-   [contextMenu](https://handsontable.com/docs/6.2.2/Options.html#contextMenu) - Enables or disables the Handsontable right-click menu. By default this is set to `True`. Alternatively you can provide a list or a dictionary with [specific options](https://handsontable.com/docs/6.2.2/demo-context-menu.html#page-specific).
+-   [editor](https://handsontable.com/docs/6.2.2/Options.html#editor) - Defines the editor used for table cells. The default setting is text.
+-   [stretchH](https://handsontable.com/docs/6.2.2/Options.html#stretchH) - Sets the default horizontal resizing of tables. Options include, 'none', 'last', and 'all'. By default TableBlock uses 'all' for the even resizing of columns.
+-   [height](https://handsontable.com/docs/6.2.2/Options.html#height) - The default height of the grid. By default TableBlock sets the height to `108` for the optimal appearance of new tables in the editor. This is optimized for tables with `startRows` set to `3`. If you change the number of `startRows` in the configuration, you might need to change the `height` setting to improve the default appearance in the editor.
+-   [language](https://handsontable.com/docs/6.2.2/Options.html#language) - The default language setting. By default TableBlock tries to get the language from `django.utils.translation.get_language`. If needed, this setting can be overridden here.
+-   [renderer](https://handsontable.com/docs/6.2.2/Options.html#renderer) - The default setting Handsontable uses to render the content of table cells.
+-   [autoColumnSize](https://handsontable.com/docs/6.2.2/Options.html#autoColumnSize) - Enables or disables the `autoColumnSize` plugin. The TableBlock default setting is `False`.
+
+A [complete list of handsontable options](https://handsontable.com/docs/6.2.2/Options.html) can be found on the Handsontable website.
+
+### Changing the default table_options
 
 To change the default table options just pass a new table_options dictionary when a new TableBlock is declared.
 
-.. code-block:: python
-
-  new_table_options = {
-      'minSpareRows': 0,
-      'startRows': 6,
-      'startCols': 4,
-      'colHeaders': False,
-      'rowHeaders': False,
-      'contextMenu': True,
-      'editor': 'text',
-      'stretchH': 'all',
-      'height': 216,
-      'language': 'en',
-      'renderer': 'text',
-      'autoColumnSize': False,
-  }
-
-  class DemoStreamBlock(StreamBlock):
-      ...
-      table = TableBlock(table_options=new_table_options)
-
-
-Supporting cell alignment
-^^^^^^^^^^^^^^^^^^^^^^^^^^
+```python
+new_table_options = {
+    'minSpareRows': 0,
+    'startRows': 6,
+    'startCols': 4,
+    'colHeaders': False,
+    'rowHeaders': False,
+    'contextMenu': True,
+    'editor': 'text',
+    'stretchH': 'all',
+    'height': 216,
+    'language': 'en',
+    'renderer': 'text',
+    'autoColumnSize': False,
+}
+
+class DemoStreamBlock(StreamBlock):
+    ...
+    table = TableBlock(table_options=new_table_options)
+```
+
+### Supporting cell alignment
 
 You can activate the `alignment` option by setting a custom `contextMenu` which allows you to set the alignment on a cell selection.
 HTML classes set by handsontable will be kept on the rendered block. You'll then be able to apply your own custom CSS rules to preserve the style. Those class names are:
 
-* Horizontal: ``htLeft``, ``htCenter``, ``htRight``, ``htJustify``
-* Vertical: ``htTop``, ``htMiddle``, ``htBottom``
-
-.. code-block:: python
-
-  new_table_options = {
-      'contextMenu': [
-          'row_above',
-          'row_below',
-          '---------',
-          'col_left',
-          'col_right',
-          '---------',
-          'remove_row',
-          'remove_col',
-          '---------',
-          'undo',
-          'redo',
-          '---------',
-          'copy',
-          'cut'
-          '---------',
-          'alignment',
-      ],
-  }
-
-    class DemoStreamBlock(StreamBlock):
-        ...
-        table = TableBlock(table_options=new_table_options)
+-   Horizontal: `htLeft`, `htCenter`, `htRight`, `htJustify`
+-   Vertical: `htTop`, `htMiddle`, `htBottom`
+
+```python
+new_table_options = {
+    'contextMenu': [
+        'row_above',
+        'row_below',
+        '---------',
+        'col_left',
+        'col_right',
+        '---------',
+        'remove_row',
+        'remove_col',
+        '---------',
+        'undo',
+        'redo',
+        '---------',
+        'copy',
+        'cut'
+        '---------',
+        'alignment',
+    ],
+}
+
+class DemoStreamBlock(StreamBlock):
+    ...
+    table = TableBlock(table_options=new_table_options)
+```

+ 15 - 15
docs/reference/contrib/typed_table_block.md

@@ -4,7 +4,7 @@ The `typed_table_block` module provides a StreamField block type for building ta
 
 ## Installation
 
-Add `"wagtail.contrib.typed_table_block"` to your INSTALLED_APPS:
+Add `"wagtail.contrib.typed_table_block"` to your `INSTALLED_APPS`:
 
 ```python
 INSTALLED_APPS = [
@@ -36,20 +36,20 @@ class DemoStreamBlock(blocks.StreamBlock):
 To keep the UI as simple as possible for authors, it's generally recommended to use Wagtail's basic built-in block types as column types, as above. However, all custom block types and parameters are supported. For example, to define a 'country' column type consisting of a dropdown of country choices:
 
 ```python
-    table = TypedTableBlock([
-        ('text', blocks.CharBlock()),
-        ('numeric', blocks.FloatBlock()),
-        ('rich_text', blocks.RichTextBlock()),
-        ('image', ImageChooserBlock()),
-        ('country', ChoiceBlock(choices=[
-            ('be', 'Belgium'),
-            ('fr', 'France'),
-            ('de', 'Germany'),
-            ('nl', 'Netherlands'),
-            ('pl', 'Poland'),
-            ('uk', 'United Kingdom'),
-        ])),
-    ])
+table = TypedTableBlock([
+    ('text', blocks.CharBlock()),
+    ('numeric', blocks.FloatBlock()),
+    ('rich_text', blocks.RichTextBlock()),
+    ('image', ImageChooserBlock()),
+    ('country', ChoiceBlock(choices=[
+        ('be', 'Belgium'),
+        ('fr', 'France'),
+        ('de', 'Germany'),
+        ('nl', 'Netherlands'),
+        ('pl', 'Poland'),
+        ('uk', 'United Kingdom'),
+    ])),
+])
 ```
 
 On your page template, the `{% include_block %}` tag (called on either the individual block, or the StreamField value as a whole) will render any typed table blocks as an HTML `<table>` element.