Custom post type taxonomies URL rewrite

What I want to achieve is an online listing catalog with a URL like this:

www.example.com/drawing-tools/brand/type/material/color/

In this example, I have a custom post type named “drawing-tools” with 4 custom taxonomies for it: “brand”, “type”, “material”, “color”

Read More

When a user access a URL like:

www.example.com/drawing-tools/rotring/mechanical-pencil/plastic/black/

it gets all the items that match those criteria.

The tricky part is that all of the taxonomies are required to be in a URL. So something like this:

www.example.com/drawing-tools/plastic/black/

would simply return an 404 error page.

So my main question is:

How exactly can I have all of the taxonomies in the URL in that form and return an 404 error page if one taxonomy is missing?

I was thinking to write a rewrite rule that would take those uri segments and pass them as arguments to a query based on the ‘Query Multiple Taxonomies’ plugin and return that 404 error if one segment is missing. But I don’t know how to accomplish this. Is there any solutions that you can give me?

[Update 1]

The rewrite rule would basically take this URL:

www.example.com/drawing-tools/rotring/mechanical-pencil/plastic/black/

and make it into:

www.example.com/?drawing-tools_name=rotring+mechanical-pencil+plastic+black

The above structure is required by the ‘Query Multiple Taxonomies’ plugin.

[Update 2]

I’ve given up to the Query Multiple Taxonomies plugin and instead I’ve switched to WP 3.1. Now, with the help from this previous question I’ve managed to get to work those taxonomies like I wanted.

Here is the full code:

register_post_type('drawing-tools', array(
    'labels' => array(
            'name' => __( 'Drawing Tools' ),
            'singular_name' => __( 'Drawing Tool' ),
            'add_new' => __( 'Add New' ),
            'add_new_item' => __( 'Add New Drawing Tool' ),
            'edit' => __( 'Edit' ),
            'edit_item' => __( 'Edit Drawing Tool' ),
            'new_item' => __( 'New Drawing Tool' ),
            'view' => __( 'View Drawing Tools' ),
            'view_item' => __( 'View Drawing Tool' ),
            'search_items' => __( 'Search Drawing Tools' ),
            'not_found' => __( 'No items found' ),
            'not_found_in_trash' => __( 'No items found in trash' ),
            'parent' => __( 'Parent Drawing Tool' ),
            ),
    'public' => true,
    'publicly_queryable' => false,
    'show_in_nav_menus' => false,
    'exclude_from_search' => false,
    'show_ui' => true,
    '_builtin' => false,
    '_edit_link' => 'post.php?post=%d',
    'capability_type' => 'post',
    'hierarchical' => false,
    'rewrite' => array("slug" => "drawing-tools/%brand%/%type%/%material%/%color%"), // Permalinks format
    'has_archive' => false,
    'menu_position' => 5,
    'supports' => array('author')
));

  register_taxonomy('brand',array('drawing-tools'), array(
    'hierarchical' => false,
    'labels' => array(
        'name' => _x( 'Brands', 'taxonomy general name' ),
        'singular_name' => _x( 'Brand', 'taxonomy singular name' ),
        'search_items' =>  __( 'Search Brands' ),
        'all_items' => __( 'All Brands' ),
        'parent_item' => __( 'Parent Brand' ),
        'parent_item_colon' => __( 'Parent Brand:' ),
        'edit_item' => __( 'Edit Brands' ), 
        'update_item' => __( 'Update Brand' ),
        'add_new_item' => __( 'Add New Brand' ),
        'new_item_name' => __( 'New Unit Brand' ),
        'menu_name' => __( 'Brands' ),
                ),
    'show_ui' => true,
    'query_var' => true,
    'rewrite' => array( 'slug' => 'drawing-tools' ),
  ));

  register_taxonomy('type',array('drawing-tools'), array(
    'hierarchical' => false,
    'labels' => array(
        'name' => _x( 'Types', 'taxonomy general name' ),
        'singular_name' => _x( 'Type', 'taxonomy singular name' ),
        'search_items' =>  __( 'Search Types' ),
        'all_items' => __( 'All Types' ),
        'parent_item' => __( 'Parent Type' ),
        'parent_item_colon' => __( 'Parent Type:' ),
        'edit_item' => __( 'Edit Types' ), 
        'update_item' => __( 'Update Type' ),
        'add_new_item' => __( 'Add New Type' ),
        'new_item_name' => __( 'New Type' ),
        'menu_name' => __( 'Types' ),
                ),
    'show_ui' => true,
    'query_var' => true,
    'rewrite' => array( 'slug' => 'drawing-tools/%brand%' ),
  ));

 register_taxonomy('material',array('drawing-tools'), array(
    'hierarchical' => false,
    'labels' => array(
        'name' => _x( 'Materials', 'taxonomy general name' ),
            'singular_name' => _x( 'Material', 'taxonomy singular name' ),
        'search_items' =>  __( 'Search Materials' ),
        'all_items' => __( 'All Materials' ),
        'parent_item' => __( 'Parent Material' ),
        'parent_item_colon' => __( 'Parent Material:' ),
        'edit_item' => __( 'Edit Material' ), 
        'update_item' => __( 'Update Material' ),
        'add_new_item' => __( 'Add New Material' ),
        'new_item_name' => __( 'New Material Name' ),
        'menu_name' => __( 'Materials' ),
                ),
    'show_ui' => true,
    'query_var' => true,
    'rewrite' => array( 'slug' => 'drawing-tools/%brand%/%type%' ),
  ));

 register_taxonomy('color',array('drawing-tools'), array(
    'hierarchical' => false,
    'labels' => array(
        'name' => _x( 'Colors', 'taxonomy general name' ),
        'singular_name' => _x( 'Color', 'taxonomy singular name' ),
        'search_items' =>  __( 'Search Colors' ),
        'all_items' => __( 'All Colors' ),
        'parent_item' => __( 'Parent Color' ),
        'parent_item_colon' => __( 'Parent Color:' ),
        'edit_item' => __( 'Edit Color' ), 
        'update_item' => __( 'Update Color' ),
        'add_new_item' => __( 'Add New Color' ),
        'new_item_name' => __( 'New Color Name' ),
        'menu_name' => __( 'Colors' ),
                ),
    'show_ui' => true,
    'query_var' => true,
    'rewrite' => array( 'slug' => 'drawing-tools/%brand%/%type%/%material%' ),
  ));  


