I have a hierarchical custom post type called “state”. My goal is to have a permalink structure like thus:
http://website.com/idaho/
http://website.com/idaho/sub-page
I’m close but haven’t quite figured it out. Here’s the code I’m using:
First, I remove the slug
public function remove_slugs( $permalink, $post, $leavename ) {
$url_components = parse_url( $permalink );
$post_path = $url_components['path'];
$post_name = end( explode( '/', trim( $post_path, '/' ) ) );
if( !empty( $post_name )) {
switch($post->post_type) {
case 'state':
if( $post->post_parent ) {
$parent = get_post( $post->post_parent );
$parent = $parent->post_name;
$permalink = str_replace( $post_path, '/' . $parent . '/' . $post_name . '/', $permalink );
} else {
$permalink = str_replace( $post_path, '/' . $post_name . '/', $permalink );
}
break;
}
}
return $permalink;
}
This is hooked into post_type_link
.
Next, I reset the query variables so WordPress knows we’re dealing with a CPT
public function parse_custom_post_type( $query ) {
if ( ! $query->is_main_query() ) return;
if ( count( $query->query ) != 2 || ! isset( $query->query['page'] ) ) return;
// Are we dealing with a page?
if ( ! empty( $query->query['pagename'] ) && ! is_home() ) {
// If the page doesn't exist, we must be dealing with a state
if ( ! is_page( $query->query['pagename'] ) ) {
$query->set( 'name', $query->query['pagename'] );
$query->set( 'state', $query->query['pagename'] );
$query->set( 'post_type', 'state' );
$query->is_page = 0;
$query->is_single = 1;
unset( $query->query_vars['page'] );
unset( $query->query_vars['pagename'] );
unset( $query->query['page'] );
unset( $query->query['pagename'] );
}
}
}
This is hooked into it pre_get_posts
.
So, the level one pages work, but not the subpages. The URLs resolve and then hit a 404.
What do I need to do to get this working?
Preface
Two things before I begin:
The Code
If you decide to move forward with this structure, here is a singleton class that should work out of the box for you if your post type has ‘hierarchical’ set to true and ‘rewrite’ set to false. Be sure to flush your rewrites after adding this to your theme’s functions.php file or your plugin (go to Settings → Permalinks and click “Save Changes”).
I thought this topic was interesting and I wrote up a deep explanation of this on my blog. There, I included some slightly more complex code that wasn’t as relevant to your specific question.