1

I have the following code in my functions.php file.

<?php
add_action('init', 'flush_rewrite_rules');

function custom_add_rewrite_rules( $wp_rewrite ) {
    $new_rules = array( 
        'insurance-leads-types/auto-insurance-leads/([^/\.]+)/?$' => 'index.php?pagename=auto-insurance-leads&state=' . $wp_rewrite->preg_index(1),
        'insurance-leads-types/home-insurance-leads/([^/\.]+)/?$' => 'index.php?pagename=home-insurance-leads&state=' . $wp_rewrite->preg_index(1)
    );
    $wp_rewrite->rules = $new_rules + $wp_rewrite->rules;
}
add_action('generate_rewrite_rules', 'custom_add_rewrite_rules');

function add_query_vars( $query_vars ) {
  $query_vars[] = 'state';
  return $query_vars;
}
add_filter( 'query_vars', 'add_query_vars' ); 

When I go to the page /insurance-leads-types/auto-insurance-leads/STATENAME/ the URL is redirected to /insurance-leads-types/auto-insurance-leads/ without the trailing STATENAME/ and the variable is not passed to $query_vars.

I used Monkeyman's Rewrite Analyzer and everything looks fine:

pagename: auto-insurance-leads

state: (.[^/]+)

Any ideas why the URL is redirecting?

2
  • I'll remove the add_action('init', 'flush_rewrite_rules'); once I get this working. Feb 16, 2012 at 18:53
  • FYI - Like a normal rewrite, I want the entire URL of the rewrite to remain in the address bar of the browser. Feb 16, 2012 at 18:57

3 Answers 3

1

You should probably use the built in rewrite api functions rather than using the generate_rewrite_rules filter. There are some issues with your rewrite regex. You need to start each with a carrot ^, to tell WP to match starting at the beginning of the URL.

I'm not really sure what you're trying to accomplish with the ([^/\.]+). Anything that isn't a slash or a period? If that's the case, it's probably not going to work the way you expect. Someone could enter insurance-leads-types/auto-insurance-leads/tx.state/ and it wouldn't get matched becauase your regex doesn't account for the stuff following the dot.

Here is a working version that will match anything that isn't a slash in the final group.

<?php
add_action( 'init', 'wpse42604_add_rewrite' );
function wpse42604_add_rewrite()
{
    add_rewrite_rule(
        '^insurance-leads-types/auto-insurance-leads/([^/]+)/?$',
        'index.php?pagename=auto-insurance-leads&state=$matches[1]',
        'top'
    );
    add_rewrite_rule(
        '^insurance-leads-types/home-insurance-leads/([^/]+)/?$',
        'index.php?pagename=home-insurance-leads&state=$matches[1]',
        'top'
    );
}

All the code as a plugin. I wrote a really big tutorial about the rewrite api that's worth a look.

Edit: Also, you might get some unpredictable behavior flushing rewrite rules one very page load like your code does.

4
  • I tried the code that you provided and now I get a 404. The page you requested could not be found. Feb 16, 2012 at 20:17
  • The regex here isn't the issue. I'm using this to parse a variable from a page link that I have created myself. The regex that I created works for my purposes. The REWRITE ANALYZER plugin shows that I have everything inserted correctly. The problem has to be somewhere else. Why does Wordpress redirect to the base PAGE? Feb 16, 2012 at 21:06
  • After more testing I can see it has something to do with this being a second level page. If I use my exact same original code and point to a first level page, the process works just fine; the URL with the extra VAR info remains and the variable passes to the page and displays. Any ideas why a second level page is redirecting to the base page? Feb 16, 2012 at 21:52
  • I just realised after posting my answer part of your issue may be that the pagename query var should be the slug of both the parent and child page with a slash in between as they appear in the URL. Nov 16, 2012 at 10:42
1

I would approach this using the add_rewrite_endpoint() function.

It takes care of adding query vars and is a lot more straight forward to set up plus you won't need to worry about page slugs changing etc...

The code would be:

// in functions.php
add_action( 'init', 'wpse42604_add_endpoints' );
function wpse42604_add_endpoints() {
   add_rewrite_endpoint( 'state', EP_PAGES );
}

// in template file eg. page.php   
if ( '' != get_query_var( 'state' ) ) {
    // ... do stuff with the state query var
}

The one downside (depending on how you look at it) is you won't get the exact URLs you're specifying above, they will be like this:

insurance-leads-types/auto-insurance-leads/state/tx/

But it's a more robust and flexible solution, plus that URL is still nice looking and readable.

The problem you're seeing is one I've run into before to do with WordPress's processing of the rewrite rules performing a canonical redirect before looking at the rewrites. Unfortunately it's a while since I traced through it so can't remember specifics but it's the redirect_canonical() function in wp-includes/canonical.php that was causing me a similar problem.

1

I faced similar issue multiple times and in my case, the redirect was caused by redirect_canonical() function placed in wp-includes/canonical.php. This function tries to redirect to base (canonical) URL for given request and it considers your URL /insurance-leads-types/auto-insurance-leads/STATENAME/ leading to same page as /insurance-leads-types/auto-insurance-leads/ so it redirects it.

Quickest fix is to disable canonical redirect when your specific query var is used - like this:

add_filter('redirect_canonical', function($redirect_url, $requested_url) {
    if ( get_query_var('state') ) {
        return $requested_url;
    }
}, 10, 2);

Of course you can play with this filter and add different conditions. I also recommend to check redirect_canonical function code to see how exactlty it works.

0

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

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