function filter_post_type_link($link, $post)
{
    if ($post->post_type != 'drawing-tools')
        return $link;

    if ($cats = get_the_terms($post->ID, 'brand'))
        $link = str_replace('%brand%', array_pop($cats)->slug, $link);

    if ($cats = get_the_terms($post->ID, 'type'))
        $link = str_replace('%type%', array_pop($cats)->slug, $link);

    if ($cats = get_the_terms($post->ID, 'material'))
        $link = str_replace('%material%', array_pop($cats)->slug, $link);

    if ($cats = get_the_terms($post->ID, 'color'))
        $link = str_replace('%color%', array_pop($cats)->slug, $link);      
    return $link;
}

add_filter('post_type_link', 'filter_post_type_link', 10, 2);

Now, when a user access the link:

www.example.com/drawing-tools/rotring/mechanical-pencil/plastic/black/

everything works as expected. The problem is that the user can also access a partial structure like this

www.example.com/drawing-tools/rotring/

and still get results according to those taxonomies.

How can I restrict a user from accessing such a URL and instead returning a 404 error message?

Related posts

Leave a Reply

2 comments

  1. I believe WP 3.1 introduced a fix for what you’re describing… from the codex:

    • Custom Content Type Improvements – allows developers to generate archive pages, and have better menu and capability controls. Read more in the article Post Types.
    • Advanced Queries – allows developers to query multiple taxonomies and custom fields

    I haven’t used either of these improvements yet so I can’t comment specifically, but it seems like that’s what you’re looking for. Good luck!

  2. The solution is fairly simple and I don’t know why it took me so long to find it on the Codex. You must make use of the $wp_query class.

    So, in the template, before calling the loop, set a variable to hold the returned data:

    $vars = $wp_query->query_vars;
    

    And then, check if the required taxonomies are set:

    if ( isset( $vars['brand']) && isset( $vars['type'] ) && isset( $vars['material'] ) && isset( $vars['size'] ) )
    

    If they are continue with the loop. If not:

    global $wp_query; 
    status_header('404');
    $wp_query->set_404();
    

    I wonder, though, if this is the most optimum solution.