I have page Example (ID=443, slug=example) that is configured, through Dashboard->Settings->Reading, as the home page of my WP site. I also have the following rewrite rule configured:

[(example)/(view-section)] => index.php?pagename=$matches[1]&foo=1&bar=2

I have a shortcode in the Example page that should generate content based on presence and value of fooand barquery vars. The problem is the query vars are not properly set when I visit the URL /example/view-section (and others related, see below).

I'm using a test plugin to debug this issue only. The complete code is below:

<!-- language: lang-php -->

function test_shortcode() {
    global $wp_rewrite;

    echo '<pre>' . 'foo: ' . get_query_var('foo') . '</pre>';
    echo '<pre>' . 'bar: ' . get_query_var('bar') . '</pre>';
    echo '<pre>' . print_r($wp_rewrite->rules, true) . '</pre>';
add_shortcode('foobar', 'test_shortcode');

function test_rules() {
    $rules = get_option('rewrite_rules');
    if (!isset($rules['(example)/(view-section)'])) {
        global $wp_rewrite;
add_action('wp_loaded', 'test_rules');

function test_rewrite_rules($wprules) {
    $rules = array('(example)/(view-section)' => 'index.php?pagename=$matches[1]&foo=1&bar=2');
    return $rules + $wprules;
add_action('rewrite_rules_array', 'test_rewrite_rules');

function test_query_vars($query_vars) {
    array_push($query_vars, 'foo');
    array_push($query_vars, 'bar');
    return $query_vars;
add_filter('query_vars', 'test_query_vars');

There are three scenarios that gave me different results:

  1. Going to /example/view-section redirects to / and the query vars values are empty.
  2. Going to /index.php?pagename=example&foo=1&bar=2 works the way I needed. Showing the content generated by the shortcode and the value of the two query vars passed in the URL.
  3. If I use page_id instead of pagename or page: /index.php?page_id=443&foo=1&bar=2, the page_id query var is removed and the default homepage is shown again.

I would like to know why is WP behaving as described above and, if possible, how to make the first case, at least, work like the second one.

Please note that if the Example page is not configured as the homepage, cases 1 and 3 work as the case 2.

I appreciate your help and will be happy to provide more details if necessary.


The question originally included links to a running WP instance with an example of the problem. However, I can't keep that instance running forever, so I removed the links and tried to explain the situation with words only.

  • What happens if you save your permalink settings again, and then try? May 8, 2012 at 18:58
  • @Stephen Harris, I get same results. I think saving permalinks again has the same effect that calling flush_rewrite_rules or $wp_rewrite->flush_rules, does it?. Also you can see in the results page that the rule is being properly added to $wp_rewrite->rules array. Thks. May 8, 2012 at 20:23

1 Answer 1


The problem has nothing to do with the rewrite rules (though I would suggest using add_rewrite_rule() rather than the more low level approach of altering the rewrite array directly. The same for flush_rewrite_rules(). Also, although as you have it the rules are only flushed once - it would be better to do it on the activation of the plug-in, rather than inside a conditional which is checked on every page load.

... so the 'problem' is actually canonicalisation. Basically various urls can point to the same content (including urls with just additional forward-slashes). The idea is that

  1. This is not good for a seo perspective - if search engines don't realise that all these url represent the same resource, they may end up competing with each other
  2. Not good from a user perspective. If they go to www.example.com?year=2012 it would be to redirect them to www.example.com/2012 - prettier and easier to remember.

So, when WordPress receives a 'broken' or 'duplicate' url such www.example.com?year=2012 it redirects it to the correct (or 'canonical') url. (www.example.com/2012) in this case.

One of the checks it performs is whether we are on the 'home page', and if we are - it checks that we are using the canonical url for our home page: in your case. If not, you are redirected here. You'll notice that redirects to there to.

You can turn this off. Canonicalisation is run on the template_redirect hook. So you can simply remove it:

remove_filter('template_redirect', 'redirect_canonical');

Or you can 'undo' it (in the specific instance of your front say), by using a hook that is used inside the redirect_canonical callback

add_filter('redirect_canonical', 'wpse51530_redirect_canonical', 10, 2);

function wpse51530_redirect_canonical($redirect_url, $requested_url){
    if( is_front_page() )
        return $requested_url;
        return $redirect_url;

You can see how WordPress does canonicalisation here.

  • Thank you @StephenHarris, that's a great explanation for the the problem I have and your suggestions pointed me right to the solution. May 9, 2012 at 16:32

Your Answer

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

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