Can’t get custom rewrite tag, query var, permastruct (permalink structure), and rewrite rule to work properly together

I’m implementing a website that is meant to host podcast shownotes and transcripts, and so I want custom permalinks and shortlinks for the webpages:

Ideally, partial or “incorrect” URLs that unambiguously match the permalink structure should redirect to the corresponding podcast permalink, e.g. the following should redirect to /podcasts/12/news-for-august:

We use a custom post type for podcasts, created using CPT UI. The value of <episode_number> is stored in an ACF field with meta key episode_number; if multiple published podcasts have the same episode number (which obviously shouldn’t happen in practice), then the one with the lowest post ID is served. The value of <episode_title> is just the post slug, since the podcast post’s title holds the actual episode title (e.g. News for August).

As a (perhaps important?) sidenote, I’m using Nginx, not Apache — I see a lot of mention of .htaccess modification, which obviously doesn’t apply here, so just mentioning that.

I’ve read up on the Rewrite API, and here’s where I’ve got to after a couple days trying to understand the relevant inner workings…

When CPT UI registers the custom post type podcast, it also adds a permastruct with the name podcast. Since my permastruct for posts (set in [Settings > Permalinks > Custom Structure]) is /articles/%post_id%/%postname%, the podcast permastruct is /articles/podcast/%postname%. In CPT UI, I can disable “With front” (so that the leading /articles is dropped) and set “Rewrite slug” to podcasts (plural) rather than the default podcast (singular), which results in permalinks of the form /podcasts/<episode_title> instead. If I can’t achieve what I want, I’ll probably have to settle for this.

I define a rewrite tag, %podcast_episode_number%, so that I can define my custom permastruct for podcasts. I just override the permastruct with the name podcast that CPT UI added, so it automatically applies to podcasts. I also define a rewrite rule to handle the shortlinks. Here is the relevant section from my theme’s functions.php:

I then define how %podcast_episode_number% should be populated in permalinks by hooking into the post_link and post_type_link filters. Strangely, in the context of podcast permalinks, the %postname% tag isn’t being populated like it is for regular blog posts, so I do that here as well:

Finally, I define how the query variable podcast_episode_number (which corresponds to the tag %podcast_episode_number%, and is implicitly registered when add_rewrite_tag() is called) should be handled, so that when we visit one of the URLs described in our problem specification, WordPress can use the podcast_episode_number parameter to determine the corresponding post ID, and thus serve the post. We hook into the request filter to do this.

After all that, and flushing the rewrite rules via [Settings > Permalinks > Save Settings], the link structures work! That is, for example, the web server responds to requests for all of the following URLs with a 301 redirect to /podcasts/12/news-for-august:

However, the page itself (/podcasts/12/news-for-august) cannot be found by WordPress… WordPress serves my theme’s 404 template (404.php) and the HTTP response is 404, just like any other Not Found URL. Clearly, this is because WordPress doesn’t know what template to use. I can resolve this by returning the post type as well as the post ID in handle_query_var() (i.e. return [ 'p' => $post_ids[0], 'post_type' => 'podcast' ]), but this has the undesirable effect of making all of the alias URLs listed above also just serve the content rather the redirecting to the permalink — this is obviously horrendous for SEO.

So what gives? How can I get the correct template to load when the client visits a podcast permalink, without other URLs serving the same content? Perhaps hook into template_redirect or use wp_redirect() or something else? Maybe my overall approach here is wrong and someone can point me in the right direction?

Any advice is much appreciated.