Select Page

Custom Post Types in WordPress 3.x are designed to work from the root of your website i.e. a flat hierarchy.

What if you needed to set a particular page or post in your website as the parent to your new custom post types?

Here’s a solution for that.

Custom Post Types

In a recent project we created a “Case Study” custom post type and added several new case study posts to our WordPress site.

We also created a page template called “Case Studies” that listed the new custom post types.

Everything was rumbling along just super until we noticed, when viewing our new custom post types, the breadcrumb trail and URL permalink weren’t including the Case Studies page that we had clicked through from.

For example.

Our Case Studies page URL was /case-studies/ and the breadcrumb trail was also /case-studies/

When clicking on a case study custom post type “Land Owners”, both the URL and breadcrumb trail changed to “/land-owners/”.

Where had the Case Studies page gone in the hierarchy?

Let me be clear, this is not a WordPress bug but rather the way custom post types are currently implemented.  And yes, it is very annoying.

WordPress assumes that all custom post types are at the top of the hierarchy. i.e. they have no associated parent.

Unfortunately, this is exactly what we weren’t looking for.

The Solution

Of course WordPress may change the way custom post types work in future versions but here’s a fix for now.

We’re going to create a meta box for the custom post type that allows us to enter the ID of a page or post and associate that with the post_parent variable, effectively making that ID our parent page.

We’re using the custom post type called “casestudy” here so change that value to your own custom post type name and copy the following into your functions.php file.

[code lang=”php”]
//Add the meta box callback function
function admin_init(){
add_meta_box(“case_study_parent_id”, “Case Study Parent ID”, “set_case_study_parent_id”, “casestudy”, “normal”, “low”);
add_action(“admin_init”, “admin_init”);

//Meta box for setting the parent ID
function set_case_study_parent_id() {
global $post;
$custom = get_post_custom($post->ID);
$parent_id = $custom[‘parent_id’][0];
<p>Please specify the ID of the page or post to be a parent to this Case Study.</p>
<p>Leave blank for no heirarchy.  Case studies will appear from the server root with no assocaited parent page or post.</p>
<input type=”text” id=”parent_id” name=”parent_id” value=”<?php echo $post->post_parent; ?>” />
// create a custom nonce for submit verification later
echo ‘<input type=”hidden” name=”parent_id_noncename” value=”’ . wp_create_nonce(__FILE__) . ‘” />’;

// Save the meta data
function save_case_study_parent_id($post_id) {
global $post;

// make sure data came from our meta box
if (!wp_verify_nonce($_POST[‘parent_id_noncename’],__FILE__)) return $post_id;
if(isset($_POST[‘parent_id’]) && ($_POST[‘post_type’] == “casestudy”)) {
$data = $_POST[‘parent_id’];
update_post_meta($post_id, ‘parent_id’, $data);
add_action(“save_post”, “save_case_study_parent_id”);

There are three functions here.

  1. function admin_init() – This initialises the meta box for our casestudy custom post type, pointing to the call-back function that creates it
  2. function set_case_study_parent_id() – This is the call-back function that contains the HTML code needed to create the meta box on the casestudy custom post type when in edit mode
  3. function save_case_study_parent_id() – This saves the meta data from the new box into the DB

This will give you the following new meta box on your custom post type, allowing you to enter the ID of a page or post which it will set as the parent document.

We set the meta box value to the ID of our “Case Studies” page which displayed all the custom post types.

Great, now our Yoast breadcrumb trail was picking up the Case Studies parent page from our custom post type, but what about the URL?

There was just one thing left to do to bring everything together.

No slug had been explicitly defined for the custom post type, so they were being displayed in the URL from the server root with just the post title i.e. “/land-owners/”.

We needed to define a slug that would match up with our Case Studies page (slug “case-study”) so that our URL would read “/case-studies/land-owners/”.

Going back into the function that registered our custom post type, we added the following line to the $args array:

[code lang=”php”]’rewrite’ => array(‘slug’ => ‘case-studies’, ‘with_front’ => true)[/code]

This rewrites the URL slug from the server root to include “case-studies” in front of the post title.

Just for reference, here’s the complete custom post type registration function with the above line included.

[code lang=”php”]/* Custom Post Types */
function register_custom_post_case_study() {

$labels = array(
‘name’ => _x(‘Case Studies’, ‘post type general name’),
‘singular_name’ => _x(‘Case Study’, ‘post type singular name’),
‘add_new’ => _x(‘Add New’, ‘Case Study’),
‘add_new_item’ => __(‘Add New Case Study’),
‘edit_item’ => __(‘Edit Case Study’),
‘new_item’ => __(‘New Case Study’),
‘view_item’ => __(‘View Case Study’),
‘search_items’ => __(‘Search Case Studies’),
‘not_found’ =>  __(‘No Case Studies found’),
‘not_found_in_trash’ => __(‘No Case Studies found in Trash’),
‘parent_item_colon’ => ”

$args = array(
‘labels’ => $labels,
‘public’ => true,
‘publicly_queryable’ => true,
‘show_ui’ => true,
‘query_var’ => true,
‘rewrite’ => array(‘slug’ => ‘case-studies’, ‘with_front’ => true),
‘capability_type’ => ‘post’,
‘hierarchical’ => false,
‘menu_position’ => null,
‘supports’ => array(‘title’,’editor’,’author’,’excerpt’,’page-attributes’)

register_post_type( ‘casestudy’ , $args );
add_action(‘init’, ‘register_custom_post_case_study’);

Now our URL matches the breadcrumbs and the Case Studies pages is the parent of our custom post type.

You may have to go into your Permalinks settings and, without making any updates, click the Save Changes button to update the new URL structure.

If you found this useful and are living near Dublin, Ireland, why not catch up with us at our regular monthly Dublin WordPress meetup.

Dublin WordPress

Attention all WordPress Users in Dublin

If you live in and around Dublin and use WordPress as a blogger, developer, designer, trainer, business venture etc, come and join us on the last Thursday of every month at the Bull & Castle (next to Christ Church) from 6.30pm onwards.

More details at