Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

RFC 93: Redirect improvements #93

Open
wants to merge 4 commits into
base: main
Choose a base branch
from

Conversation

RealOrangeOne
Copy link
Member

@RealOrangeOne RealOrangeOne commented Feb 22, 2024

Add an RFC (as discussed internally) for adding a few useful features to redirects.

View rendered version

In Django 4.2, the redirect only happens in `process_response`, so Wagtail kicks in first.

### Open questions

1. Should we also confirm whether the `old_path` matches an existing view?
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this is well worth flagging. i.e. "There is an existing system path that may stop working. Are you sure?"

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would this still be relevant if redirects continue to only come into play in the event of a 404?


An `is_eager` column will be added to a `Redirect`, which flags whether the redirect should run before the rest of the Wagtail page process, or afterwards (as they would currently). `is_eager` will default to `False`, to ensure it's not a breaking change, or impact other site behaviours.

To properly support `is_eager`, the `RedirectMiddleware` will also need bringing up the `MIDDLEWARES` list, below incredibly high middleware such as `SecurityMiddleware`, `GzipMiddleware` and `WhitenoiseMiddleware`, but still as high as possible. Unfortunately, this will impact performance, as a database query will need to be made for redirects on every request.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is one that doesn't sit well with me at the moment. I can see pitchforks being raised :)

What if we provide a separate, EagerRedirectMiddleware for just this? Plenty of Wagtail sites are perfectly fine with the current setup


### Specification

I propose Wagtail automatically update URL redirects which point to Wagtail pages to reference the page instead. An example implementation exists in [#6465](https://github.com/wagtail/wagtail/issues/6465).
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This will need to account for i18n-prefixed URLs

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Localisation may make this a lot more complex (but is also something we need to account for). For example, if we want to redirect to a page with multiple translations, what URL do we redirect to?

@RealOrangeOne RealOrangeOne changed the title Redirect improvements RFC 93: Redirect improvements Mar 4, 2024

### Specification

As part of the redirect creation process, redirects will confirm that the source and destination URL are different. This is relatively simple to determine for single-site deployments:
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would this get in the way of people manually setting up redirects in advance of taking certain actions (E.g. Moving a group of pages) when automatic redirect creation is disabled?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It would, yes, and so would require automatic redirections to properly kick in. We could make this validation opt-out.

Django 4.2 makes this a lot better, and eager redirects can severely impact performance and introduce potential foot-guns.
@gasman gasman self-assigned this Mar 22, 2024
@gasman
Copy link
Contributor

gasman commented Mar 22, 2024

For background, the use-case that originally prompted the desire to validate against circular redirects was a site that added various /foo -> /foo/ redirects (redundantly, since CommonMiddleware already handled this).

With eager redirects out of the picture (no longer required as of Django 4.2 due to django/django@fbac2a4), it seems to me that the usefulness of this becomes more marginal, since this redirect loop would only happen if the destination was a 404 (in which case the redirect would not be doing anything useful even if it were working correctly).

Having said that, there's no real downside to having this validation in place, so happy to go ahead with adding it.

@gasman
Copy link
Contributor

gasman commented Mar 22, 2024

Should we also confirm whether the old_path matches an existing view?

I take it the idea here is to provide some sort of feedback to the user to indicate "this redirect won't trigger because its URL corresponds to an existing page"? I can see the value in that, but I think it's different enough from the focus of this RFC, and hard enough to get right, that we shouldn't try to tackle it here. (Presumably in many / most cases, old_path will indeed pattern-match against at least one view at the urlconf level - namely, wagtail_serve - but we then need to follow Wagtail's routing logic to find out if it's a 404 or not. So either that's a special case for wagtail_serve, or we generalise it to support other views that might return a 404 somewhere in their execution... I think that rabbit-hole could get pretty deep.)

@gasman
Copy link
Contributor

gasman commented Mar 22, 2024

[Converting URL redirects to page redirects]

Should this be automatic, or a warning during creation or a report? Adding links in RichText automatically detects internal links, but prompts the user. This might be more difficult in a conventional creation flow.

My gut feeling is that converting them automatically is possibly more "magic" than we really want - it's overriding what the user specifically asked to do, with what the system thinks they meant to do, and I could imagine situations where it gets it wrong. Something along the lines of:

  • A bank wants to relaunch their mortgage calculator app
  • Their content editor creates a page at /new-mortgage-calculator/ talking about the new mortgage calculator they'll be launching soon, along with a URL redirect from /mortgage-calculator/ to /new-mortgage-calculator/
  • A short while later they deploy the new app at /new-mortgage-calculator/, and move the page to somewhere under /archive/
  • The redirect from /mortgage-calculator/ is now unexpectedly pointing to the archived page

@gasman
Copy link
Contributor

gasman commented May 3, 2024

Picking this up again for 6.2 planning...

I think we're happy to go ahead with validating against circular redirects, as per #11659.

Re converting URL redirects to page redirects - as per above, I don't think this should happen automatically. A UI for prompting users about this might look something like:

On submitting the "add redirect" form, if the external URL field has been filled in, parse it and run it through Wagtail's routing logic. If this resolves to a page, AND that page's get_url method returns a URL equal to the one entered (this latter check needed to account for things like RoutablePageMixin where converting to a page redirect would lose information), present a confirmation page saying:

The URL {url} corresponds to the page {page title}. Do you wish to create this as a page redirect? This will ensure that the redirect continues to work cleanly if the page is moved or renamed in future.
Yes, change this to a page redirect
No, keep this as a URL redirect

These buttons will be linked to hidden forms; the "yes" button will submit a replica of the original form with the page ID populated and the URL field cleared, while the "no" button will submit a replica of the original form with an additional flag to skip the routing check.

This workflow will only work for adding a single redirect, not bulk uploading - are we happy to treat the latter as out of scope, or do we need to account for that too?

@ababic
Copy link

ababic commented May 4, 2024

This workflow will only work for adding a single redirect, not bulk uploading - are we happy to treat the latter as out of scope, or do we need to account for that too?

I would say that's a fair compromise. But, I am slightly concerned about giving developers / admins / editors a false sense of security here... It's very easy to assume that because Wagtail treats individual redirects one way, it also does something about batches (whether visible or not), and therefore assume it's something they don't need to consider. Is there anything we could do to alleviate this?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
Status: ✅ Done
Development

Successfully merging this pull request may close these issues.

4 participants