I understand there are 2 different types when it comes to a custom post type:
-page
-post.

Where page supports child pages, and post does not.

However, when i try to make a child page with only numbers in it’s slug, wordpress puts -2 behind it. Example:

/posttype/parent/10-2/

instead of what i would have wanted:

/posttype/parent/10/

Why is this, and how can i solve it? I have searched for hours, but i can’t seem to find a solution, other than it’s perhaps a limitation in WordPress, do to a conflict with it’s date permalink system. I’m not using this system, but could this be true?

EDIT, some more information:
There are no posts whatsoever which can conflict with my permalink. The permalink is definitely not taken.

I get this behaviour with a completely new install of wordpress, and only 1 custom post type. The only posts in the wordpress database are ‘parent’ and ’02’. Where ’02’ turns into ’02-2′.

I was wondering if maybe pagination /slug/page/02 was maybe the reason numeric slugs were not accepted?

It is important to note, I only get this with numeric slugs, /parent/child/ is not a problem.

I’ve seen something about overriding the filters, but won’t that simply hide the problem? I prefer to solve it.

The code I use to register my custom post type:

    $labels = array(
    'name'                => _x( $options['euthus_posttype_meervoud'], 'Post Type General Name', 'text_domain' ),
    'singular_name'       => _x( $options['euthus_posttype'], 'Post Type Singular Name', 'text_domain' ),
    'menu_name'           => __( $options['euthus_posttype_meervoud'], 'text_domain' ),
    'name_admin_bar'      => __( $options['euthus_posttype_meervoud'], 'text_domain' ),
    'parent_item_colon'   => __( 'Parent Item:', 'text_domain' ),
    'all_items'           => __( 'All Items', 'text_domain' ),
    'add_new_item'        => __( 'Add New Item', 'text_domain' ),
    'add_new'             => __( 'Add New', 'text_domain' ),
    'new_item'            => __( 'New Item', 'text_domain' ),
    'edit_item'           => __( 'Edit Item', 'text_domain' ),
    'update_item'         => __( 'Update Item', 'text_domain' ),
    'view_item'           => __( 'View Item', 'text_domain' ),
    'search_items'        => __( 'Search Item', 'text_domain' ),
    'not_found'           => __( 'Not found', 'text_domain' ),
    'not_found_in_trash'  => __( 'Not found in Trash', 'text_domain' ),
);
$rewrite = array(
    'slug'                => $options['euthus_posttype_baseurl'],
    'with_front'          => true,
    'pages'               => false,
    'feeds'               => true,
);
$args = array(
    'label'               => __( 'euthus_childs', 'text_domain' ),
    'description'         => __( $options['euthus_posttype_meervoud'], 'text_domain' ),
    'labels'              => $labels,
    'supports'            => array( 'title', 'thumbnail', 'page-attributes',),
    'hierarchical'        => true,
    'public'              => true,
    'show_ui'             => true,
    'show_in_menu'        => true,
    'menu_position'       => 20,
    'menu_icon'           => 'dashicons-networking',
    'show_in_admin_bar'   => true,
    'show_in_nav_menus'   => true,
    'can_export'          => true,
    'has_archive'         => true,
    'exclude_from_search' => false,
    'publicly_queryable'  => true,
    'rewrite'             => $rewrite,
    'capability_type'     => 'page',
);
register_post_type( 'euthus_childs', $args );

As I understand, the ‘capability_type’ must be set to page and not post to allow for hierarchical, where setting it to ‘post’ does not allow this.

2 s
2

As you guessed and @Rarst suspected, there’s a pagination check in wp_unique_post_slug() for hierarchical post types:

preg_match( "@^($wp_rewrite->pagination_base)?\d+$@", $slug )

which will match any numeric only slug, optionally preceded by “page”. To get around this you could use the 'wp_unique_post_slug' filter, basically replicating the original code without the pagination check, eg

add_filter( 'wp_unique_post_slug', function ( $slug, $post_ID, $post_status, $post_type, $post_parent, $original_slug ) {
    if ( $slug !== $original_slug && is_post_type_hierarchical( $post_type ) ) {

        global $wpdb, $wp_rewrite;

        $slug = $original_slug; // Undo any previous processing.

        // The following is just a copy & paste of the WP code without the pagination check.
        $feeds = $wp_rewrite->feeds;
        if ( ! is_array( $feeds ) )
            $feeds = array();

        if ( 'nav_menu_item' == $post_type )
            return $slug;

        /*
         * Page slugs must be unique within their own trees. Pages are in a separate
         * namespace than posts so page slugs are allowed to overlap post slugs.
         */
        $check_sql = "SELECT post_name FROM $wpdb->posts WHERE post_name = %s AND post_type IN ( %s, 'attachment' ) AND ID != %d AND post_parent = %d LIMIT 1";
        $post_name_check = $wpdb->get_var( $wpdb->prepare( $check_sql, $slug, $post_type, $post_ID, $post_parent ) );

        /**
         * Filter whether the post slug would make a bad hierarchical post slug.
         *
         * @since 3.1.0
         *
         * @param bool   $bad_slug    Whether the post slug would be bad in a hierarchical post context.
         * @param string $slug        The post slug.
         * @param string $post_type   Post type.
         * @param int    $post_parent Post parent ID.
         */
        if ( $post_name_check || in_array( $slug, $feeds ) || apply_filters( 'wp_unique_post_slug_is_bad_hierarchical_slug', false, $slug, $post_type, $post_parent ) ) {
            $suffix = 2;
            do {
                $alt_post_name = _truncate_post_slug( $slug, 200 - ( strlen( $suffix ) + 1 ) ) . "-$suffix";
                $post_name_check = $wpdb->get_var( $wpdb->prepare( $check_sql, $alt_post_name, $post_type, $post_ID, $post_parent ) );
                $suffix++;
            } while ( $post_name_check );
            $slug = $alt_post_name;
        }
    }
    return $slug;
}, 10, 6 );

Leave a Reply

Your email address will not be published. Required fields are marked *