URL Rewrite doesn’t work for nested pages

I am using URL rewrite like this page: unexpected problem in url rewrite

It works without any problem, but when I try to use the same rules for nested page, it doesn’t work. Say, I have two pages named page-a and page-b. page-a is parent for page-b. Now I want to catch the passed variable. The URL structure will be:

Read More
page-a/page-b/
page-a/page-b/var1/
page-a/page-b/var1/var2/
page-a/page-b/var1/var2/var3/

So, I created three rules. The full code is as follows:

add_filter( 'query_vars', 'wpse26388_query_vars' );
function wpse26388_query_vars( $query_vars ){
    $query_vars[] = 'var1';
    $query_vars[] = 'var2';
    $query_vars[] = 'var3';
    return $query_vars;
}

function wpse26388_rewrites_init(){
     add_rewrite_rule(
        'page-a/page-b/([0-9]+)/?$',
        'index.php?pagename=page-b&var1=$matches[1]',
        'top' );

    add_rewrite_rule(
        'page-a/page-b/([0-9]+)/([0-9]+)/?$',
        'index.php?pagename=page-b&var1=$matches[1]&var2=$matches[2]',
        'top' );

    add_rewrite_rule(
        'page-a/page-b/([0-9]+)/([0-9]+)/([0-9]+)/?$',
        'index.php?pagename=page-b&var1=$matches[1]&var2=$matches[2]&var3=$matches[3]',
        'top' );
}
add_action( 'init', 'wpse26388_rewrites_init' );

I am using Rewrite analyzer and the variables get the correct regex values. Now when I go to that page with parameter like page-a/page-b/10/20, the parameters are truncated automatically. get_query_var('var1') doesn’t get anything. So, if I pass 1, 2 or 3 parameter it will always redirect to page-a/page-b/.

Can anyone point me what I’m doing wrong?

I know this regex capture numbers. But I need regex so that anything that comes after page-a/page-b/ will be captured by the query variables. I hope someone can help me with this too.

Related posts

2 comments

  1. I have found my answer while searching. Thanks to this answer of @Milo: https://wordpress.stackexchange.com/a/50775/23214

    pagename must include the full parent/child path. So, I had to change index.php?pagename=page-b... to index.php?pagename=page-a/page-b.... Changed it and works ok.

    Here is the Full code:

    add_filter( 'query_vars', 'wpse26388_query_vars' );
    function wpse26388_query_vars( $query_vars ){
        $query_vars[] = 'var1';
        $query_vars[] = 'var2';
        $query_vars[] = 'var3';
        return $query_vars;
    }
    
    function wpse26388_rewrites_init(){
         add_rewrite_rule(
            'page-a/page-b/([0-9]+)/?$',
            'index.php?pagename=page-a/page-b&var1=$matches[1]',
            'top' );
    
        add_rewrite_rule(
            'page-a/page-b/([0-9]+)/([0-9]+)/?$',
            'index.php?pagename=page-a/page-b&var1=$matches[1]&var2=$matches[2]',
            'top' );
    
        add_rewrite_rule(
            'page-a/page-b/([0-9]+)/([0-9]+)/([0-9]+)/?$',
            'index.php?pagename=page-a/page-b&var1=$matches[1]&var2=$matches[2]&var3=$matches[3]',
            'top' );
    }
    add_action( 'init', 'wpse26388_rewrites_init' );
    
  2. Okies, so before we begin doing anything with regex besides numbers, lets take a look at all of your patterns really quick:

    add_rewrite_rule(
        'page-a/page-b/([0-9]+)/?$',
        'index.php?pagename=page-b&var1=$matches[1]',
        'top' );
    

    This rule is added to the top of the list, first. This means that it will be processed LAST of these 3 rules. This rule looks like it does what you want it to.

    add_rewrite_rule(
        'page-a/page-b/([0-9]+)/([0-9]+)/?$',
        'index.php?pagename=page-bs&var1=$matches[1]&var2=$matches[2]',
        'top' );
    

    This rule is processed 2nd (of these 3 rules). This rule’s pattern looks fantastic, however, the url it’s rewriting too looks like it has a typo. Change pagename=page-bs to pagename=page-b, unless you have a pagename of page-bs on your site.

    add_rewrite_rule(
        'page-a/page-b([0-9]+)/([0-9]+)/([0-9]+)/?$',
        'index.php?pagename=page-b&var1=$matches[1]&var2=$matches[2]&var3=$matches[3]',
        'top' );
    

    Finally, this rule is processed FIRST (of these 3 rules). This rule’s rewrite looks fine, however it looks like your pattern has a typo. Change 'page-a/page-b([0-9]+)/([0-9]+)/([0-9]+)/?$' to 'page-a/page-b/([0-9]+)/([0-9]+)/([0-9]+)/?$' (you missed a forward slash after page-b).

    Now, after those typos are corrected, we should be rewriting to the correct rule, depending on the number of slashes (or query vars, in this case). Keep in mind that Regex is [b]very[/b] picky when it comes to typos and making sure that your pattern is correct. It looks like your rules are in the correct order as well.

    Now, if we want to match anything more than numbers, we need to specify this in our regex patterns. Usually we want to match numbers, lowercase letters, uppercase letters, and hyphens when we do URL rewriting. To do this we need to change all instances of ([0-9]+) to ([0-9a-zA-Z-]+).

    Here is an example URL and its corresponding pattern:
    URL: http://www.example.com/page-a/page-b/my-cool-new-slug-12/my-cool-new-subslug-11/
    Rewrite Rule:

    add_rewrite_rule(
        'page-a/page-b/([0-9a-zA-Z-]+)/([0-9a-zA-Z-]+)/?$',
        'index.php?pagename=page-b&var1=$matches[1]&var2=$matches[2]',
        'top' );
    

    Expected Rewritten URL: http://www.example.com/index.php?pagename=page-b&var1=my-cool-new-slug-12&var2=my-cool-new-subslug-11

    Hope that helps!

    Let me know if you have any questions.

Comments are closed.