Loading Experience

How to Link Post Categories to their Slugs and Set Up 301 Redirects

Table of Contents

Moving your WordPress posts to a /blog/%category%/ permalink structure is good for SEO — but the moment you save the new structure, every existing URL starts returning a 404. This guide fixes that in two steps, and every old URL redirects itself from then on.

yoursite.com/my-post/  →  301  →  yoursite.com/blog/vps-hosting/my-post/

No redirect plugin. No redirect table to maintain. New and recategorised posts are handled automatically.

Before You Start: Check for Slug Conflicts

If a page and a post share the same slug, that page will start redirecting to the post. Rename one of them before you begin.

Most sites have no overlap. To be certain, run this in phpMyAdmin — it should return nothing:

SELECT a.post_name FROM wp_posts a
JOIN wp_posts b ON b.post_name = a.post_name
 AND b.post_type = 'page' AND b.post_status = 'publish'
WHERE a.post_type = 'post' AND a.post_status = 'publish';
1

Step 1: Change the WordPress Permalink Structure

In WordPress admin go to Settings → Permalinks, choose Custom Structure, and enter:

/blog/%category%/%postname%/

Click Save Changes. Your posts now live at the new URLs.

Every old URL returns a 404 from this moment — step 2 fixes that, so do it straight away.

2

Step 2: Add the 301 Redirect Code

This catches any old URL and sends it to the correct new one — for every post you already have, and every post you publish later.

add_action( 'template_redirect', function () {
    if ( ! is_404() || is_admin() ) return;

    $uri  = isset( $_SERVER['REQUEST_URI'] ) ? wp_unslash( $_SERVER['REQUEST_URI'] ) : '';
    $path = wp_parse_url( $uri, PHP_URL_PATH );
    if ( ! is_string( $path ) || '' === trim( $path, '/' ) ) return;

    $segments = array_values( array_filter( explode( '/', trim( $path, '/' ) ) ) );
    if ( empty( $segments ) ) return;

    // already a new-style URL
    if ( 'blog' === $segments[0] && count( $segments ) >= 3 ) return;

    $last = urldecode( end( $segments ) );
    if ( preg_match( '/^(page|feed|amp|embed)$/i', $last ) && count( $segments ) > 1 ) {
        array_pop( $segments );
        $last = urldecode( end( $segments ) );
    }

    $slug = sanitize_title( $last );
    if ( '' === $slug ) return;

    $match = get_posts( array(
        'name'        => $slug,
        'post_type'   => 'post',
        'post_status' => 'publish',
        'numberposts' => 1,
        'fields'      => 'ids',
    ) );
    if ( empty( $match ) ) return;

    $target = get_permalink( $match[0] );
    if ( ! $target ) return;

    if ( untrailingslashit( (string) wp_parse_url( $target, PHP_URL_PATH ) ) === untrailingslashit( $path ) ) return;

    $query = wp_parse_url( $uri, PHP_URL_QUERY );
    if ( ! empty( $query ) ) $target .= ( strpos( $target, '?' ) === false ? '?' : '&' ) . $query;

    wp_safe_redirect( $target, 301 );
    exit;
}, 1 );

Only change the highlighted 'blog' if your permalink uses a different prefix.

Where to Add the Code

BestA new file at wp-content/mu-plugins/redirect.php, starting with <?php. Always active, and it survives theme changes.
EasiestA snippets plugin such as WPCode or Code Snippets — paste and activate.
Also fineYour child theme's functions.php. Never the parent theme — updates will wipe it.

How to Verify the Redirects Are Working

Open an old post URL. It should jump straight to the new address. To confirm properly:

curl -sI https://yoursite.com/old-post-slug/ | grep -iE "^(HTTP/|location:)"

You want a 301 and a location: header containing /blog/….

Troubleshooting Permalink Redirect Issues

Still 404Your cache is serving the old response. Purge Cloudflare and any caching plugin. To confirm that's all it is, add ?x=123 to the URL — if that redirects, the code works and only the cache is stale.
A page redirectsA post shares its slug. Rename one of them.
Goes to /blog/uncategorized/That post has no category assigned. Assign one — the redirect updates instantly.
Nothing happensAnother plugin is handling 404s first. SEO plugins are the usual cause — turn off their 404 or redirect handling.

Why You Don't Need a Redirect Plugin

Redirect plugins store one rule per URL, which you then maintain by hand forever. This code stores nothing — it looks up each post as the request arrives, so new posts and recategorised posts are handled on their own.

Works with any permalink structure · no posts or pages are modified

Share it
Still Got Stuck? Need Help
Got a Project in Mind?
Schedule a Meeting!