2
votes

I have a problem, after upgrading to wordpress 4.0 my custom post type isn't working anymore, here's how I register my custom post type:

function my_post_type() {
    $labels = array(
        'name'               => 'Staff'
    );
    $args = array(
        'labels'              => $labels,
        'public'              => true,
        'exclude_from_search' => true,
        'publicly_queryable'  => true,
        'show_ui'             => true,
        'show_in_nav_menus'   => false,
        'show_in_menu'        => true,
        'show_in_admin_bar'   => true,
        'menu_position'       => 20,
        'menu_icon'           => null,
        'capability_type'     => 'post',
        'hierarchical'        => true,
        'supports'            => array('title','editor','thumbnail','custom-fields','page-attributes'),
        'has_archive'         => false,
        'rewrite'             => false,
        'query_var'           => true,
        'can_export'          => true
    );
    register_post_type('my_staff', $args);
}
add_action('init', 'my_post_type');

The problem is that permalink to this post type gives 404, if I set 'hierarchical' to false, everything works, but the thing is that I need 'hierarchical' set to true, any solutions to this?

5

5 Answers

3
votes

I ran into this same issue after upgrading to WP 4.0 earlier today--views to single posts of one of my hierarchical custom post types showed 404 after the upgrade.

I did some digging into the WP core to see what change was made that might be causing the problem and discovered this:

https://core.trac.wordpress.org/changeset/28803

Reverting back to the previous code fixed the 404 issue for me. Can't tell if this is an indication of my own poor CPT implementation or an unforeseen bug with this change in Core. That said, if others with this problem would like to try this solution, it's a relatively simple change.

Replace line 2558 in /wp-includes/query.php from this:

if ( ! $ptype_obj->hierarchical ) {

to this:

if ( ! $ptype_obj->hierarchical || strpos($q[ $ptype_obj->query_var ], '/') === false ) { 
1
votes

I had the same issue, and I was able to solve this by setting 'hierarchical' => false in the register_post_type arguments.

$args = array(
    'labels' => $labels,
    'public' => true,
    'publicly_queryable' => true,
    'show_ui' => true, 
    'query_var' => true,
    'has_archive' => true,
    'menu_icon' => '',
    'show_in_menu' => 'bcs-options',
    'rewrite' => array('slug' => 'stories'),
    'capability_type' => 'page',
    'hierarchical' => false,
    'menu_position' => null,
    'supports' => array('title','editor','thumbnail','excerpt','comments','revisions')
);

I was still able to set the custom post parent manually in my code and everything works again as before. Not sure why Wordpress 4.0 broke things, but my guess is it has to do with how the new version handles permalinks for custom post types where hierarchical is set to true. Someone with a deeper knowledge of the Wordpress code base might be able to elaborate on this.

0
votes

All you need to do is add $post_type=whatever to the line

$children = wp_list_pages..

so it looks like

$children = wp_list_pages("title_li=&child_of=".$post->post_parent."&echo=0$post_type=whatever");

This will help you http://codex.wordpress.org/Function_Reference/wp_list_pages#List_members_of_a_custom_post_type

0
votes

Same problem here.

We developed custom post types for products, product categories and product suppliers in our WordPress Shopping Cart plugin and also a custom rewrite rule so that product URLs could be 'pretty' with the category names in them.

After the WordPress 4.0 upgrade, these hierarchical custom post types broke. The only quick solution at this time was to release an update, setting hierarchical to false since the products of all our clients showed 404 Page Not Found.

Something must've changed in WordPress 4.0. We are still working on a solution, trying to find the best way to get them back as they were before.

0
votes

I ran into exactly the same problem although, i didn't readily link it to the change to Wordpress 4.0. I've got several custom post types and only a few of them were returning 404 pages. It was only after seeing your original question that i realised that the problem was with those custom post types that were set to 'hierarchical' => true. Once i set 'hierarchical' => false, I could view the "problem" custom post.

However, that also meant that I lost some of the URL/permalink structure that I had when hierarchical was set to true. So, "custom-post-type\parent-title\post-title" became "custom-post-type\post-title".

I ended up setting a "post_type_link" filter to add the parent back into the link. I also have a rewrite rule setup for this revised link structure.

That solution was inspired by this post: https://wordpress.stackexchange.com/questions/136786/parent-cpt-child-custom-post-type-url-permalink-relationship

Although I didn't used a "%" parameter in the rewrite slug in the register_post_type. Instead, in the post_type_link function, i search for the slug and replace it with the original slug + any required prefix. I found that way i could keep the original slug in the link, which isn't 'contaminated' with the "%" parameter which, means the link is still useful for displaying the archive page and also the "%" parameter doesn't show up in breadcrumbs.

Extract from the register_post_type:

'rewrite' => array(
                        'slug' => 'dresses'// 'dresses/%designer%'
                  ),

post_type_link filter:

add_filter("post_type_link","rewrite_dress",10,2);

function rewrite_dress($link, $post) {
    if(get_post_type($post) === "dress") {
        $designer = get_post($post->post_parent);
        $designer = $designer->post_name . "/";
        if(!(check_not_empty($designer))) {
         $designer = "";
        }
        //$link     = str_replace("%designer%",$designer,$link);
        $link     = str_replace("dresses/","dresses/" . $designer,$link);
    }
    return $link;

    /*
    originally the slug had a reference in it e.g. %designer%
    we could then do a string replace on it to insert the designer
    but, if you used the breadcrumbs to view the root e.g. /dresses
    then it would actually appear as /dresses/%designer% which isn't wanted.
    */

}

Rewrite rule:

function rewrite_dress_rules(){
    global $wp_rewrite;
    /* /dresses/designer/dress */
    $q = "dresses/(.*)/(.*)";
    $q = "dresses/([^/]*)/([^/]*)/?";
    add_rewrite_rule($q,'index.php?post_type=dress&designer=$matches[1]&dress=$matches[2]','top');
    // $wp_rewrite->flush_rules(); // !!!
}

add_action("init", 'rewrite_dress_rules' );

That all kind of works for me. At least for the time being. I'll have to keep an eye on future Wordpress updates to see they have any further impact.