diff --git a/CHANGELOG.txt b/CHANGELOG.txt index 0a8cc9db89..6cd825e39c 100644 --- a/CHANGELOG.txt +++ b/CHANGELOG.txt @@ -25,6 +25,7 @@ Changelog * Changed project template to explicitly import development settings via `settings.dev` (Tomas Olander) * Improved L10N and I18N for revisions list (Roel Bruggink) * The multiple image uploader now displays details of server errors (Nigel Fletton) + * Added `WAGTAIL_APPEND_SLASH` setting to determine whether page URLs end in a trailing slash (Andrew Tork Baker) * Fix: The currently selected day is now highlighted only in the correct month in date pickers (Jonas Lergell) * Fix: Fixed crash when an image without a source file was resized with the "dynamic serve view" * Fix: Registered settings admin menu items now show active correctly (Matthew Downey) diff --git a/CONTRIBUTORS.rst b/CONTRIBUTORS.rst index d96651cc49..e935697e31 100644 --- a/CONTRIBUTORS.rst +++ b/CONTRIBUTORS.rst @@ -124,6 +124,7 @@ Contributors * Yannick Chabbert * Andy Babic * Tomas Olander +* Andrew Tork Baker Translators =========== diff --git a/docs/advanced_topics/settings.rst b/docs/advanced_topics/settings.rst index a3d411c1ba..32ab5d20ba 100644 --- a/docs/advanced_topics/settings.rst +++ b/docs/advanced_topics/settings.rst @@ -150,6 +150,29 @@ Site Name This is the human-readable name of your Wagtail install which welcomes users upon login to the Wagtail admin. +.. _append_slash: + +Append Slash +------------ + +.. code-block:: python + + # Don't add a trailing slash to Wagtail-served URLs + WAGTAIL_APPEND_SLASH = False + +Similar to Django's ``APPEND_SLASH``, this setting controls how Wagtail will handle requests that don't end in a trailing slash. + +When ``WAGTAIL_APPEND_SLASH`` is ``True`` (default), requests to Wagtail pages which omit a trailing slash will be redirected by Django's `CommonMiddleware`_ to a URL with a trailing slash. + +When ``WAGTAIL_APPEND_SLASH`` is ``False``, requests to Wagtail pages will be served both with and without trailing slashes. Page links generated by Wagtail, however, will not include trailing slashes. + +.. note:: + + If you use the ``False`` setting, keep in mind that serving your pages both with and without slashes may affect search engines' ability to index your site. See `this Google Webmaster Blog post`_ for more details. + +.. _commonmiddleware: https://docs.djangoproject.com/en/dev/ref/middleware/#module-django.middleware.common +.. _this Google Webmaster Blog post: https://webmasters.googleblog.com/2010/04/to-slash-or-not-to-slash.html + Search ------ diff --git a/docs/releases/1.5.rst b/docs/releases/1.5.rst index 61b29a1e39..bc03418d17 100644 --- a/docs/releases/1.5.rst +++ b/docs/releases/1.5.rst @@ -50,6 +50,7 @@ Minor features * Changed project template to explicitly import development settings via ``settings.dev`` (Tomas Olander) * Improved L10N and I18N for revisions list (Roel Bruggink) * The multiple image uploader now displays details of server errors (Nigel Fletton) + * Added ``WAGTAIL_APPEND_SLASH`` setting to determine whether page URLs end in a trailing slash - see :ref:`append_slash` (Andrew Tork Baker) Bug fixes ~~~~~~~~~ diff --git a/wagtail/wagtailcore/models.py b/wagtail/wagtailcore/models.py index 91ba09a9b7..c9a6409f6b 100644 --- a/wagtail/wagtailcore/models.py +++ b/wagtail/wagtailcore/models.py @@ -34,7 +34,8 @@ from wagtail.utils.deprecation import SearchFieldsShouldBeAList from wagtail.wagtailcore.query import PageQuerySet, TreeQuerySet from wagtail.wagtailcore.signals import page_published, page_unpublished from wagtail.wagtailcore.url_routing import RouteResult -from wagtail.wagtailcore.utils import camelcase_to_underscore, resolve_model_string +from wagtail.wagtailcore.utils import ( + WAGTAIL_APPEND_SLASH, camelcase_to_underscore, resolve_model_string) from wagtail.wagtailsearch import index logger = logging.getLogger('wagtail.core') @@ -784,6 +785,13 @@ class Page(six.with_metaclass(PageBase, MP_Node, ClusterableModel, index.Indexed for (site_id, root_path, root_url) in Site.get_site_root_paths(): if self.url_path.startswith(root_path): page_path = reverse('wagtail_serve', args=(self.url_path[len(root_path):],)) + + # Remove the trailing slash from the URL reverse generates if + # WAGTAIL_APPEND_SLASH is False and we're not trying to serve + # the root path + if not WAGTAIL_APPEND_SLASH and page_path != '/': + page_path = page_path.rstrip('/') + return (site_id, root_url, page_path) @property diff --git a/wagtail/wagtailcore/urls.py b/wagtail/wagtailcore/urls.py index fe33985b3d..3a7ad5139b 100644 --- a/wagtail/wagtailcore/urls.py +++ b/wagtail/wagtailcore/urls.py @@ -3,15 +3,26 @@ from __future__ import absolute_import, unicode_literals from django.conf.urls import url from wagtail.wagtailcore import views +from wagtail.wagtailcore.utils import WAGTAIL_APPEND_SLASH + + +if WAGTAIL_APPEND_SLASH: + # If WAGTAIL_APPEND_SLASH is True (the default value), we match a + # (possibly empty) list of path segments ending in slashes. + # CommonMiddleware will redirect requests without a trailing slash to + # a URL with a trailing slash + serve_pattern = r'^((?:[\w\-]+/)*)$' +else: + # If WAGTAIL_APPEND_SLASH is False, allow Wagtail to serve pages on URLs + # with and without trailing slashes + serve_pattern = r'^([\w\-/]*)$' + urlpatterns = [ url(r'^_util/authenticate_with_password/(\d+)/(\d+)/$', views.authenticate_with_password, name='wagtailcore_authenticate_with_password'), - # Front-end page views are handled through Wagtail's core.views.serve mechanism. - # Here we match a (possibly empty) list of path segments, each followed by - # a '/'. If a trailing slash is not present, we leave CommonMiddleware to - # handle it as usual (i.e. redirect it to the trailing slash version if - # settings.APPEND_SLASH is True) - url(r'^((?:[\w\-]+/)*)$', views.serve, name='wagtail_serve') + # Front-end page views are handled through Wagtail's core.views.serve + # mechanism + url(serve_pattern, views.serve, name='wagtail_serve') ] diff --git a/wagtail/wagtailcore/utils.py b/wagtail/wagtailcore/utils.py index b0daa28416..c0f1e4ed61 100644 --- a/wagtail/wagtailcore/utils.py +++ b/wagtail/wagtailcore/utils.py @@ -4,12 +4,16 @@ import re import unicodedata from django.apps import apps +from django.conf import settings from django.db.models import Model from django.utils.encoding import force_text from django.utils.six import string_types from django.utils.text import slugify +WAGTAIL_APPEND_SLASH = getattr(settings, 'WAGTAIL_APPEND_SLASH', True) + + def camelcase_to_underscore(str): # http://djangosnippets.org/snippets/585/ return re.sub('(((?<=[a-z])[A-Z])|([A-Z](?![A-Z]|$)))', '_\\1', str).lower().strip('_')