0

I've created a custom post type with a rewrite to use the grandparent relationship as the URL like so:

function cpt_child(){
 $args = array(
  //code
  'rewrite' => array( 'slug' => '%grandparent%/%parent%', 'with_front' => false),
 );
 register_post_type( 'child', $args );
}
add_action( 'init', 'cpt_child' );

Then I update the permalink:

add_filter( 'post_type_link', 'filter_the_post_type_link', 1, 2 );
function filter_the_post_type_link( $post_link, $post ) {
  switch( $post->post_type ) {
    case 'child':
            $post_link = get_bloginfo( 'url' );
            $relationship_child = p2p_type('children_to_parents')->get_adjacent_items($post->ID);
            $parent = $relationship['parent']->post_name;
            $relationship_parent = p2p_type('parents_to_grandparents')->get_adjacent_items($parent['parent']->ID);
            $grandparent = $relationship_parent['parent']->post_name;
            $post_link .= "/{$grandparent}/";
            $post_link .= "{$parent}/";
            $post_link .= "{$post->post_name}";
    break;
  }
  return $post_link;
}

This all works great, but unfortunately the rewrite rule matches regular pages as well which makes them 404.

I can prevent this by adding a custom slug, for example 'relationship': http://example.com/relationship/grandparent/parent/child

But I'd really like to use http://example.com/grandparent/parent/child and have it not break regular pages.

Query debugging:

CPT rewrite active and CPT rewrites are working but pages break

Request:

test

Query String:

name=test

Matched Rewrite Rule:

([^/]+)(?:/([0-9]+))?/?$

Matched Rewrite Query:

name=test&page=

CPT rewrite inactive and pages work (normal)

Request:

account-information

Query String:

pagename=account-information

Matched Rewrite Rule:

(.?.+?)(?:/([0-9]+))?/?$

Matched Rewrite Query:

pagename=account-information&page=

Thanks in advance!

2
  • I don't have the time at the moment to write up a working answer, but if you look at some of the rewrite questions that I've answered in the past you might find some helpful bits. basically, you can hook parse_query after the rewrite rules are parsed into query vars and change them to "fix" your custom post type queries.
    – Milo
    Commented Mar 30, 2016 at 2:39
  • Thanks for replying and I'll make sure to look through your past answers. Just to be clear, the CPT rewrite is working great it's just that regular pages are getting caught. This is resulting in the regular pages to 404, for example a page called test http://example.com/test 404's with the CPT rewrite in place.
    – Bram G
    Commented Mar 30, 2016 at 3:28

1 Answer 1

0

I managed to find a solution thanks to Milo's previous answers on other related questions. I found this particular post Remove base slug in CPT & CT, use CT in permalink to be extremely helpful.

My initial CPT with grandparent relationship rewrite remains the same:

function cpt_child(){
 $args = array(
  //code
  'rewrite' => array( 'slug' => '%grandparent%/%parent%', 'with_front' => false),
 );
 register_post_type( 'child', $args );
}
add_action( 'init', 'cpt_child' );

Then I update the permalink:

add_filter( 'post_type_link', 'filter_the_post_type_link', 1, 2 );
function filter_the_post_type_link( $post_link, $post ) {
  switch( $post->post_type ) {
    case 'child':
            $post_link = get_bloginfo( 'url' );
            $relationship_child = p2p_type('children_to_parents')->get_adjacent_items($post->ID);
            $parent = $relationship['parent']->post_name;
            $relationship_parent = p2p_type('parents_to_grandparents')->get_adjacent_items($parent['parent']->ID);
            $grandparent = $relationship_parent['parent']->post_name;
            $post_link .= "/{$grandparent}/";
            $post_link .= "{$parent}/";
            $post_link .= "{$post->post_name}";
    break;
  }
  return $post_link;
}

Hooked into request and changed query based on request vars that match my needs. Added is_admin() check to prevent request filter from changing the CPT's back end.

// URL rewrite pages 404 fix
if ( ! is_admin() ) {
  function svbr_fix_requests( $request ){
    // if it's not a section request and request is not empty treat request as page or post
    if( ( ! array_key_exists( 'section' , $request ) ) && ( ! empty($request) ) ){
            $request['post_type'] = array( 'post', 'page' );
    }

    // return request vars
    return $request;
  }
  add_filter( 'request', 'svbr_fix_requests' );
}

Because we changed the query vars we have to add template functionality.

// Use single_template filter to properly redirect to page.php and custom page templates
function svbr_get_template_file($single_template) {
  global $post;

  $page_custom_template = get_post_meta( $post->ID, '_wp_page_template', true );

  if ($post->post_type == 'page') {
    if($page_custom_template != 'default') {
      // We are using a child theme, so get_stylesheet_directory()
      $single_template = get_stylesheet_directory() . '/' . $page_custom_template;
    }
    else {
      $single_template = get_template_directory() . '/page.php';
    }
  }
  return $single_template;
}
add_filter( 'single_template', 'svbr_get_template_file' );

Last but not least we have to add the template class to the body for styling purposes.

// Add template class to body
add_filter( 'body_class', 'template_class_name' );
function template_class_name( $classes ) {
  global $post;
  $page_custom_template = get_post_meta( $post->ID, '_wp_page_template', true );
  $page_custom_template = str_replace('.php','',$page_custom_template);
  $page_custom_template = 'page-template-' . $page_custom_template;
    // add 'class-name' to the $classes array
    $classes[] = $page_custom_template;
    // return the $classes array
    return $classes;
}

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.