logo
Ask your WordPress questions! Pay money and get answers fast! (more info)

Warning: Please do not give out any FTP or ssh credentials to anyone, unless you trust them completely. Giving out login details is dangerous.

If the asker does not get an answer then they have 10 days to request a refund.

$50
(Hierarchical) Custom Post Type & Taxonomy Permalinks

Hello!

I've a custom post type 'books', a registered taxonomy 'book_taxonomy' and some trouble with my permalinks:

I'd like my permalinks for the cpt 'books' look like this:

domain.com/baseurl/--> static page with custom template
domain.com/baseurl/[book genre]/[book name]/ --> book-article
domain.com/baseurl/[book genre]/ --> archive of all book-articles matching 'book genre'


The Cherry on the cake would be a support of hierarchical taxonomies. E.g.:

domain.com/baseurl/[book genre]/[book sub genre]/[book name]/ --> book-article
domain.com/baseurl/[book genre]/[book sub genre]/[...]/[book name]/ --> book-article


After 'some' unsuccessful trial and error attempts based on snippets and tutorials I found on the web, I would be very thankfull for your help:-)

I think the only PHP you can use from my attempts, is this:
	add_action('init', 'post_type_books');
function post_type_books() {
register_post_type('books',
array(
'labels' => array('name' => __('Books')),
'public' => true,
'capability_type' => 'post',
'has_archive' => true,
'hierarchical' => false,
'query_var' => true,
'rewrite' => array('with_front'=>false)
)
);
}

add_action( 'init', 'taxonomy_books', 0 );
function taxonomy_books() {
register_taxonomy ('book_taxonomy',array('books'),
array(
'labels' => array('name' => __('Genre')),
'show_ui' => true,
'hierarchical' => true,
'query_var' => true,
'rewrite' => false

)
);
}


Supplement: Well, I've forgot to say that I'm not looking for a plugin-based solution... I'd like to "hardcode" it to my functions.php :-)

This question has been answered.

mark | 06/16/12 at 2:45pm Edit

Previous versions of this question: 06/16/12 at 2:50pm | 06/16/12 at 9:50pm

The experts have suggested, on average, a prize of $87 for this question.

(2) Possible Answers Submitted...

See a chronological view of answers?

