Opened 5 years ago
Last modified 13 days ago
#52737 new enhancement
Allow 301 redirect on _wp_old_slug to be filterable
| Reported by: | brookedot | Owned by: | |
|---|---|---|---|
| Priority: | normal | Milestone: | Awaiting Review |
| Component: | Permalinks | Version: | |
| Severity: | normal | Keywords: | has-patch has-unit-tests |
| Cc: | Focuses: |
Description
While the URL on old_slug_redirect_url is filterable the same should be true for the redirect status. It currently is hardcoded as a 301. Allowing any status code will allow for 302 or other status to be used.
https://core.trac.wordpress.org/browser/trunk/src/wp-includes/query.php#L1082
Attachments (3)
Change History (9)
#2
@
5 years ago
- Keywords needs-refresh removed
As per wp_redirect document $status use int parameter.
Good catch updated in 52737.3.2.patch. Not sure why my patch naming was off, but the patch itself should be good.
I'll also mention #40032 as a tangentially related ticket that also touches this code. If both are implemented the one that is added second may need an additional be refresh,
#3
@
5 years ago
Thanks for the patch, this makes sense:
- Minor nit pick: the
permanent redirectcomment next to wp_redirect can be deleted as it may not be permanent. - I think it would be handy to include the post ID or post object as a second parameter on the new filter, this will allow developers to use different status codes under different circumstances.
(BTW: Trac's patch renaming can be weird, if you upload files with 52737.patch or 52737.diff trac will do a better job working out if it needs to rename.)
This ticket was mentioned in PR #9862 on WordPress/wordpress-develop by @kush123.
10 months ago
#4
- Keywords has-unit-tests added
### Overview
This PR introduces a new filter old_slug_redirect_status that allows developers to customize the HTTP redirect status code used by the wp_old_slug_redirect() function. Currently, the redirect status is hardcoded as 301 (permanent redirect), but this change enables the use of 302 (temporary redirect) or other status codes as needed.
### Background
WordPress automatically redirects old post URLs to new ones when a post's slug changes, helping maintain SEO value and user experience. However, the redirect status code was hardcoded as 301, limiting flexibility for developers who might need different redirect behaviors.
Fixes: #52737
### Changes Made
#### Core Changes (src/wp-includes/query.php)
- Added new filter:
old_slug_redirect_statusin thewp_old_slug_redirect()function - Filter parameters:
$status(int): The HTTP response status code (default: 301)$id(int): The post ID being redirected to
- Validation: Added check to prevent redirect if filter returns falsy value
- Documentation: Added proper PHPDoc with
@since 6.8.0tag
#### Test Coverage (tests/phpunit/tests/rewrite/oldSlugRedirect.php)
- New test method:
test_old_slug_redirect_status_filter() - Test scenarios:
- Default 301 redirect behavior (backward compatibility)
- Custom 302 redirect status via filter
- Redirect prevention by returning 0/false
- Proper post ID parameter passing
- Helper methods: Added filter callbacks and redirect capture functionality
### Usage Examples
#### Change redirect to temporary (302)
add_filter( 'old_slug_redirect_status', function( $status, $post_id ) { return 302; // Temporary redirect }, 10, 2 );
#### Conditional redirect based on post type
add_filter( 'old_slug_redirect_status', function( $status, $post_id ) { $post = get_post( $post_id ); if ( $post && $post->post_type === 'product' ) { return 302; // Temporary redirect for products } return $status; // Keep default 301 for other post types }, 10, 2 );
#### Disable redirect for specific posts
add_filter( 'old_slug_redirect_status', function( $status, $post_id ) { $disabled_posts = [123, 456, 789]; if ( in_array( $post_id, $disabled_posts ) ) { return false; // No redirect } return $status; }, 10, 2 );
#### Use different status codes based on post age
add_filter( 'old_slug_redirect_status', function( $status, $post_id ) { $post = get_post( $post_id ); if ( $post ) { $post_age_days = ( time() - strtotime( $post->post_date ) ) / DAY_IN_SECONDS; // Use 302 for recent posts (less than 30 days old) if ( $post_age_days < 30 ) { return 302; } // Use 301 for older posts (default behavior) return 301; } return $status; }, 10, 2 );
### Filter Reference
#### old_slug_redirect_status
Description: Filters the HTTP status code used for old slug redirects.
Parameters:
$status(int): The HTTP response status code to use for the redirect. Default 301.$id(int): The post ID being redirected to.
Return Value:
- (int|false) The HTTP status code to use, or false to prevent the redirect.
Example:
/** * Change old slug redirects to use 302 status for draft posts. * * @param int $status The redirect status code. * @param int $id The post ID being redirected to. * @return int|false Modified status code or false to prevent redirect. */ function custom_old_slug_redirect_status( $status, $id ) { $post = get_post( $id ); if ( $post && $post->post_status === 'draft' ) { return 302; // Temporary redirect for drafts } return $status; // Use default for published posts } add_filter( 'old_slug_redirect_status', 'custom_old_slug_redirect_status', 10, 2 );
#5
@
6 months ago
- Keywords needs-refresh added; needs-testing removed
When I try to apply the patch 52737.3.2.patch against the latest trunk (7.0-alpha-61215-src), it fails with the error message No file found- and creates an Oops.rej file.
As the patch can not be applied successfully, I removed needs-testing and adding needs-refresh.
This ticket was mentioned in PR #12450 on WordPress/wordpress-develop by @abcd95.
13 days ago
#6
- Keywords needs-refresh removed
Trac ticket: https://core.trac.wordpress.org/ticket/52737
This PR addresses Trac Ticket #52737 by introducing the old_slug_redirect_status filter. Previously, wp_old_slug_redirect() hardcoded the redirect status to 301, preventing developers from issuing temporary redirects (302) or other custom HTTP status codes when a post's slug changes.
- Introduced the
old_slug_redirect_statusfilter insrc/wp-includes/query.php. - Passed the
$id(Post ID) as the second parameter to allow conditional redirects based on post properties.
Example -
// Example: Use 302 for WooCommerce products only add_filter( 'old_slug_redirect_status', function( $status, $post_id ) { if ( get_post_type( $post_id ) === 'product' ) return 302; return $status; }, 10, 2 );
- Allowed returning a falsy value to entirely abort the redirect.
![(please configure the [header_logo] section in trac.ini)](/chrome/site/your_project_logo.png)
As per wp_redirect document
$statususe int parameter. So we have to change the doc block for the filter like below