5

I have several pages set up in a hierarchy on my site. Currently the site's pages and URLs look like this.

Page name        | Current URL           | Preferred URL 
-----------------|----------------------------------------
Page AAA         | /pageAAA/             | /pageAAA/
|-- Page BBB     | /pageAAA/pageBBB/     | /pageBBB/
Page CCC         | /pageCCC/             | /pageCCC/
Page DDD         | /pageDDD/             | /pageDDD/
|-- Page EEE     | /pageDDD/pageEEE/     | /pageEEE/

I would like to strip the page hierarchy from the URL and just use the page name instead. Currently this is not a problem for the "POSTS" as I have set the "Permalink" to /%postname%/

Edit: The reason that I want to do this is; I am importing a existing site into wordpress. The Existing site has a hierarchy for the pages (menu) but a flat url structure. I do not know if this has any added benefit for SEO but I want to keep the URL structure the same as the old site

8
  • Is there any reason to do this? From SEO point of view it could be the plus. example.com/Kodak/Kodak-1234/ is OK. Can you precise, please? – Max Yudin Mar 21 '13 at 18:32
  • 1
    Why create a hierarchy at all, then? – vancoder Mar 21 '13 at 18:38
  • @MaxYudin I do not know if there is a added SEO benefit, – Steven Smethurst Mar 21 '13 at 18:42
  • @vancoder I want the hierarchy for the menu system in wordpress. – Steven Smethurst Mar 21 '13 at 18:43
  • You can create your own hierarchy in the menu system...? It's independent of parent/child pages. – vancoder Mar 21 '13 at 18:44
1

I'd be curious if someone can find a better solution to this. Here's what I came up with:

function wpse_91821_flatten_page_paths( $wp ) {
    if ( false !== strpos( $wp->matched_query, 'pagename=' ) && isset( $wp->query_vars['pagename'] ) && $wp->query_vars['pagename'] && false === strpos( $wp->query_vars['pagename'], '/' ) ) {
        if ( !get_page_by_path( $wp->query_vars['pagename'] ) ) {
            $page = get_posts( array(
                'name'        => $wp->query_vars['pagename'],
                'post_type'   => 'page',
                'post_status' => 'publish',
                'numberposts' => 1
            ) );
            if ( $page && isset( $page[0] ) ) {
                $wp->query_vars['pagename'] = get_page_uri( $page[0]->ID );
                $wp->request = $wp->query_vars['pagename'];
            }
        }
    }
}
add_action( 'parse_request', 'wpse_91821_flatten_page_paths', 5 );

What I'm doing here is intercepting parse_request and if it's a pagename request, and the pagename doesn't have a "/" in it, then I check to see if I can find a post with the correct name. If I find a page, I set the query var, which allows the rest of the request chain to proceed as normal, because WordPress thinks the request is the full hierarchical one.

You'd also want to add a filter to post_type_link so that your links are generated correctly (otherwise they'll continue to be hierarchical).

4
  • I think you have to be very careful using this solution. I don't think it takes care of assuring unique post_names (am I missing something?) for these pages. So you may end up with multiple pages with the same post_name, so you won't be able to access some of them. – Krzysiek Dróżdż Jun 20 '13 at 20:24
  • That's a great question. I'm not sure offhand if page names need to be unique, and if they aren't, if other issues arrive. I'll do some testing when I have some free time and report back on my findings. Thanks! – Matthew Boynes Jun 20 '13 at 22:16
  • Of course they have to. Otherwise WP would not know which page to show based on permalink. Let's say you have 3 pages with post_name='contact'. Which of them should be displayed when you go to yoursite.com/contact? That's why WP has built in functions to assure that post_names are unique (and they change your post_name if it creates conflict). But these functions allow you to have same post_name for pages, if they have different parents. Your code will break this feature, I guess. – Krzysiek Dróżdż Jun 21 '13 at 6:37
  • I'm not sure this solution is valid with WordPress 4.5.3 - I couldn't get it to work anyway. – Howdy_McGee Jun 22 '16 at 15:08
0

I wouldn't change page permalink behavior. Much simpler/safer solution will be to set flat page hierarchy (if you really want it to be flat).

If you want to have hierarchy in menu, you can still have it - you can create custom menu and display it with wp_nav_menu function.

0
function wpse_91821_flatten_page_paths( $wp ) {
    if ( false !== strpos( $wp->matched_query, 'pagename=' ) && isset( $wp->query_vars['pagename'] ) && $wp->query_vars['pagename'] && false === strpos( $wp->query_vars['pagename'], '/' ) ) {
        if ( !get_page_by_path( $wp->query_vars['pagename'] ) ) {
            $page = get_posts( array(
                'name'        => $wp->query_vars['pagename'],
                'post_type'   => 'page',
                'post_status' => 'publish',
                'numberposts' => 1
            ) );
            if ( $page && isset( $page[0] ) ) {
                $wp->query_vars['pagename'] = get_page_uri( $page[0]->ID );
                $wp->request = $wp->query_vars['pagename'];
            }
        }
    }
}
add_action( 'parse_request', 'wpse_91821_flatten_page_paths', 5 );

function custom_permalinks_page_link( $permalink, $post_id ) {
    if ( empty( $post_id ) ) return $permalink;
    $post = get_post( $post_id );
    return home_url( $post->post_name . "/");
}
add_filter( 'page_link', 'custom_permalinks_page_link', 10, 2 );

function custom_rewrite() {
    add_rewrite_rule('^([^/]+)?', 'index.php?pagename= $matches[1]', 'top');
}
add_action( 'init', 'custom_rewrite' );

As of wp 4.7, you would need to work around the parse_request: as use_verbose_page_rules is triggered and get_page_by_path call checks the page parents and their presence in the url(!) - this unexpected core check could be avoided by adding an evil space as in https://github.com/weaveworks/wordepress/blob/master/plugin/wordepress/wordepress.php#L91

This is, of course, very fragile and should be probably avoided :)

This presentation may contain a better answer but I was not able to comprehend it: https://www.slideshare.net/MikeSchinkel/hardcore-url-routing-2014?next_slideshow=1

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.