WordPress permalink and redirect made simple

If you are using WordPress inside a company, will come the time to change the permalink structure of your custom posts type (CPT), as request by the SEO department. I said company, because almost nobody will invest so much money for such a thing.

In my case, the request has been to create a structure like /custom_taxonomy/custom_taxonomy_nth_child/custom_post which it’s also reasonable, but can create a lot of problems if you are not aware of how slugs works.

As you should probably know, such standard structure it’s not the default and it’s achievable, without change code, just with posts. Whenever you do not know, you can do that through your Permalinks setting, writing %category%/%postname% inside “Custom Structure”. You can find more information inside the WP codex.

This last hint will help you to understand how can you extend it for your CPT. The whole process is basically done in 2 steps: the first to restructure your permalinks, the second one to make WordPress recognize them.


Step 1: Rewrite tag

Assuming your CPT name or slug is  custom_post , you need to define the tag just like the post and the category above, using %custom_post%.

This will allow you to play around with it as follow:

add_action('init', 'custom_post_rewrite');
function custom_post_rewrite($rewrite) {

  global $wp_rewrite;

  add_rewrite_tag('%custom_post%', '([^/]+)', 'custom_post=');
  add_permastruct('custom_post', '/%category%/%custom_post%', false);


In this way we modify then the  permalink structure (add_permastruct) prefixing with the standard /%category%/ , though it will still not have the whole tree.

The reason we rewrite the rule, it’s because the ugly and original version of the permalink of your CPT would be index.php?custom_post= . You can verify this playing with the settings.

Also remember, you will need to update the permalinks every time you make a modification. To avoid this hassle while developing, you can add at the bottom the line $wp_rewrite->flush_rules() , keeping in mind to remove it at final deployment, since this will trigger at every post submission.


Step 2: Permalinks

Now we have finally defined our tag and made the CPT prefixed automatically by WP by the category. However we still do not have the whole hierarchy, so we’ll need to update again the permalink structurelike this:

function custom_post_permalinks( $permalink, $post ) {
  if ( $post->post_type == 'custom_post' ) {
    if ( $cats = get_the_terms( $post->ID, 'category' ) ) {
        $cat_current = current( $cats );
        $cats_parent = get_category_parents( $cat_current, false, '/', true );
        $cats_parent_fix =  substr($cats_parent, 0, strlen($cats_parent) -1 );
      $permalink = str_replace( '%category%', $cats_parent_fix, $permalink );
    } else {
        return $permalink;
  return $permalink;
add_filter( 'post_type_link', 'custom_post_permalinks', 10, 2 );

In few words, we check if the post is our CPT and has categories, to retrieve the whole tree using / as divider and then replace the whole tag with the whole tree. I’ve added $cats_parent_fix to avoid repetition of our CPT.


Related content:

Version 0.2

Since this is a temporary theme, a “rough” child version of the theme Baskerville which I started for fun, replacing the parts I did not like, I’m updating now to a new version of the theme. If you are inspecting all around, you will notice there’s no use any grid or frontend framework such like … Continued

Editor friendly shortcode: wp.mce.views

One of the coolest features WordPress offers us is the shortcode. They give the possibility to render a complex design with a lot of properties and connect an interface to it to input the values. It also can render an actual template as preview of is final result. The UI can be powered with AJAX … Continued

Everyday Git usage

Taking the chance to work in a team environment with different developers, I’ve faced many times a lack of documentation for everyday Git commands, which personally define mandatory to avoid mess. To be clear, these occurring errors have been dictated by a change of OS which I usually work with, from Windows to Mac OS … Continued

New theme from scratch (with free download)!

Even I still wonder where I found the time to code a new website, through I have no free time at all, I finally accomplished to develop a theme also for me from scratch, using the starter theme Sage (ver 9 cames with bootstrap and needs to be cleaned, duh). The whole to-do list planned … Continued