I'm working on a project with several custom post types, where one of the post types is naturally (but not actually in the WordPress sense) the 'parent' of the others. For example, say I have a custom post type called 'book' and another one called 'character', and say I want to have the following custom URL structure:


Thus, the canonical URL for the post about the character Thing One in the book The Cat In the Hat would be:


A character is associated with a book with a post meta row.

I've created custom rewrites to make it work...

add_rewrite_rule (

...but I'd also need to make sure that the 'character post' in the URL belongs to the 'book'...

books/cat-in-the-hat/characters/thing-one     //good
books/anna-karenina/characters/count-vronsky  //good
books/anna-karenina/characters/thing-one      //bad

This can't happen automatically: I have to hook into a filter or an action to check whether the character matches the book, and if not, either redirect to the correct, canonical URL or force a 404.

Where's the best place to accomplish this check? My choices (so far) are:

  • The request filter -- i.e. checking before the main query is instantiated.
  • The various WP_Query filters -- i.e. make WP_Query do the checking for me by adding a post meta constraint.

I realize this is rather an open-ended question and probably a matter of taste, but any insight into the most code and database efficient way of doing things would be appreciated. Thanks.

  • How do you link the charater to the book internally? via a taxonomy? Sep 23, 2013 at 17:03
  • It sounds like @ChrisCarson said post meta row which I can only assume when the user creates a new book, they somehow find / pick the character(s) attached to it, which is then saved as meta values attached to the book post ID. That being said, I am confused with OPs final example - the last url being bad assumes that 2 different books cannot have the same character names.
    – Howdy_McGee
    Mar 20, 2014 at 22:01

1 Answer 1


I tackled subordinate post types with a similar vein but was not as strict on the canonical url aspect; however, I ran into a similar situation with deeplinking custom WooCommerce product type links.

I leveraged the template_redirect hook to push a 404 if it didn't match the route and the post_type_link to ensure the meta tag for canonical link and all the_permalink() and get_permalink() references matched the intended link.

A snippit of the way I would recommend handling this:

add_action( 'template_redirect', 'wp20140320_template_redirect' );
public function wp20140320_template_redirect(){
    global $wp_query, $post;

    // the character post type has the book id set as meta?
    // or could set as post_parent if you don't have characters heirarchical
    $book_id = get_post_meta( $post->ID, '_book_id', true );

    // compare_parent_slug_to_id to check required $book_id against set parent book slug
    if( $post->post_type == 'character' && ! compare_parent_slug_to_id( $book_id ) ){

        // set is_404 since post type is character and parent slug does not match set
        $wp_query->is_404 = true;
        include get_404_template();
        exit; // maybe a better way to gracefully exit?


Modified from source

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

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