I have a query string added to some urls which isn’t pretty:
?city=Amsterdam
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;
$wp_rewrite->flush_rules();
}
}
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 Answers
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 “https://wordpress.stackexchange.com/”, + 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:
- rewrite_rules_array
- page_rewrite_rules
- author_rewrite_rules
- search_rewrite_rules
- comments_rewrite_rules
- root_rewrite_rules
- date_rewrite_rules
- post_rewrite_rules
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.