0

I am trying to modify the permalink structure of the default post type post to include custom taxonomy terms. Here's my function and filter:

/**
 * Add media type slug to URL structure for posts
 */
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
    $media_type = get_taxonomy_parents( $first_term, 'media-type', false, '/', true );
    // Remove trailing slash
    $media_type = trim( $media_type, '/' );
  } else {
    $media_type = 'articles';
  }
  $media_type = urlencode($media_type);
  $media_type = str_replace( '%2F', '/' , $media_type );
  $link = str_replace( '%media_type%', $media_type , $link );

  return $link;
}

In Settings > Permalinks I am using a custom structure of /insights/%media_type%/%postname%/.

The post URL is formatted correctly after resetting permalinks, but when I navigate to the link I get a 404 page. Sad panda.

How am I being a dummy and how should I be smarter so this works?

EDIT: After reading a bit of the codex, I realized that I forgot to add the rewrite rule. That said, I'm still missing something. I updated the function above ever so slightly and I set hierarchical to true in the rewrite property when I registered the taxonomy. Now my posts work fine unless they are assigned to multiple taxonomy terms in the hierarchy (for example, xx.com/insights/parent/post works, but xx.com/insights/parent/child/poststill gives me a 404). My regex skills are pretty weak, so wonder if I'm missing something there to account for the hierarchy.

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]&name=$matches[2]','top' );
}
  • 1
    Did you add media_type to the list of query vars? – Milo Oct 4 '17 at 3:32
  • I did not. After reading through the codex and a few samples, I modified my function a bit: – Chance Strickland Oct 4 '17 at 21:13
  • @Milo See above for my modified filter function and where I set media_type as an acceptable query var. I feel like I'm really close here. – Chance Strickland Oct 4 '17 at 21:54
0

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, '/', true );

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

    // Remove trailing slash
    $media_type = trim( $media_type, '/' );

  } else {
    // Set default
    $media_type = 'articles';
  }
  // Encode for URL usage, but preserve slashes
  $media_type = str_replace( '%2F', '/' , urlencode($media_type) );

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

  return $link;
}
|improve this answer|||||

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.