I had cpt with taxonomy like this:

add_action('init', 'zsz_add_posttype');
function zsz_add_posttype()
// -- Taxonomy CATEGORIES  -  [category-a] [category-b] [category-c] [...]
    register_taxonomy('success-category', array('our-success'), array(
        'hierarchical' => true,
        'labels' => array('name' => __('Success Category', ZSZ_DOMAIN) ),
        'show_ui' => true,
        'show_admin_column' => true,
        'query_var' => true,
        'rewrite' => array('slug' => 'success-category'),
        'show_in_rest' => true,
    // -- OUR SUCCESS
            'labels' => array(
                'name' => __('Our Success', ZSZ_DOMAIN),
                'singular_name' => __('Our Success', ZSZ_DOMAIN)
            'public' => true,
            'has_archive' => false,
            'publicly_queryable' => true,
            'exclude_from_search' => true,
            'show_in_rest' => true,
            'menu_position' => 5,
            //'rewrite' => array('slug' => ''),
            'supports' => array('title', 'editor', 'thumbnail', 'revisions', 'excerpt', 'page-attributes'),
            'menu_icon' => 'dashicons-awards',
            'rewrite' => array('slug' => __('our-success', ZSZ_DOMAIN), 'with_front' => false),

When I use modified code from here:

function wpa_show_permalinks( $post_link, $post ){
    if(!is_object($post) || $post->post_type !== 'our-success' ){
        return $post_link;

    $terms = wp_get_object_terms( $post->ID, 'success-category' );
    if( isset($terms[0]->slug) && !empty($terms[0]->slug) ){
        return str_replace( 'our-success' , $terms[0]->slug , $post_link );
    return $post_link;
add_filter( 'post_type_link', 'wpa_show_permalinks', 1, 2 );

And add rewrite rule:

function wpd_foo_rewrite_rule() {
add_action( 'init', 'wpd_foo_rewrite_rule',1,1 );

Custom types singles are working fine, but normal single posts are giving 404. When I change to add_rewrite_rule([...], 'bottom') things are reversed, and cpt single give 404 when single posts are working fine. I'm thinking that two rewrite rules looks the same and Wordpress don't recognize that post is custom. How can I fix it? What I'm doing wrong?

What I want to achieve:

  • working cpt single post: example.com/success-category-abc/our-success-postname/
  • working wordpress posts: example.com/category-name/postname/

Permalinks in dashboard are set to: example.com/%category%/%postname%/

1 Answer 1


I think I solved my problem. So if you have your WordPress post permalink set to %category%/%postname%/, and you want this for custom post type and taxonomy, you could prepare your rewrite links for all generated taxonomy terms (cat-a, cat-b etc.). Code:

add_filter( 'rewrite_rules_array', function($rules) {
    $categories = get_terms(['taxonomy' => 'success-category' ]);
    foreach ($categories as $category){
        $rules = array($category->slug.'/([^/]*)/?$' => 'index.php?success-category='.$category->slug.'&our-success=$matches[1]&post_type=our-success') + $rules;
    return $rules;

I was trying the same with wpd_foo_rewrite_rule() function, but it seems like there are no terms with 'init' action. So I have removed function wpd_foo_rewrite_rule()

I left function wpa_show_permalinks unchanged.

There is only problem with new created terms, but if you flush_rewrite_rules() once, problem disappear.


I ended with two more functions.

First for checking if term haven't any relation and setting flag for future flush_rewrite_rules() with update_option( 'success-category-flush-rewrite-rules', true );

add_action('added_term_relationship', 'flush_if_term_first_time_in_use', 10, 3);
function flush_if_term_first_time_in_use( int $object_id, int $tt_id, string $taxonomy ) {
    if( $taxonomy !== 'success-category' ){
    if( get_term($tt_id)->count === 0 ){
        update_option( 'success-category-flush-rewrite-rules', true );

Second only for execute flush_rewrite_rules()

function flush_rewrite_after_term_relation() {
    if( get_option('success-category-flush-rewrite-rules') == true){
        update_option( 'success-category-flush-rewrite-rules', false );
add_action( 'init', 'flush_rewrite_after_term_relation',1,1 );

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.