I have a query string added to some urls which isn't pretty:


So i'd like to structure the url like: https://example.com/realpage1/realpage2/amsterdam/ or https://example.com/realpage1/amsterdam/ depending on the type of content.

And then get the variable with some htaccess like:

RewriteRule ^/(.*)/(.*)/(.*)$ ?city=$3

The page /aaa/bbb/ does exits. But the above gives a 404.

How can i achieve this in Wordpress? Thanks.

UPDATE: Following @pat's suggestion, and the code form the user-contributed-notes, i now have the below code. But, still a 404 is returned. What am i missing? Code is added to my child-theme functions.php by the way.

function wpdocs_flush_rules() {

    $rules = get_option( 'rewrite_rules' );

    if ( ! isset( $rules['(.*)/(.*)/([a-zA-Z-]{4,20})/?$'] ) ) {
        global $wp_rewrite;

add_action( 'wp_loaded','wpdocs_flush_rules' );

function wpdocs_insert_rewrite_rules( $rules ) {

    $newrules = array();
    $newrules['(.*)/(.*)/([a-zA-Z-]{4,20})/?$'] = 'index.php?stad=$matches[3]';
    return $newrules + $rules;

add_filter( 'page_rewrite_rules', 'wpdocs_insert_rewrite_rules' );

function wpdocs_insert_query_vars( $vars ) {

    $vars[] = 'city';
    return $vars;

add_filter( 'query_vars', 'wpdocs_insert_query_vars' );
  • 2
    You shouldn't need to edit .htaccess to add rewrite rules to WordPress. There's an entire API provided for just that. Check out the WP_Rewrite class, and have a look at the user-contributed notes which appears to have a quick recipe for how to create a URL rewrite. – Pat J May 15 '20 at 13:47
  • @PatJ Thanks for pointing me to this class! Great! I modified the examples provided but still a 404.. oh i updated me question above. – Peps May 15 '20 at 14:44

There are a few points to share because I could foresee that the comment will be very long and I post some suggestion here for reference and hopefully could fix it up.

1st point about the rewrite

$newrules['/(\d*)$'] = 'index.php?city=$matches[1]';

I guess you expect to use a url like https://example.com/new_york/ to the path so city will take up new_york like city=new_york. However, the rule (\d*) which expect to screen out only digits so character other than 0-9 will be ignored.

Just guessing that it would be ([^/]+)

  • ([^/]+) excluding slash '/', + match any characters 1 to unlimited times
  • () means for capturing group
$newrules['([^/]+)/?$'] = 'index.php?city=$matches[1]';

Please try the regex in this tool (the tool requires escape of / => written as \/, in php code, it is not necessary in your case)

2nd point about the priority

The rewrite_rules_array is used so the rule above will be added to the end (or near end if there is any other plugins doing the same) of the rule. The rewrite rule is matching sequentially. So, there is chance that the 404 is being determined before the rule is being matched with similar patterns.

The rule could be put in higher priority by a number of ways such as putting in other earlier rule filters or using add_rewrite_rule() with top attribute to make it matching in higher priority. In other words, the possibility of this rule is being matched first is heightened and might result in other undesired effect. So a thorough test to match your needs is necessary. Please expect testing and adjustment to be made before it comes to satisfaction.

Please refer to docs for different filters:

function wpdocs_insert_rewrite_rules( $rules ) {

    $newrules = array();
    $newrules['([^/]+)/?$'] = 'index.php?city=$matches[1]';
    return $newrules + $rules;
add_filter( 'TRY_CHANGING_FILER_HERE_IF_LOADING_PRIORITY_MATTERS','wpdocs_insert_rewrite_rules' );

An alternative way to using the above filters using add_rewrite_rule()

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

about the writing format

Just a personal opinion that you could use the format shown in the docs to write the array for simplicity and clarity.

function wpdocs_insert_query_vars( $vars ) {

    $vars[] = 'city';
    return $vars;

add_filter( 'query_vars','wpdocs_insert_query_vars' );

The rules inside wpdocs_flush_rules() is also needed to be updated.

  • Thanks for the post / explanation! I now made the rule: $newrules['([a-zA-Z-]{4,20})/?$'] = "index.php?city=$matches[1]"; Doesn't this line set the rule to the first place also? return $newrules + $rules; Also, still 404 unfortunatly. The city page = /aaa/bbb/city/ Does that change anything? – Peps May 16 '20 at 11:42
  • Also tried different filters, no luck yet. I'll update my question with the current code. – Peps May 16 '20 at 11:44
  • Updated them in my question. Testing with this url now: example.com/realpage1/realpage2/amsterdam – Peps May 16 '20 at 12:56
  • Let us continue this discussion in chat. – simongcc May 16 '20 at 13:42
  • Ready when you are! – Peps May 19 '20 at 7:46

Oke, so after days of digging I finally found the answer. The problem was:


The 'pagename' parameter had to be set and filled too, with both 'slugs'.

The complete code I ended up with:

function custom_rewrite_rule() {
    add_rewrite_rule( '(.*)/(.*)/([a-z-]{4,20})[/]?$', 'index.php?pagename=$matches[1]/$matches[2]&city=$matches[3]', 'top' );
add_action('init', 'custom_rewrite_rule', 10, 0);

function insert_custom_query_vars ( $vars ) {

    $vars[] = 'city';
    return $vars;

add_filter( 'query_vars', 'insert_custom_query_vars' );

Happy blogging ;)

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.