Understanding add_rewrite_rule

I am trying to get add_rewrite_rule working to extract a param from url and pass it through to the request. Seen a number of posts about this, but can’t seem to get it working.

If a url begins with a certain string, I would like to remove it from the url and pass it as a query params.

Example request url:

http://domain.com/foo/my_page

This would get transformed to

http://domain.com/my_page?param=foo

If ‘foo’ is not present, it should just go through as a normal request. This logic should apply to any page url or custom post type url on my site (basically foo/*). Thinking it would act as a pass thru, if the url has ‘foo’ strip it out and then just pass along to WordPress to to it’s normal thing.

I already have ‘param’ in as an allowed query_vars.

In total, it would need to work for the following:

  • /foo/my_page (Page)
  • /foo/my_folder/my_page (Sub-Page)
  • /foo/example_type (Custom Post Archive)
  • /foo/example_type/example_post (Custom Post Single)

2

A basic rule that would work for your example:

function wpd_foo_rewrite_rule() {
    add_rewrite_rule(
        '^foo/([^/]*)/?',
        'index.php?pagename=$matches[1]&param=foo',
        'top'
    );
}
add_action( 'init', 'wpd_foo_rewrite_rule' );

This takes whatever comes after foo/ and sets that as pagename for the query, and then param gets the static value foo. If you need different URL patterns, you’ll need extra rules for each unique pattern. Refer to WP_Query docs for the various query vars that can be set within rewrite rules. Don’t forget to flush rewrite rules after adding new ones. This can be done by visiting the Permalinks Settings page.

Now visiting your example URL:

http://domain.com/foo/my_page

will load the correct page, but it’s not going to behave exactly like visiting:

http://domain.com/my_page?param=foo

because when using internal rewrites, param is set within the $wp_query query object, not the $_GET superglobal. If you need to work with code that’s looking for a value in $_GET, you’ll need an extra step to set that value:

function wpd_foo_get_param() {
    if( false !== get_query_var( 'param' ) ){
        $_GET['param'] = get_query_var( 'param' );
    }
}
add_action( 'parse_query', 'wpd_foo_get_param' );

Another method to consider is using endpoints, so /foo/ would be on the end of URLs rather than as a prefix. The advantage to this is that the API’s add_rewrite_endpoint simplifies adding all of the rules you need, including enabling pagination.

Leave a Comment