Make WordPress Core

Opened 6 weeks ago

Last modified 6 weeks ago

#64785 new enhancement

Add filter for redirect_to URL in get_the_password_form()

Reported by: regnalf's profile regnalf Owned by:
Milestone: Awaiting Review Priority: normal
Severity: normal Version: 2.7
Component: Posts, Post Types Keywords: has-patch 2nd-opinion
Focuses: Cc:

Description

Description of the Problem:
Currently, get_the_password_form() hardcodes the redirect_to hidden input value directly to get_permalink( $post->ID ). While there is a filter for the entire form HTML (the_password_form), changing only the redirect URL requires brittle string manipulation (like str_replace or regex) on the rendered HTML block.

Use Case:
When building custom features like "Public Preview Links" for draft or unpublished posts, or when working with custom routing/headless setups, the standard permalink is often not the correct URL to redirect the user back to after a successful password entry.

Proposed Solution:
Introduce a dedicated filter (e.g., the_password_form_redirect_url or password_form_redirect_to) to easily modify the redirect destination without parsing HTML.

I will link a GitHub Pull Request with the proposed code and a unit test shortly.

Change History (6)

This ticket was mentioned in PR #11128 on WordPress/wordpress-develop by Regnalf.


6 weeks ago
#1

  • Keywords has-patch added

### Description
This PR introduces a new filter the_password_form_redirect_url in get_the_password_form() to allow developers to customize the redirect destination after a password has been entered.

Currently, this is hardcoded to the post's permalink. In scenarios like "Public Preview Links" or headless setups, the standard permalink might not be the correct return-to URL. This filter provides a clean way to modify the URL without parsing the entire HTML form.

#2 in reply to: ↑ description @westonruter
6 weeks ago

  • Keywords 2nd-opinion added

Replying to regnalf:

While there is a filter for the entire form HTML (the_password_form), changing only the redirect URL requires brittle string manipulation (like str_replace or regex) on the rendered HTML block.

Not quite, as now with the HTML Tag Processor it is safe and pretty trivial to update hidden input:

<?php
add_filter(
        'the_password_form',
        static function ( string $output, WP_Post $post ): string {
                $processor = new WP_HTML_Tag_Processor( $output );
                while ( $processor->next_tag( 'INPUT' ) ) {
                        if (
                                $processor->get_attribute( 'type' ) === 'hidden' &&
                                $processor->get_attribute( 'name' ) === 'redirect_to'
                        ) {
                                $processor->set_attribute( 'value', my_plugin_get_password_redirect_url( $post ) );
                                break;
                        }
                }
                return $processor->get_updated_html();
        },
        10,
        2
);

#3 @regnalf
6 weeks ago

Hi @westonruter,

Thanks for the quick feedback! Using the WP_HTML_Tag_Processor here is indeed a very interesting way to avoid brittle Regex or str_replace.

However, from an architectural and performance standpoint, I still strongly believe a dedicated filter for the URL is the much cleaner approach. Here is why:

Separation of Concerns & Overhead
Instantiating a class, parsing the HTML string, finding the tag, and rewriting the HTML is quite a lot of overhead just to modify a single data variable. Modifying a rendered HTML string to change a logical variable feels like a presentation-layer hack for a logic-layer requirement. Filtering the data before it is embedded into the HTML structure is significantly faster and cleaner.

Remaining Fragility (Markup dependency)
If a custom theme or another plugin uses the_password_form to completely rebuild the form (e.g., for custom styling or accessibility), or if the core ever renames the input field in the future, the Tag Processor approach would silently fail because it tightly couples the logic to the exact <input name="redirect_to"> structure.

By providing a dedicated filter for the URL, we don't just patch the default core form, we provide a clean API. Theme developers can then actually use this new hook to retrieve the correct, filtered redirect URL for their custom markup. This makes renamed input fields or complete form rewrites a complete non-issue.

Given how common it is to redirect users after entering a password, wouldn't providing a direct data filter be the more robust "WordPress way" compared to parsing the DOM?

Looking forward to your thoughts!

#4 @westonruter
6 weeks ago

I will say that the likelihood of the redirect_to field ever being renamed is zero. This would be an extreme backwards-compatibility breakage for a very old part of WordPress.

I have very little experience with password-protected posts. I'll leave this for another contributor to comment on the need for a filter here.

In the meantime, using the HTML Tag Processor will be very reliable.

#5 @regnalf
6 weeks ago

Hi @westonruter and everyone,

You are absolutely right about the "redirect_to field" — the likelihood of it ever being renamed is practically zero, so relying on the field name isn't the fragile part here.

The goal of a "Public Preview Link" approach already works perfectly for me. The only remaining minor flaw is the password submission redirect itself.

When a client visits the password-protected post via a special link (e.g., ?preview_hash=abc123), they still need to enter the post password. After submitting the form, the default redirect drops these custom query parameters. To seamlessly maintain the preview state for the client, I just need to append that specific hash back to the redirect URL using add_query_arg().

This is where the WP_HTML_Tag_Processor approach or version with str_replace falls short. If we rely on parsing the HTML, safely modifying the URL to append parameters becomes highly complex. A developer would have to:

  • Extract the existing URL from the HTML attribute.
  • Parse the URL to safely append new arguments (checking for existing ? or & in case other plugins already added parameters).
  • Re-inject the string back into the HTML.

This makes it impossible to simply use core functions like add_query_arg(), which expect a raw URL string, not an HTML block. Furthermore, if multiple plugins try to append parameters this way by parsing the same HTML string, they risk overriding each other and breaking the markup.

A dedicated data filter (apply_filters( '...', $url )) provides a clean API. It allows any plugin or theme to safely run add_query_arg() on the raw URL before it is rendered. This guarantees interoperability between plugins and keeps the logic completely separate from the presentation layer.

My opinion is that a hook to filter the url is the only truly robust solution for handling URL parameters in this scenario.

#6 @westonruter
6 weeks ago

  • Version changed from 6.9.1 to 2.7
Note: See TracTickets for help on using tickets.