Change the Default WordPress Post Slug to /blog/ Without Breaking CPT URLs

Out of the box, WordPress posts live at /post-title/ with no slug prefix. This is fine for many sites, but if you are building a site where posts form a blog section that sits alongside pages, custom post types, and a WooCommerce shop, you will usually want posts at /blog/post-title/ — both for clarity in navigation and to avoid slug collisions with pages or CPTs. There are two ways to do this in WordPress: via the Permalinks settings screen (quick, but with a category/tag side effect) or programmatically through the register_post_type_args filter (no settings screen dependency, version-control friendly). Both approaches require one extra step to ensure that custom post types do not accidentally inherit the /blog/ prefix — the with_front flag in CPT rewrite arguments. This article covers both methods, explains the side effects of each, and shows how to use pre_post_link to fix generated permalink URLs when using the filter approach.

Problem: WordPress posts have no URL prefix by default. You want all posts accessible at /blog/post-title/ without breaking custom post type URLs or category/tag archive paths.

Solution: Either set a custom permalink structure in Settings → Permalinks, or use the register_post_type_args filter to change the post type's rewrite slug programmatically. Both require 'with_front' => false on all CPTs to prevent them from inheriting the blog prefix.

Method 1 — Settings screen. Go to Settings → Permalinks → Custom structure and enter /blog/%postname%/. Then open the Optional section and set Category base to category and Tag base to tag to prevent the blog prefix appearing in taxonomy archive URLs.

For any existing or future custom post types, add 'with_front' => false to their rewrite arguments to prevent them from picking up the /blog/ prefix:

<?php
register_post_type( 'event', [
    // ... other args ...
    'rewrite' => [
        'slug'       => 'event',
        'with_front' => false, // do not prepend the global permalink prefix
    ],
] );

Method 2 — programmatic filter. Add to functions.php. This approach works without touching the Permalinks settings screen and is safe to deploy via version control:

<?php
add_filter( 'register_post_type_args', 'set_blog_slug_for_posts', 10, 2 );

function set_blog_slug_for_posts( $args, $post_type ) {
    if ( $post_type !== 'post' ) {
        return $args;
    }
    $args['rewrite'] = [
        'slug'       => 'blog',
        'with_front' => true,
    ];
    return $args;
}

// Fix the generated permalink so it includes /blog/
add_filter( 'pre_post_link', 'fix_post_permalink_with_blog_slug', 10, 2 );

function fix_post_permalink_with_blog_slug( $permalink, $post ) {
    if ( $post->post_type !== 'post' ) {
        return $permalink;
    }
    return '/blog/%postname%/';
}

NOTE: Changing post slugs on an existing live site creates broken links for all previously indexed URLs. Before making the change, generate a list of all post URLs from the Yoast SEO post sitemap at /post-sitemap.xml, then bulk-import 301 redirects using the Redirection plugin (by John Godley) before the new slugs go live. Without redirects, search engines will treat every existing post URL as a new page and you will lose accumulated ranking signals.

Sources:

  1. https://wordpress.stackexchange.com/questions/131666/possible-to-change-the-slug-of-default-post-type/131676
  2. https://stackoverflow.com/questions/52427918/how-to-change-wordpress-default-posts-permalinks-programmaticall