Opened 5 years ago
Last modified 2 months ago
#52737 new enhancement
Allow 301 redirect on _wp_old_slug to be filterable
| Reported by: |
|
Owned by: | |
|---|---|---|---|
| Milestone: | Awaiting Review | Priority: | normal |
| Severity: | normal | Version: | |
| Component: | Permalinks | Keywords: | has-patch needs-testing has-unit-tests |
| Focuses: | Cc: |
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 (7)
#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.
2 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 );
As per wp_redirect document
$statususe int parameter. So we have to change the doc block for the filter like below