Custom Post Type posts, conflict with posts after add_rewrite_rule to top

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
    register_post_type(
        'our-success',
        array(
            '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_rewrite_rule(
        '([^/]+)/([^/]+)(?:/([0-9]+))?/?$',
        'index.php?success-category=$matches[1]our-success=$matches[2]post_type=our-success',
        'top'
    );
}
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%/

Topic rewrite-tag rewrite-rules permalinks custom-post-types Wordpress

Category Web


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.


Update

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' ){
        return;
    }
    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){
        flush_rewrite_rules();
        update_option( 'success-category-flush-rewrite-rules', false );
    }
}
add_action( 'init', 'flush_rewrite_after_term_relation',1,1 );

About

Geeks Mental is a community that publishes articles and tutorials about Web, Android, Data Science, new techniques and Linux security.