It's now several hours that I am trying to get this done without finding a proper solution.


I'd like WP to use the following URL structure:

1) Posts -> /%category%/articles/%postname%/
2) CPT   -> /%category%/CPT/%postname%/

Where the %category% bit is the default categories taxonomy used in the Posts


To add the default categories taxonomy to the CPT, this bit has been added while registering the CPT

'taxonomies'         => array('category'),

whereas the followings are the rewrite args

$rewrite_args = array( 'slug' => '%category%/test', 'with_front' => false, 'feeds' => false, 'pages' => false );


I know the most obvious solution is to change the permalink structure in the setting panel. And this need to be done in any case otherwise anything I will describe will work.

So my Permalink structure has been set as



If I leave the basic configuration, no hooks, anything. Posts works as expected.

At the time I hook on the post_type_link to make my CPT replacing the %category%, the default configuration stops working.

I tried to re-register the Posts type; this seems to give better results (though there is the inconvenience to see the "posts" item twice in the admin bar), but for some reason when I do this, the CPT custom slug stops working.

Do you have any specific hint? Thanks Andrea

  • when you say "At the time I hook on the post_type_link to make my CPT replacing the %category%, the default configuration stops working", how does it stop working? what happens? what does your post_type_link code look like?
    – Milo
    Jun 24, 2014 at 17:50
  • also- category is a hierarchical taxonomy, your issue is made more complicated if you need to support parent/child category permalinks.
    – Milo
    Jun 24, 2014 at 18:16

3 Answers 3


You'll have to add your own rewrite rules to make this work, no way around that.

First, don't use the %category% rewrite tag, register your own tag and use that for the CPT categories:

function wpd_query_vars( $qvars ) {
    $qvars[] = 'cptcat';
    return $qvars;
add_filter( 'query_vars', 'wpd_query_vars' );

You can then swap that tag for the category in post_type_link. Note that this only handles one level of term. If you want to do parent/child term permalinks, you'll have to modify this function and add a rewrite rule to catch every level of term hierarchy.

function wpd_test_post_link( $post_link, $id = 0 ){
    $post = get_post($id);  
    if ( is_object( $post ) && $post->post_type == 'your_cpt' ){
        $terms = wp_get_object_terms( $post->ID, 'category' );
        if( $terms ){
            foreach( $terms as $term ){
                if( 0 == $term->parent ){
                    return str_replace ( '%cptcat%' , $term->slug , $post_link );
        } else {
            return str_replace ( '%cptcat%' , 'uncategorized', $post_link );
    return $post_link;
add_filter( 'post_type_link', 'wpd_test_post_link', 1, 2 );

Now this still won't work because WordPress thinks your permalink is a parent/child category request. Add a rewrite rule to override that:

function wpd_test_rewrites(){
add_action( 'init', 'wpd_test_rewrites' );
  • thnaks for this. Just to be 100%, how the slug should look like? Jun 25, 2014 at 11:00
  • Well, I get the code on the test machine, and it's almost there. One thing that I notice is the fact that the %postname is no longer add. I solved this by changing the wpd_test_post_link function, but I still have a problem with the final SQL query that WP runs. Instead of querying for my CPT, WP try to fetch from the post_type=post thus resulting in 0 records and a 404 error page. Do you know how can I fix this? Jun 25, 2014 at 12:55
  • The slug should be the same but with the new rewrite tag instead. You've not added the rewrite rule if its querying the wrong post type. Tested and working on current version of WordPress.
    – Milo
    Jun 25, 2014 at 14:21
  • Yes, you are right. I left a comment there. But I had still to change the pos_link to add the post type. But overall, a big thank you. Jun 25, 2014 at 14:35
  • One more question, what if I do attach more than a function to the post_type_link (because I have more than a CPT). Would that work, or should I have just one common function? Jun 25, 2014 at 14:46

/%category%/ isn't a variable that Wordpress can process or replace when you setup a slug for a Customer Post Type.

If you want a category system to run inside the Custom Post Type as like is available for the normal post type, ensure you have these enabled:

capability_type' => 'post', 'has_archive' => true, 'hierarchical' => true,

Hopefully this will help.

  • This is not the problem. Jun 24, 2014 at 17:43
  • @AndreaMoro apologises, but you may want to edit or clean up the question as it's confusing as to what aspect your asking about, CTP slug or custom permalinks. I also think that it won't be possible to replace the %category% section of a permalink structure as it's required for normal posts to work, the minimal functionality of Wordpress. Jun 24, 2014 at 17:49
  • @Caleuanhokins I added few more details in the hope to make this clear?. As per my understanding the slug or custom permalinks are the same, aren't they? Jun 24, 2014 at 17:55
  • @AndreaMoro they actually work differently. What you may need to do is see Lopinsjk's second answer in their topic on Wordpress.org site: wordpress.org/support/topic/… Jun 24, 2014 at 18:00
  • I've plaid around that solution, but as soon as the hook is used, the standard slugs/permalinks stop working. Can you get clarified the difference between slug and permalink, please? Jun 24, 2014 at 18:07

I think that you are looking to use the add_permastruct function. I haven't done a lot with it, but from my understanding this is what you are looking to do:

(Adapted from a TutsPlus tutorial)

// Please note that this will only work on WordPress 3.4+ http://core.trac.wordpress.org/ticket/19871
add_permastruct('cpt_category_archive', '%category%/%yourcpt_cpt%/%postname%');

Your declaration for the CPT looks fine, but 'slug' => '%category%/test' should just be 'slug' => 'test'

This is untested, so you should try it on a non-production server. You should likely flush rewrite rules after making the code live (perhaps with flush_rewrite_rules()).

This is some advanced futzing around with WP Rewrite, more info at the codex entry for WP Rewrite and add_permastruct as well as in the code.

  • this is essentially what happens when you register a post type - a rewrite tag and permastruct are added. in this case making the slug %category%/whatever_key_you_registered_the_cpt_with will generate an identical set of rewrite rules as your example.
    – Milo
    Jun 25, 2014 at 15:00

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.