Make WordPress Core

Opened 5 years ago

Last modified 2 months ago

#52737 new enhancement

Allow 301 redirect on _wp_old_slug to be filterable

Reported by: brookedot's profile brookedot 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)

52737.patch (557 bytes) - added by brookedot 5 years ago.
52737.2.patch (557 bytes) - added by brookedot 5 years ago.
52737.3.2.patch (554 bytes) - added by brookedot 5 years ago.

Download all attachments as: .zip

Change History (7)

@brookedot
5 years ago

#1 @mukesh27
5 years ago

  • Keywords needs-refresh added

As per wp_redirect document $status use int parameter. So we have to change the doc block for the filter like below

/**
 * Filters the old slug redirect status.
 *
 * @since 5.8.0
	 *
 * @param int $status The HTTP response status code to use.
 */

@brookedot
5 years ago

@brookedot
5 years ago

#2 @brookedot
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,

Version 0, edited 5 years ago by brookedot (next)

#3 @peterwilsoncc
5 years ago

Thanks for the patch, this makes sense:

  • Minor nit pick: the permanent redirect comment 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)

  1. Added new filter: old_slug_redirect_status in the wp_old_slug_redirect() function
  2. Filter parameters:
    • $status (int): The HTTP response status code (default: 301)
    • $id (int): The post ID being redirected to
  3. Validation: Added check to prevent redirect if filter returns falsy value
  4. Documentation: Added proper PHPDoc with @since 6.8.0 tag

#### Test Coverage (tests/phpunit/tests/rewrite/oldSlugRedirect.php)

  1. New test method: test_old_slug_redirect_status_filter()
  2. 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
  3. 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 );
Note: See TracTickets for help on using tickets.