Skip to content

Commit 2ec8d6a

Browse files
committed
Taxonomy: Add old slug redirects for term URLs
1 parent acebfd0 commit 2ec8d6a

4 files changed

Lines changed: 458 additions & 0 deletions

File tree

src/wp-includes/default-filters.php

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -472,6 +472,9 @@
472472
add_action( 'post_updated', 'wp_check_for_changed_slugs', 12, 3 );
473473
add_action( 'attachment_updated', 'wp_check_for_changed_slugs', 12, 3 );
474474

475+
// Redirect old term slugs.
476+
add_action( 'template_redirect', 'wp_old_slug_term_redirect' );
477+
475478
// Redirect old dates.
476479
add_action( 'post_updated', 'wp_check_for_changed_dates', 12, 3 );
477480
add_action( 'attachment_updated', 'wp_check_for_changed_dates', 12, 3 );

src/wp-includes/query.php

Lines changed: 126 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1255,3 +1255,129 @@ function generate_postdata( $post ) {
12551255

12561256
return false;
12571257
}
1258+
1259+
/**
1260+
* Redirect old term slugs to the correct term link.
1261+
*
1262+
* Attempts to find the current term slug from the past slugs.
1263+
*
1264+
* @since x.x.x
1265+
*/
1266+
function wp_old_slug_term_redirect() {
1267+
if ( ! is_404() ) {
1268+
return;
1269+
}
1270+
1271+
$taxonomy = '';
1272+
$slug = '';
1273+
1274+
if ( '' !== get_query_var( 'category_name' ) ) {
1275+
$taxonomy = 'category';
1276+
$slug = get_query_var( 'category_name' );
1277+
} elseif ( '' !== get_query_var( 'tag' ) ) {
1278+
$taxonomy = 'post_tag';
1279+
$slug = get_query_var( 'tag' );
1280+
} elseif ( '' !== get_query_var( 'taxonomy' ) && '' !== get_query_var( 'term' ) ) {
1281+
$taxonomy = get_query_var( 'taxonomy' );
1282+
$slug = get_query_var( 'term' );
1283+
}
1284+
1285+
if ( str_contains( $slug, '/' ) ) {
1286+
$slug = basename( $slug );
1287+
}
1288+
1289+
if ( '' === $taxonomy || '' === $slug ) {
1290+
return;
1291+
}
1292+
1293+
$term_id = _find_term_by_old_slug( $slug, $taxonomy );
1294+
1295+
if ( ! $term_id ) {
1296+
return;
1297+
}
1298+
1299+
/**
1300+
* Filters the old slug redirect term ID.
1301+
*
1302+
* @since x.x.x
1303+
*
1304+
* @param int $term_id The redirect term ID.
1305+
*/
1306+
$term_id = apply_filters( 'old_slug_redirect_term_id', $term_id );
1307+
1308+
if ( ! $term_id ) {
1309+
return;
1310+
}
1311+
1312+
$link = get_term_link( (int) $term_id, $taxonomy );
1313+
1314+
if ( is_wp_error( $link ) ) {
1315+
return;
1316+
}
1317+
1318+
if ( get_query_var( 'paged' ) > 1 ) {
1319+
if ( get_option( 'permalink_structure' ) ) {
1320+
$link = trailingslashit( $link ) . 'page/' . get_query_var( 'paged' );
1321+
} else {
1322+
$link = add_query_arg( 'paged', get_query_var( 'paged' ), $link );
1323+
}
1324+
} elseif ( is_feed() ) {
1325+
if ( get_option( 'permalink_structure' ) ) {
1326+
$link = trailingslashit( $link ) . 'feed';
1327+
} else {
1328+
$link = add_query_arg( 'feed', get_default_feed(), $link );
1329+
}
1330+
}
1331+
1332+
/**
1333+
* Filters the old slug redirect URL.
1334+
*
1335+
* @since 4.4.0
1336+
*
1337+
* @param string $link The redirect URL.
1338+
*/
1339+
$link = apply_filters( 'old_slug_redirect_url', $link );
1340+
1341+
if ( ! $link ) {
1342+
return;
1343+
}
1344+
1345+
wp_redirect( $link, 301 );
1346+
exit;
1347+
}
1348+
1349+
/**
1350+
* Find the term ID for redirecting an old slug.
1351+
*
1352+
* @since x.x.x
1353+
* @access private
1354+
*
1355+
* @see wp_old_slug_term_redirect()
1356+
* @global wpdb $wpdb WordPress database abstraction object.
1357+
*
1358+
* @param string $slug The term slug to search for.
1359+
* @param string $taxonomy The taxonomy to search within.
1360+
* @return int The term ID.
1361+
*/
1362+
function _find_term_by_old_slug( $slug, $taxonomy ) {
1363+
global $wpdb;
1364+
1365+
$query = $wpdb->prepare(
1366+
"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",
1367+
$slug,
1368+
$taxonomy
1369+
);
1370+
1371+
$last_changed = wp_cache_get_last_changed( 'terms' );
1372+
$key = md5( $query );
1373+
$cache_key = "find_term_by_old_slug:$key";
1374+
$cache = wp_cache_get_salted( $cache_key, 'term-queries', $last_changed );
1375+
if ( false !== $cache ) {
1376+
return (int) $cache;
1377+
}
1378+
1379+
$term_id = (int) $wpdb->get_var( $query );
1380+
wp_cache_set_salted( $cache_key, $term_id, 'term-queries', $last_changed );
1381+
1382+
return $term_id;
1383+
}

src/wp-includes/taxonomy.php

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3337,6 +3337,20 @@ function wp_update_term( $term_id, $taxonomy, $args = array() ) {
33373337

33383338
$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 ) );
33393339

3340+
// Check for changed slugs and save the old slug.
3341+
$old_slug = $term['slug'];
3342+
if ( $old_slug !== $slug && ! empty( $old_slug ) ) {
3343+
$old_slugs = (array) get_term_meta( $term_id, '_wp_old_slug' );
3344+
3345+
if ( ! in_array( $old_slug, $old_slugs, true ) ) {
3346+
add_term_meta( $term_id, '_wp_old_slug', $old_slug );
3347+
}
3348+
3349+
if ( in_array( $slug, $old_slugs, true ) ) {
3350+
delete_term_meta( $term_id, '_wp_old_slug', $slug );
3351+
}
3352+
}
3353+
33403354
// Check whether this is a shared term that needs splitting.
33413355
$_term_id = _split_shared_term( $term_id, $tt_id );
33423356
if ( ! is_wp_error( $_term_id ) ) {

0 commit comments

Comments
 (0)