Nested CPT URLs + Posts 2 Posts

So after a lot of time spent and a lot of trying different things, I finally figured out the right way to do this. I used MonkeyMan Rewrite Analyzer and the WP Debug Bar to help figure out how to construct the rewrite.

So first, my custom post type URLs are rewritten as such:

// Artist Rewrite Args
$rewrite = array(
  'slug'                => 'artist',
  'with_front'          => true,
  'pages'               => true,
  'feeds'               => true,
);

// Portfolio Rewrite Args
$rewrite = array(
  'slug'                => 'portfolio',
  'with_front'          => false,
  'pages'               => true,
  'feeds'               => true,
);

Then, I register a rewrite tag %artistname% for the artist name, which we’ll grab via a WP_Query function, as well as a rewrite rule to fill in the slug to be occupied by the artist’s name, which will come before the slug of the portfolio being shown.

// Portfolio Rewrite Rule
add_action( 'init', 'portfolio_rewrite_tag' );
function portfolio_rewrite_tag() {

    add_rewrite_tag('%artistname%','[^/]+');
    // defines the rewrite structure for 'portfolios'
    // says that if the portfolio URL matches this rule, then it should display the 'artists' post whose post name matches the last slug set
    add_rewrite_rule( '^artist/[^/]+/([^/]+)/?$','index.php?portfolio=$matches[1]','top' );   
}

Next, I refined the URL filter to check if it’s a portfolio post, and if so, pull the slug of the first connected artist, and then plop that slug into the post link string.

// Grab connected artist name and swap it into the URL
function filter_portfolio_link( $post_link, $post ) {
  if ( $post->post_type === 'portfolio' ) {
    $connected = new WP_query( array(
      'post_type' => 'artist',
      'connected_type' => 'portfolios_to_artists',
      'connected_items' => $post,
      'nopaging' => true,
    ) );
    if ($connected->have_posts() ) {
      $first = true;
      foreach ( $connected as $connectedPost ) {
          setup_postdata($connectedPost);
          if ($connectedPost->post_type === 'artist') {
            if ($first) {
              $artistName = $connectedPost->post_name;
              $first = false;
            }
          }
      }
      $post_link = str_replace( 'portfolio', 'artist/' . $artistName, $post_link );
    }
  }
  return $post_link;
}
add_filter( 'post_type_link', 'filter_portfolio_link', 10, 2);

So that’s it! While I didn’t use the same plugin as discussed in the thread Nested custom post types with permalinks, the whole thread was super helpful in arriving at this conclusion.