Updating permalink structure using ‘post_link’ filter results in 404 error for posts

I found a solution, and while I’m not convinced it’s the simplest or most performant solution, it does the job. If someone some day takes interest in this and has a cleaner method, I’d love to revisit it. For now, here’s what worked:

In my register_taxonomy function, set the rewrites as such:

'rewrite'             => array(
  'slug'                => 'media-type',
  'hierarchical'        => true,
),

Then, set rewrite rules for posts:

add_action( 'init', 'xx_media_type_rewrite_tag', 10, 0 );

function xx_media_type_rewrite_tag() {
  add_rewrite_tag( '%media_type%', '([^&]+)', 'media-type=" );
  add_rewrite_rule( "^insights/([^/]*)/([^/]*)/([^/]*)/?','index.php?media_type=$matches[1]&media_type=$matches[2]&name=$matches[3]','top' );
  add_rewrite_rule( '^insights/([^/]*)/([^/]*)/?','index.php?media_type=$matches[1]&name=$matches[2]','top' );
}

Then, filter the post link (this the part I’d imagine could look a lot cleaner if I knew what I was doing):

add_filter( 'post_link', 'xx_filter_post_type_link', 10, 2 );

function xx_filter_post_type_link( $link, $post ) {

  if ( false === strpos( $link, '%media_type%') )
    return $link;

  $terms = wp_get_post_terms( $post->ID, 'media-type');

  // set media type; if none is found, provide a default value.
  if ( 0 < count($terms) ) {

    // Get first term in array
    $first_term = $terms[0]->term_id;

    // Create a string to represent hierarchy of terms
    // get_taxonomy_parents() is a custom function that returns a string formatted as `$tax_parent . $separator . $tax_child . $separator` etc.
    $media_type = get_taxonomy_parents( $first_term, 'media-type', false, "https://wordpress.stackexchange.com/", true );

    // Remove everything after second `/` character (we only want to go two levels deep into the tax hierarchy)
    if ( 2 < substr_count( $media_type, "https://wordpress.stackexchange.com/" ) ) {
      $media_type = substr( $media_type, 0, strpos( $media_type, "https://wordpress.stackexchange.com/", strpos( $media_type, "https://wordpress.stackexchange.com/") + 1 ) );
    }

    // Remove trailing slash
    $media_type = trim( $media_type, "https://wordpress.stackexchange.com/" );

  } else {
    // Set default
    $media_type="articles";
  }
  // Encode for URL usage, but preserve slashes
  $media_type = str_replace( '%2F', "https://wordpress.stackexchange.com/" , urlencode($media_type) );

  $link = str_replace( '%media_type%', $media_type , $link );

  return $link;
}