Similar questions have been asked before, but no answer suits well.

I have: site.com/parent-page/child-page and would like to have: site.com/child-page

So I want to exclusively have permalinks with depth 1, without using the custom menu but still "hierarchizing" my pages in the admin all pages view and with parent/order in page attributes.

The solution also needs to work automatically, so not changing permalinks on each page with the plugin "Custom Permalinks".

This is what I need, and I am sure it is possible with a few lines of code in the functions.php, which I have found elsewhere but only for posts to remove the category, but not working for pages to remove the parent.

This is such code, that maybe can be changed to work for pages?

add_filter( 'post_link', 'remove_parent_cats_from_link', 10, 3 );
function remove_parent_cats_from_link( $permalink, $post, $leavename ) {
    $cats = get_the_category( $post->ID );
    if ( $cats ) {
        // Make sure we use the same start cat as the permalink generator
        usort( $cats, '_usort_terms_by_ID' ); // order by ID
        $category = $cats[0]->slug;
        if ( $parent = $cats[0]->parent ) {
            // If there are parent categories, collect them and replace them in the link
            $parentcats = get_category_parents( $parent, false, '/', true );
            // str_replace() is not the best solution if you can have duplicates:
            // example.com/luxemburg/luxemburg/ will be stripped down to example.com/
            // But if you don't expect that, it should work
            $permalink = str_replace( $parentcats, '', $permalink );
    return $permalink;

a quick search shows another stackexchange topic on this, and it used this code to cleanup the permalink of parents/ancestors:

function wpse_101072_flatten_hierarchies( $post_link, $post ) {
    if ( 'page' != $post->post_type )
        return $post_link;

    $uri = '';
    foreach ( $post->ancestors as $parent ) {
        $uri = get_post( $parent )->post_name . "/" . $uri;

    return str_replace( $uri, '', $post_link );
add_filter( 'post_type_link', 'wpse_101072_flatten_hierarchies', 10, 2 );

You can find that discussion here: Removing parent slug from URL on custom post type

  • 1
    This does funny things :) The ones who have a parent still show with parents, but the ones without parent lead to 404 :D And also it is talked about custom post types, and Sebastian in the end asks the same question as me, how to make it work for pages, which stood unanswered. So I still hope it will find an answer.
    – Sofian
    Mar 23 '15 at 14:52

tl;dr = Install the free plugin "Permalinks Customizer". Set "PostTypes Settings" for Pages to '%postname%' and then edit pages to modify the respective Permalinks accordingly. I have tested this with a scenario of hierarchical and non-hierarchical pages, and ivt works without any difficulty.

The longer answer
The OP's scenario is based on a generic page and, in my view, this presents a significant, possibly an impossible, challenge since the solution must apply anonymously. That is, there is no predictable "trigger" or "handle" that can be used to create a rewrite that will create a valid request. A custom post type might work (or not), but the OP has ruled this out as an this option. The OP's proposed approach also carries the risk of duplicate pages. Considering all of this, one might suggest that the OP's proposed approach is neither worthwhile nor wise - but I shall leave that for the OP to judge themself.

The OP is quite correct; the answer proposed by Nicu does not work because this line has the effect of building the uri from the original parentage.

$uri = get_post( $parent )->post_name . "/" . $uri;

I have (unsuccessfully) worked on a filter that would meet the OP's requirements. I offer it here just in case it might be useful for someone else. For reference purposes, all my testing was done with Permalinks set to "Post Name", and every time I adjusted a filter, I refreshed the Permalinks page. I created four pages. Ancestry, Parents (parent = 'Ancestry'), Children (parent = 'Parents'), and Transportation (no parent).

I found that creating the uri is the easy part, or at least seems easy. This alternative (in functions.php) works:

function wpse_182006_pages_permalink( $link, $post_id) {

    // get the post_type and evaluate
    $posttype = get_post_field( 'post_type', $post_id, 'display' );
    if ($posttype !== 'page'){
        return link;

    // build the uri from the slug
    $slugname = get_post_field( 'post_name', $post_id, 'display' );
    $slugname = $slugname."/";
    $link = home_url($slugname);
    return $link;


add_filter( 'page_link', 'wpse_182006_pages_permalink', 10, 3 );

Both the "Ancestry" and "Transportation" pages open normally.
The "Parents" and "Children" pages (each with a 'parent' page) open to 404 errors.
If you look at the Request Query (refer below), it is evident that the 404 is generated because WordPress interprets the "page" as a "post", and no such post exists. Note that the post ID is not used in the failed queries. Perhaps this is the key to a successful rewrite, but it was beyond my ability.

For reference, these are "request" details for "Ancestry":
Matched Query = 'pagename=ancestory&page='
Matched Rule = '(.?.+?)(?:/([0-9]+))?/?$'
Main query = SELECT wp_posts.* FROM wp_posts WHERE 1=1 AND (wp_posts.ID = '46') AND wp_posts.post_type = 'page' ORDER BY wp_posts.post_date DESC

By comparison, these are "request" details for "Children":
Matched Query = 'name=children&page='
Matched Rule = '([^/]+)(?:/([0-9]+))?/?$'
Main query = SELECT wp_posts.* FROM wp_posts WHERE 1=1 AND wp_posts.post_name = 'parents' AND wp_posts.post_type = 'post' ORDER BY wp_posts.post_date DESC

FWIW, by setting the permalink this way, the permalink is not editable. Before:
enter image description here

enter image description here

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.