Warning: Please do not give out any FTP or ssh credentials to anyone, unless you trust them completely. Giving out login details is dangerous.

  • avatar
    Last edited:
    06/16/12
    2:55pm
    Arnav Joy says:

    try this

    	add_action('init', 'post_type_books');

    function post_type_books() {

    register_post_type('books',

    array(

    'labels' => array('name' => __('Books')),

    'public' => true,

    'capability_type' => 'post',

    'has_archive' => true,

    'hierarchical' => false,

    'query_var' => true,

    'rewrite' => array('with_front'=>false)

    )

    );

    }



    add_action( 'init', 'taxonomy_books', 0 );

    function taxonomy_books() {

    register_taxonomy ('book_taxonomy',array('books'),

    array(

    'labels' => array('name' => __('Genre')),

    'show_ui' => true,

    'hierarchical' => true,

    'query_var' => true,

    'rewrite' => true



    )

    );

    }

    • 06/16/12 3:06pm

      mark says:

      Well, no: that doesn't have any effect... I think it's not that simple:-(
      I'm sure we'll have to add a filter with some new rewrite rules for the cpt. But I don't know how this filter should look like...

    • 06/16/12 3:09pm

      Arnav Joy says:

      write this after the above code in functions.php

      flush_rewrite_rules();

    • 06/16/12 3:15pm

      Arnav Joy says:

      or try this

      function my_em_rewrite_flush(){

      global $wp_rewrite;

      $wp_rewrite->flush_rules();

      }

      add_action('init','my_em_rewrite_flush');

    • 06/16/12 3:22pm

      Arnav Joy says:

      try this

      add_action( 'init', 'taxonomy_books', 0 );

      function taxonomy_books() {

      register_taxonomy ('book_taxonomy',array('books'),

      array(

      'labels' => array('name' => __('Genre')),

      'show_ui' => true,

      'hierarchical' => true,

      'query_var' => true,

      'rewrite' => array( 'slug' => 'books/type' ),



      )

      );

      }

    • 06/16/12 3:28pm

      Arnav Joy says:

      you can check this plugin

      http://wordpress.org/extend/plugins/permalinks-for-hierarchical-custom-post-types/

    • 06/16/12 4:25pm

      mark says:

      Hey Arnav,

      thanks for your help, but I think this isn't the way we'll get it to work :-) I'm quite sure we'll HAVE to set up and add some specific rewrite rules.
      Somthink like this or maybe not:


      global $wp_rewrite;
      $book_structure = '/mybooks/%book_taxonomy%/%books%';
      $wp_rewrite->add_rewrite_tag("%books%", '([^/]+)', "books=");
      $wp_rewrite->add_permastruct('books', $book_structure, false);


      And we'll have to add a filter to translate the permalink tags. Somthink like that could be found here:
      http://shibashake.com/wordpress-theme/custom-post-type-permalinks-part-2
      But as I said: I already worked on an trial and error 'method' on this for 'some' hours and couldn't get it working.


      Flushing the rules without defining new ones can not have any effect - am I wrong?

      BTW, another question: Is there any difference between
      flush_rewrite_rules();
      and

      function my_em_rewrite_flush(){
      global $wp_rewrite;
      $wp_rewrite->flush_rules();
      }
      add_action('init','my_em_rewrite_flush');
      ? In the past I've only used the first one...


      Plugin: As I wrote, I'm not looking for a plugin-based solution... I realy NEED to hardcode the rules into my functions.php :-/


  • avatar
    Last edited:
    06/16/12
    3:43pm
    Daniel Yoen says:

    try this plugin :

    http://wordpress.org/extend/plugins/custom-post-type-ui/

    hope this help :)

    • 06/16/12 8:19pm

      Daniel Yoen says:

      try this :

      <?php
      function swi_post_type_books()
      {
      register_post_type('books', array(
      'labels' => array(
      'name' => __('Books')
      ),
      'public' => true,
      'capability_type' => 'post',
      'has_archive' => true,
      'hierarchical' => false,
      'query_var' => true,
      'publicly_queryable' => true,
      'query_var' => true,
      'rewrite' => false
      ));
      register_taxonomy('books_taxonomy', array(
      'books'
      ), array(
      'labels' => array(
      'name' => __('Genre')
      ),
      'show_ui' => true,
      'hierarchical' => true,
      'query_var' => true,
      'rewrite' => false
      ));
      }
      function swi_custom_rewrite_post_type()
      {
      global $wp_rewrite;

      add_rewrite_tag('%books_cat%', '([^/]+)');
      add_rewrite_tag('%books_subcat%', '([^/]+)');
      $books_structure = '/mybooks/%books_cat%/%books_subcat%/%books%';
      $wp_rewrite->add_rewrite_tag("%books%", '([^/]+)', "books=");
      $wp_rewrite->add_permastruct('books', $books_structure, false);
      }
      function swi_books_permalink($permalink, $post_id, $leavename)
      {
      $post = get_post($post_id);
      $rewritecode = array(
      '%year%',
      '%monthnum%',
      '%day%',
      '%hour%',
      '%minute%',
      '%second%',
      $leavename ? '' : '%postname%',
      '%post_id%',
      '%category%',
      '%author%',
      $leavename ? '' : '%pagename%',
      '%books_cat%',
      '%books_subcat%'
      );
      if ('' != $permalink && !in_array($post->post_status, array(
      'draft',
      'pending',
      'auto-draft'
      )))
      {
      $unixtime = strtotime($post->post_date);
      $category = '';
      if (strpos($permalink, '%category%') !== false)
      {
      $cats = get_the_category($post->ID);
      if ($cats)
      {
      usort($cats, '_usort_terms_by_ID');
      $category = $cats[0]->slug;
      if ($parent = $cats[0]->parent)
      $category = get_category_parents($parent, false, '/', true) . $category;
      }
      if (empty($category))
      {
      $default_category = get_category(get_option('default_category'));
      $category = is_wp_error($default_category) ? '' : $default_category->slug;
      }
      }
      $post_type = $post->post_type;
      $books_cat = '';
      $cat_parent = '';
      if (strpos($permalink, '%books_cat') !== false)
      {
      $terms = wp_get_object_terms($post->ID, 'books_taxonomy');
      if (!is_wp_error($terms) && !empty($terms))
      {
      foreach ($terms as $term)
      {
      if ($term->parent == 0)
      {
      $books_cat = $term->slug;
      $cat_parent = $term->term_id;
      break;
      }
      }
      }
      }
      $books_subcat = '';
      if (strpos($permalink, '%books_subcat%') !== false && !empty($cat_parent))
      {
      foreach ($terms as $term)
      {
      if ($term->parent == $cat_parent)
      {
      $books_subcat = $term->slug;
      break;
      }
      }
      }
      $author = '';
      if (strpos($permalink, '%author%') !== false)
      {
      $authordata = get_userdata($post->post_author);
      $author = $authordata->user_nicename;
      }
      $date = explode(" ", date('Y m d H i s', $unixtime));
      $rewritereplace = array(
      $date[0],
      $date[1],
      $date[2],
      $date[3],
      $date[4],
      $date[5],
      $post->post_name,
      $post->ID,
      $category,
      $author,
      $post->post_name,
      $books_cat,
      $books_subcat
      );
      $permalink = str_replace($rewritecode, $rewritereplace, $permalink);
      }
      else
      {
      }
      return $permalink;
      }
      add_action('init', 'swi_post_type_books');
      add_action('init', 'swi_custom_rewrite_post_type');
      add_filter('post_type_link', 'swi_books_permalink', 10, 3);
      ?>

      hope this help :)

    • 06/16/12 8:20pm

      Daniel Yoen says:

      same code, better looks. :)

    • 06/16/12 8:25pm

      Daniel Yoen says:

      Sorry.


      <?php
      function swi_post_type_books()
      {
      register_post_type('books', array(
      'labels' => array(
      'name' => __('Books')
      ),
      'public' => true,
      'capability_type' => 'post',
      'has_archive' => true,
      'hierarchical' => false,
      'query_var' => true,
      'publicly_queryable' => true,
      'query_var' => true,
      'rewrite' => false
      ));
      register_taxonomy('books_taxonomy', array(
      'books'
      ), array(
      'labels' => array(
      'name' => __('Genre')
      ),
      'show_ui' => true,
      'hierarchical' => true,
      'query_var' => true,
      'rewrite' => false
      ));
      }
      function swi_custom_rewrite_post_type()
      {
      global $wp_rewrite;

      add_rewrite_tag('%books_cat%', '([^/]+)');
      add_rewrite_tag('%books_subcat%', '([^/]+)');
      $books_structure = '/mybooks/%books_cat%/%books_subcat%/%books%';
      $wp_rewrite->add_rewrite_tag("%books%", '([^/]+)', "books=");
      $wp_rewrite->add_permastruct('books', $books_structure, false);
      }
      function swi_books_permalink($permalink, $post_id, $leavename)
      {
      $post = get_post($post_id);
      $rewritecode = array(
      '%year%',
      '%monthnum%',
      '%day%',
      '%hour%',
      '%minute%',
      '%second%',
      $leavename ? '' : '%postname%',
      '%post_id%',
      '%category%',
      '%author%',
      $leavename ? '' : '%pagename%',
      '%books_cat%',
      '%books_subcat%'
      );
      if ('' != $permalink && !in_array($post->post_status, array(
      'draft',
      'pending',
      'auto-draft'
      )))
      {
      $unixtime = strtotime($post->post_date);
      $category = '';
      if (strpos($permalink, '%category%') !== false)
      {
      $cats = get_the_category($post->ID);
      if ($cats)
      {
      usort($cats, '_usort_terms_by_ID');
      $category = $cats[0]->slug;
      if ($parent = $cats[0]->parent)
      $category = get_category_parents($parent, false, '/', true) . $category;
      }
      if (empty($category))
      {
      $default_category = get_category(get_option('default_category'));
      $category = is_wp_error($default_category) ? '' : $default_category->slug;
      }
      }
      $post_type = $post->post_type;
      $books_cat = '';
      $cat_parent = '';
      if (strpos($permalink, '%books_cat') !== false)
      {
      $terms = wp_get_object_terms($post->ID, 'books_taxonomy');
      if (!is_wp_error($terms) && !empty($terms))
      {
      foreach ($terms as $term)
      {
      if ($term->parent == 0)
      {
      $books_cat = $term->slug;
      $cat_parent = $term->term_id;
      break;
      }
      }
      }
      }
      $books_subcat = '';
      if (strpos($permalink, '%books_subcat%') !== false && !empty($cat_parent))
      {
      foreach ($terms as $term)
      {
      if ($term->parent == $cat_parent)
      {
      $books_subcat = $term->slug;
      break;
      }
      }
      }
      $author = '';
      if (strpos($permalink, '%author%') !== false)
      {
      $authordata = get_userdata($post->post_author);
      $author = $authordata->user_nicename;
      }
      $date = explode(" ", date('Y m d H i s', $unixtime));
      $rewritereplace = array(
      $date[0],
      $date[1],
      $date[2],
      $date[3],
      $date[4],
      $date[5],
      $post->post_name,
      $post->ID,
      $category,
      $author,
      $post->post_name,
      $books_cat,
      $books_subcat
      );
      $permalink = str_replace($rewritecode, $rewritereplace, $permalink);
      }
      else
      {
      }
      return $permalink;
      }
      add_action('init', 'swi_post_type_books');
      add_action('init', 'swi_custom_rewrite_post_type');
      add_filter('post_type_link', 'swi_books_permalink', 10, 3);
      ?>

    • 06/16/12 9:49pm

      mark says:

      Hey Daniel,

      Wow, what a monster*... and a realy good start! :-) :-) :-)
      - this code works perfectly for cpt posts with extactly two selected hierachical (sub)categories :-)

      but...
      - it doesn't work if only a maincategory is selected (or the category-depth is deeper then 2)
      - it doesn't show archive-pages for links like

      domain.com/mybooks/[book genre]/ --> archive of all book-articles matching 'book genre'

      Any Ideas how we can achieve that? This last point is very important for me. Currently the homepage shows up when requesting an URL like "mysite.com/mybooks/sciencefiction/", but I'd like to see an achive-page of all scifi-books (shown by the matching template 'achive-books.php')


      *) I removed all the unnecessary code and 'slimmed' it a little bit (still works like the code above):
      	function swi_post_type_books(){
      register_post_type('books', array(
      'labels' => array(
      'name' => __('Books')
      ),
      'public' => true,
      'capability_type' => 'post',
      'has_archive' => true,
      'hierarchical' => false,
      'query_var' => true,
      'publicly_queryable' => true,
      'query_var' => true,
      'rewrite' => false
      )
      );

      register_taxonomy('books_taxonomy', array('books'),
      array(
      'labels' => array(
      'name' => __('Genre')
      ),
      'show_ui' => true,
      'hierarchical' => true,
      'query_var' => true,
      'rewrite' => false
      )
      );
      }

      function swi_custom_rewrite_post_type(){
      global $wp_rewrite;
      add_rewrite_tag('%books_cat%', '([^/]+)');
      add_rewrite_tag('%books_subcat%', '([^/]+)');
      $books_structure = '/mybooks/%books_cat%/%books_subcat%/%books%';
      $wp_rewrite->add_rewrite_tag("%books%", '([^/]+)', "books=");
      $wp_rewrite->add_permastruct('books', $books_structure, false);
      }


      function swi_books_permalink($permalink, $post_id, $leavename){
      $post = get_post($post_id);

      $rewritecode = array(
      '%books_cat%',
      '%books_subcat%'
      );

      if ('' != $permalink && !in_array($post->post_status, array('draft','pending','auto-draft'))){
      $books_cat = '';
      $cat_parent = '';

      if (strpos($permalink, '%books_cat') !== false){
      $terms = wp_get_object_terms($post->ID, 'books_taxonomy');
      if (!is_wp_error($terms) && !empty($terms)) {
      foreach ($terms as $term){
      if ($term->parent == 0) {
      $books_cat = $term->slug;
      $cat_parent = $term->term_id;
      break;
      }
      }
      }
      }

      $books_subcat = '';
      if (strpos($permalink, '%books_subcat%') !== false && !empty($cat_parent)){
      foreach ($terms as $term){
      if ($term->parent == $cat_parent){
      $books_subcat = $term->slug;
      break;
      }
      }
      }

      $rewritereplace = array(
      $books_cat,
      $books_subcat
      );

      $permalink = str_replace($rewritecode, $rewritereplace, $permalink);

      }

      return $permalink;
      }

      add_action('init', 'swi_post_type_books');
      add_action('init', 'swi_custom_rewrite_post_type');
      add_filter('post_type_link', 'swi_books_permalink', 10, 3);


      I'll have to say: I had no idea that all this might be that complicated! :)

    • 06/17/12 9:56am

      Daniel Yoen says:

      Hello, Try this :)

      <?php
      function swi_post_type_books()
      {
      register_post_type('books', array(
      'labels' => array(
      'name' => __('Books')
      ),
      'public' => true,
      'capability_type' => 'post',
      'has_archive' => true,
      'hierarchical' => true,
      'query_var' => true,
      'publicly_queryable' => true,
      'query_var' => true,
      'rewrite' => array('slug' => '/mybooks/%cat%/%subcat%', 'with_front' => true)
      ));
      register_taxonomy('mybooks', array('books'
      ), array(
      'labels' => array(
      'name' => __('Genre')
      ),
      'show_ui' => true,
      'hierarchical' => true,
      'query_var' => true,
      'rewrite' => true
      ));

      global $wp_rewrite;

      add_rewrite_tag('%cat%', '([^/]+)');
      add_rewrite_tag('%subcat%', '([^/]+)');
      add_rewrite_tag("%books%", '([^/]+)', "books=");
      $wp_rewrite->add_permastruct('books', '/mybooks/%cat%/%subcat%/%books%', false);
      }
      add_action('init', 'swi_post_type_books');

      function swi_books_permalink($permalink, $post_id, $leavename)
      {
      $post = get_post($post_id);
      $rewritecode = array('%cat%', '%subcat%');
      if ('' != $permalink && !in_array($post->post_status, array('draft', 'pending', 'auto-draft')))
      {
      $post_type = $post->post_type;
      $cat = '';
      $cat_parent = '';
      if (strpos($permalink, '%cat%') !== false)
      {
      $terms = wp_get_object_terms($post->ID, 'mybooks');
      if (!is_wp_error($terms) && !empty($terms))
      {
      foreach ($terms as $term)
      {
      if ($term->parent == 0)
      {
      $cat = $term->slug;
      $cat_parent = $term->term_id;
      break;
      }
      }
      }
      }
      $subcat = '';
      if (strpos($permalink, '%subcat%') !== false && !empty($cat_parent))
      {
      foreach ($terms as $term)
      {
      if ($term->parent == $cat_parent)
      {
      $subcat = $term->slug;
      break;
      }
      }
      }
      $rewritereplace = array($cat, $subcat);
      $permalink = str_replace($rewritecode, $rewritereplace, $permalink);
      }
      else
      {
      }
      return $permalink;
      }
      add_filter('post_type_link', 'swi_books_permalink', 10, 3);

      function swi_rewrite_flush()
      {
      global $wp_rewrite;
      $wp_rewrite->flush_rules();
      }
      add_action('init','swi_rewrite_flush');
      ?>


      Hope this help :)

    • 06/17/12 2:44pm

      mark says:

      Hey Daniel,
      sorry to say, but: no effect :-/

      The code isn't able to "decide" whether to call an archive OR an post...

      As I read the php the book-permalink structure is still "static" (/mybooks/%cat%/%subcat%). So it works only if exactly 2 hierachical categories are selected:-(

      I think we need somthing more flexible, maybe something completly different?

      Hm...

    • 06/17/12 2:49pm

      Daniel Yoen says:

      I've tested it and succeeded in wordpress 3.4

      /mybooks/%cat%/%subcat%/%postname%/ | works
      /mybooks/%cat%/ | works

      In my view. :D

    • 06/17/12 3:56pm

      mark says:

      hey Daniel,

      I just send you an message with the live-example.. it realy doesn't work... :-( and if it would, I would wonder why?
      I can't see a function/ section which could do what I've requested... maybe I'm wrong.. but could you please explain how an archive will be displayed by the code posted above? :-)

      Thanks
      :-))

    • 06/20/12 5:31am

      mark says:

      Hey Daniel,

      thanks again. The new code works fine for me - no sub-(sub...)-categories, but I can live with that at the moment.

      Thanks a lot!
      Mark

This question has expired.



Daniel Yoen had additional discourse to offer.

Hai Bui, Arnav Joy, mark voted on this question.



Current status of this question: Completed



Warning: Please do not give out any FTP or ssh credentials to anyone, unless you trust them completely. Giving out login details is dangerous.

If the asker does not get an answer then they have 10 days to request a refund.