I've been reading through this question and answer with great interest as I'm trying to achieve something very similar, but I'm failing and was wondering if someone could help me out.

I am also using a custom plug which is querying a custom table in order to populate a page. The page is a normal WP page with a template attached that calls a function to my plug-in file to get data.

If I type this in the URL I get my page loading properly:

www.mywebsite.com/?pagename=products/food-and-catering-workwear&prodid=232&pname=Trilby Hat

I would like to type this (or use it in a link) and get the same result:

mywebsite.com/products/food-and-catering-workwear/232/Trilby Hat/

(BTW, I also was thinking the reverse about rewrite_rules at first; that it would actually 'change' my URL to the more 'friendly' version once in place :-)

I have added this line to the init function in my plug-in file (one thing is that I'm using this same init function to enqueue some js -- I was assuming it would bo okay to just add this line to the same function):

 add_rewrite_rule('([^/]+)/([^/]+)/([^/]+)/?','index.php?pagename=$matches[1]&prodid=$matches[2]&pname=$matches[3]','top' );

Note: in my page hierarchy there will always be a parent page and a child page in the slug; chances are the parent will always be the same page, but the child will definitely vary. But I'd like to keep the rule flexible to catch all possibilities. The main trigger for my plug-in will be these two variables in the query string.

I've also added prodid and pname to $query_vars:

 add_filter( 'query_vars', 'prod_query_vars' );
    function prod_query_vars( $query_vars )
        $query_vars[] = 'prodid';
        $query_vars[] = 'pname';
        return $query_vars;

Does anyone see where I'm going wrong? One other thing. I'm not understanding the rule- flushing part. Since this is in a plug-in (not functions.php) when do I need to flush the rules? Each time I've updated the plugin file (trying out different code possibilities), I've first gone to the Permalinks page before trying to use my 'friendly' URL format. I noticed in one of the examples from the previous question: flush_rewrite_rules(false) was placed in the register_activation_hook() function, but my plug-in is already set up and running. I'm trying to alter it, so I'm thinking at this point I wouldn't be using this (but maybe this would be a solution for future 'installs' of the plug-in)

I'm also not that versed in regular expressions, so I know it could be there where I'm going astray.

Sorry for the long-winded question, but I wanted to supply as much detail to my situation as possible.

Thanks in advance to anyone who can help.


In regards to when you need to be flushing the rewrite rules:

This should only happen once, make sure you are not calling flush_rules() on init, as this will really kill performance for high traffic sites.

WordPress stores all of the rewrites in an array in the database, so all you need to do is hook in just before it updates the database. One way to do it is hook into "rewrite_rules_array" and add your rule:

add_filter( 'rewrite_rules_array', 'my_rewrites_function' );

function my_rewrite_function( $rules ) {

    $my_rules = array(
        '([^/]+)/([^/]+)/([^/]+)/?' => 'index.php?pagename=$matches[1]&prodid=$matches[2]&pname=$matches[3]'
    $rules = array_merge( $my_rules, $rules );

    return $rules;

Keep your 'query_vars' hook as it is. You will need to visit the Permalinks page to insert your rule into WordPress' options - but then you should be set.

If it doesn't work, you can hook into 'parse_request' to see which rewrite rule was chosen for the page you are viewing:

add_filter( 'parse_request', 'my_request_rewrite_check' );

function my_request_check( $wp ) {

    var_dump( $wp->matched_rule );
    return $wp;

Also, your regex is a but loose for the structure you put above mywebsite.com/products/food-and-catering-workwear/232/Trilby Hat/, it would be more like:


Is says "starts with 'products', '/', then any word, '/', then any numbers, '/', then any word" ("$" means that the string has to now end)

I hope that helps!

  • Thanks, Joe, but it's still not working. I seems to be picking up some other rule, so that click a link like this: mywebsite.com/products/food-and-catering-workwear/232/Trilby Hat/, it sends me to mywebsite.com/products/food-and-catering-workwear/. Using the 'parse_string' filter you suggested it tells me this is the rule it used: string(39) "(products/hand-protection)(/[0-9]+)?/?$". I am using your suggested regex for my new rule, ie. ` ^products/([^/]+)/([\d]*)/([^/]+)/?$`. Do you know what I'm missing? Thanks. – Kevin Mar 7 '11 at 10:36
  • I just reread what I wrote above. First off, English is my first language. . .don't know what happened there :-). The rule that it says it used to display the example I gave was this: string(50) "(products/food-and-catering-workwear)(/[0-9]+)?/?$". What I had up there was something stuck in my clipboard. Sorry. Also, if I type this in the URL mywebsite.com/?pagename=products/food-and-catering-workwear&prodid=232&pname=Trilby Hat I get the page I really want and the rule it says it used was: NULL. – Kevin Mar 7 '11 at 12:09
  • Me again. I have now changed my rewrite rule to this '^products/([^/]+)/([\d]*)/([^/]+)/?$' => 'index.php?pagename=products/$matches[1]&prodid=$matches[2]&pname=$matches[3]', and so when I click on a link mywebsite.com/products/food-and-catering-workwear/232/Trilby Hat/ it will show that in the URL but it displays this page mywebsite.com/products/food-and-catering-workwear/ BUT the parse_string filter tells me it used this rule to get there: string(35) "products/([^/]+)/([\d]*)/([^/]+)/?$". That means it's picking up my filter but just not rewriting it properly, yes? – Kevin Mar 7 '11 at 16:57

Okay, after looking at this and looking at this, I realised that my problem was NOT with the rewrite rules. It was with how my plug was dealing with the query string!!! It was looking for $_GET['prodid'] to populate the page. I did not realise that by using the "query_vars" hook, I need to be using $prodid (as long as I declared it as global first).

Anyway, it's sorted now and I thank Joe again for his help as well those involved in the first (linked) question, as that provided me with a lot of assistance too.

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.