How to add custom taxonomy in custom post type permalink?

Solution would be a little tricky but you’re on the right path.

  1. You need to register taxonomy and post type with dynamic rewrite:
function wpse346452_cpt() {

    register_taxonomy( 'campaign', 'asset', array( 'label' => 'Campaing' ) );

    register_post_type( 'asset', array(
        'public' => true,
        'label' => 'Asset',
        'rewrite' => array(
            'slug' => '%campaign_name%',
        ),
    ) );

}
add_action( 'init', 'wpse346452_cpt' );
  1. You need to replace that dynamic rewrite so that it represents the term attached to it:
function wpse346452_permalink( $post_link, $post ) {
    if( is_object( $post ) && $post->post_type == 'asset' ) {
        $terms = wp_get_object_terms( $post->ID, 'campaign' );
        if( $terms ) {
            return str_replace( '%campaign_name%' , $terms[0]->slug , $post_link );
        }
    }
    return $post_link;
}
add_filter( 'post_type_link', 'wpse346452_permalink', 10, 2 );
  1. Now you get 404 because the rewrite rule is not defined yet. Each time you have a new term under campaign, you need a new rule. So let’s add rewrite rules for each available terms dynamically:
function wpse346452_dynamic_rw_rules() {

    $terms = get_terms( array(
        'taxonomy' => 'campaign',
        'hide_empty' => false,
    ) );

    if( !empty( $terms ) ) {
        foreach( $terms as $term ) {
            add_rewrite_rule(
                '^' . $term->slug . '/(.*)/?$',
                'index.php?post_type=asset&name=$matches[1]',
                'top'
            );
        }
    }

}
add_action( 'init', 'wpse346452_dynamic_rw_rules' );

Now it will work as you needed. But the downside is, whenever you add new campaign, you need to go to permalink settings and save, thus flush rewrite rules. So let’s automate that too:

function wpse346452_flush_rewrite( $term_id, $tt_id, $taxonomy = 'campaign' ) {
    if( $taxonomy === 'campaign' ) {
        $term = get_term_by( 'term_taxonomy_id', $tt_id );
        add_rewrite_rule(
            '^' . $term->slug . '/(.*)/?$',
            'index.php?post_type=asset&name=$matches[1]',
            'top'
        );
        if( !function_exists( 'flush_rewrite_rules' ) ) {
            require_once WPINC . '/rewrite.php';
        }
        flush_rewrite_rules();
    }
}
add_action( 'edit_term', 'wpse346452_flush_rewrite', 10, 3 );
add_action( 'create_campaign', 'wpse346452_flush_rewrite', 10, 3 );

Here we’re hooking into create and edit term and if the taxonomy is campaign then we’re firing flush_rewrite_rules() to refresh permalinks.

This is the only perfect method of doing this as far my knowledge. But there’s a limitation for doing this. As there’s no limit of adding terms, it can conflict with rewrite rules from other plugins. So need to be used carefully.

tech