Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions src/wp-includes/default-filters.php
Original file line number Diff line number Diff line change
Expand Up @@ -472,6 +472,9 @@
add_action( 'post_updated', 'wp_check_for_changed_slugs', 12, 3 );
add_action( 'attachment_updated', 'wp_check_for_changed_slugs', 12, 3 );

// Redirect old term slugs.
add_action( 'template_redirect', 'wp_old_slug_term_redirect' );

// Redirect old dates.
add_action( 'post_updated', 'wp_check_for_changed_dates', 12, 3 );
add_action( 'attachment_updated', 'wp_check_for_changed_dates', 12, 3 );
Expand Down
126 changes: 126 additions & 0 deletions src/wp-includes/query.php
Original file line number Diff line number Diff line change
Expand Up @@ -1255,3 +1255,129 @@ function generate_postdata( $post ) {

return false;
}

/**
* Redirect old term slugs to the correct term link.
*
* Attempts to find the current term slug from the past slugs.
*
* @since x.x.x
*/
function wp_old_slug_term_redirect() {
if ( ! is_404() ) {
return;
}

$taxonomy = '';
$slug = '';

if ( '' !== get_query_var( 'category_name' ) ) {
$taxonomy = 'category';
$slug = get_query_var( 'category_name' );
} elseif ( '' !== get_query_var( 'tag' ) ) {
$taxonomy = 'post_tag';
$slug = get_query_var( 'tag' );
} elseif ( '' !== get_query_var( 'taxonomy' ) && '' !== get_query_var( 'term' ) ) {
$taxonomy = get_query_var( 'taxonomy' );
$slug = get_query_var( 'term' );
}

if ( str_contains( $slug, '/' ) ) {
$slug = basename( $slug );
}

if ( '' === $taxonomy || '' === $slug ) {
return;
}

$term_id = _find_term_by_old_slug( $slug, $taxonomy );

if ( ! $term_id ) {
return;
}

/**
* Filters the old slug redirect term ID.
*
* @since x.x.x
*
* @param int $term_id The redirect term ID.
*/
$term_id = apply_filters( 'old_slug_redirect_term_id', $term_id );

if ( ! $term_id ) {
return;
}

$link = get_term_link( (int) $term_id, $taxonomy );

if ( is_wp_error( $link ) ) {
return;
}

if ( get_query_var( 'paged' ) > 1 ) {
if ( get_option( 'permalink_structure' ) ) {
$link = trailingslashit( $link ) . 'page/' . get_query_var( 'paged' );
} else {
$link = add_query_arg( 'paged', get_query_var( 'paged' ), $link );
}
} elseif ( is_feed() ) {
if ( get_option( 'permalink_structure' ) ) {
$link = trailingslashit( $link ) . 'feed';
} else {
$link = add_query_arg( 'feed', get_default_feed(), $link );
}
}

/**
* Filters the old slug redirect URL.
*
* @since 4.4.0
*
* @param string $link The redirect URL.
*/
$link = apply_filters( 'old_slug_redirect_url', $link );

if ( ! $link ) {
return;
}

wp_redirect( $link, 301 );
exit;
}

/**
* Find the term ID for redirecting an old slug.
*
* @since x.x.x
* @access private
*
* @see wp_old_slug_term_redirect()
* @global wpdb $wpdb WordPress database abstraction object.
*
* @param string $slug The term slug to search for.
* @param string $taxonomy The taxonomy to search within.
* @return int The term ID.
*/
function _find_term_by_old_slug( $slug, $taxonomy ) {
global $wpdb;

$query = $wpdb->prepare(
"SELECT tm.term_id FROM $wpdb->termmeta AS tm INNER JOIN $wpdb->term_taxonomy AS tt ON tm.term_id = tt.term_id WHERE tm.meta_key = '_wp_old_slug' AND tm.meta_value = %s AND tt.taxonomy = %s",
$slug,
$taxonomy
);

$last_changed = wp_cache_get_last_changed( 'terms' );
$key = md5( $query );
$cache_key = "find_term_by_old_slug:$key";
$cache = wp_cache_get_salted( $cache_key, 'term-queries', $last_changed );
if ( false !== $cache ) {
return (int) $cache;
}

$term_id = (int) $wpdb->get_var( $query );
wp_cache_set_salted( $cache_key, $term_id, 'term-queries', $last_changed );

return $term_id;
}
14 changes: 14 additions & 0 deletions src/wp-includes/taxonomy.php
Original file line number Diff line number Diff line change
Expand Up @@ -3337,6 +3337,20 @@ function wp_update_term( $term_id, $taxonomy, $args = array() ) {

$tt_id = (int) $wpdb->get_var( $wpdb->prepare( "SELECT tt.term_taxonomy_id FROM $wpdb->term_taxonomy AS tt INNER JOIN $wpdb->terms AS t ON tt.term_id = t.term_id WHERE tt.taxonomy = %s AND t.term_id = %d", $taxonomy, $term_id ) );

// Check for changed slugs and save the old slug.
$old_slug = $term['slug'];
if ( $old_slug !== $slug && ! empty( $old_slug ) ) {
$old_slugs = (array) get_term_meta( $term_id, '_wp_old_slug' );

if ( ! in_array( $old_slug, $old_slugs, true ) ) {
add_term_meta( $term_id, '_wp_old_slug', $old_slug );
}

if ( in_array( $slug, $old_slugs, true ) ) {
delete_term_meta( $term_id, '_wp_old_slug', $slug );
}
}

// Check whether this is a shared term that needs splitting.
$_term_id = _split_shared_term( $term_id, $tt_id );
if ( ! is_wp_error( $_term_id ) ) {
Expand Down
Loading
Loading