10

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)
  • any URL, meaning posts, categories, tags, etc., not just the page post type, or just any page? what about parent/child pages in hierarchy? – Milo Dec 31 '16 at 0:05
  • @Milo I have clarified this for you. I am only using pages and custom post types (archive and single pages). – Louis W Dec 31 '16 at 0:07
7
+25

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.

  • Thanks for the through explanation. Seems close, works for pages but giving me a 404 error for custom post archive and single urls. – Louis W Jan 2 '17 at 4:51
  • well yeah, like I said, you need to add additional rules that match each of those patterns. I don't know what those URLs look like on your setup. – Milo Jan 2 '17 at 7:00
  • I have a custom page type named 'projects' which has an archive and single pages. Can you give an example for that, and I can make all the others. – Louis W Jan 2 '17 at 16:50
  • Also, it doesn't appear to work for sub-pages. – Louis W Jan 2 '17 at 18:59
  • 1
    Edit your question to add an example of each URL pattern that needs a rule. I'm not really concerned about my answer being accepted, sometimes I can trick people into answering their own questions by giving them something to start with. – Milo Jan 3 '17 at 0:15
6

Ok, I've gotten working examples for all 3 types of requests. It took a ton of experimenting and messing around in order to get them working. I guess Milo is good at nudging people into answering their own questions.

After countless changes and refreshing the permalinks I realized it was much easier to figure out the urls outside of the add_rewrite_url and once they worked then define the rewrite. Example being index.php?param=foo&post_type=example_type.

Another obvious thing, but adding it here so it might help someone else. You must define the custom post type add_rewrite_rule rules BEFORE you define your page/sub-page wildcard rules. I wasted quite a bit of time with that one and think it's the main thing that was causing me to not understand why the rules didn't work.

Here are the 3 rules which work across all my needs. The Page/Sub-Page rule was combined into a single one.

// Custom Post Archive
add_rewrite_rule(
    '^foo/example_type/?$',
    'index.php?param=foo&post_type=example_type',
    'top'
    );

// Custom Post Individual
add_rewrite_rule(
    '^foo/example_type/([^/]*)/?$',
    'index.php?param=foo&example_type=$matches[1]',
    'top'
    );

// Pages, Top-Level and Sub-Pages
// This MUST be placed in the code AFTER custom post add_rewrite_rule
add_rewrite_rule(
    '^foo/(.+)/?$',    
    'index.php?param=foo&pagename=$matches[1]',
    'top'
    );

Additionally what I've done is set up a loop to add multiple custom post type rules. Remember, you must define the custom post type add_rewrite_rule rules BEFORE you define your page/sub-page wildcard rules.

$custom_types = array('example_type', 'projects', 'people');

foreach($custom_types as $type) {

    // Custom Post Archive
    add_rewrite_rule(
        '^foo/'.$type.'/?$',
        'index.php?param=foo&post_type='.$type,
        'top'
        );

    // Custom Post Individual
    add_rewrite_rule(
        '^foo/'.$type.'/([^/]*)/?$',
        'index.php?param=foo&'.$type.'=$matches[1]',
        'top'
        );

}

The Rewrite Analyzer which Milo passed along was quite helpful when trying to better understand how Wordpress queries for pages/posts.

  • Late to the show, but can I ping you for another example? Mind you, I totally do not understand the $tag parameter of the add_rewrite_rule. Have no clue what it means. Nor do I understand example using pagename=$matches[1]'. HUH??? I have a URL like domain.com/detail?id=2&it=3. I want the page to be domain.com/detail/2-3/. Are you willing? – Debbie Kurth Nov 10 at 8:52

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.