I have urls of this form:

example.com/event/?eventId=1 example.com/event/?eventId=2

The problem is Google is indexing only example.com/event, which is a blank page. It's not able to display an event without the Id. I would like to redirect this url to this form:


This will allow Google to index each event individually.

The event page is provided by the admin. I imagine something like:

function add_eventId_rule() {
  $post = get_post(get_option('EVENT_AGENT_EVENT_PAGEID'));
  if($post != null)
      substr(wp_make_link_relative(get_permalink($post)), 1) . '(\d*)/?$',
      'index.php?page_id=' . $post->ID .'&eventId=$matches[1]',
    // this produces the regex event/(\d*)/?$  Can produce foo/bar/event if
    // the display page has parent pages

function ea_query_vars($qvars) {
  $qvars[] = 'eventId';
  return $qvars;

function capture_event_display_page($post)
  add_option('EVENT_AGENT_EVENT_PAGEID', $post->ID);

add_filter( 'query_vars', 'ea_query_vars' );
add_action( 'init', 'add_eventId_rule');
add_action( 'save_post', 'capture_event_display_page')

Using this code, the following work: https://www.eventagent.ai/event/?eventId=80 https://www.eventagent.ai/index.php?page_id=87&eventId=80

But the one I want doesn't. It strips the eventId: https://www.eventagent.ai/event/80

How come? What am I missing?

  • did you resave the permalinks after adding that code? And have you ran this through one of the rewrite analyser debugging plugins from .org? Is eventId referring to the post ID of an event custom post type?
    – Tom J Nowell
    Apr 22, 2022 at 0:26
  • The eventId is used by a 3rd-party SaaS product. Has nothing to do with WP. There is no custom post type. I just want to rewrite the Url, not change permalinks. He's an example of the unfriendly version: events.imcw.org/event/?eventId=1083
    – AldenG
    Apr 23, 2022 at 15:13
  • 1
    Rewriting the URL is what permalinks are in WordPress. They take a URL example.com/foo/bar, run it through rewrite rules ( regexes ) that map it into the form index.php?foo=bar then it processes it. In that example foo is a query variable. That misunderstanding may be why you haven't found your solution. When you add/remove a rewrite rule you need to re-save permalinks as that's the easiest way to flush all the rules out and recreate them. The rewrite rules analyser plugin lets you type the URL in and see which rules match and in which order. Maybe you didn't re-save or whitelist eventId
    – Tom J Nowell
    Apr 25, 2022 at 14:22
  • Thanks for the help! I left out the whitelist for brevity, but I've added it above. I noticed the qvars array always had eventId in it, anyway, so I don't imagine it was doing anything. So when someone activates my plugin, it needs to regenerate permalinks? This is not a post type, it's a shortcode that can appear on any page. If I add the above to the init hook in the plugin, nothing happens. It's behaving like the rewrite rules are determined before the plugin init fires.
    – AldenG
    Apr 26, 2022 at 15:52
  • Actually, the /event/ page is supplied by the user, so I will need to regenerate permalinks on the save_post hook when I have that page name.
    – AldenG
    Apr 26, 2022 at 16:02

1 Answer 1


Because it's not enough to register your rule, you need to flush the rewrite rules for it to take effect. An easy way of doing this is to visit the permalinks settings page.

This is true regardless of where the rewrite rule came from. The most common reason people encounter this is because of the rewrite rules core creates for custom post types, but this is not unique to custom post types.

Another possibility is that your rewrite rules regular expression doesn't match the URLs you are testing, or, that another rule with higher priority matches it first. The rewrite analyser plugin or one of its competitors can help diagnose this.

Warning: A common mistake developers make to try and work around this is to flush the rewrite rules programmatically on every request so they don't have to do it manually. This introduces bugs but it also adds a heavy performance hit that's trivially avoided. Flush them on plugin de/activation, when you update your plugins database settings, or when user interaction requires it, and never on the frontend unless absolutely unavoidably necessary. You may see this referred to as flushing on the init hook.

  • Okay, I edited the question to provide my full example, rather than a simplified version. Looks like I'm right to only flush_rewrite_rules when the admin gives me a new display page. However, I still see no change of behavior. The trailing ID is always stripped. Does this code look right? Is my next step to use the rewrite analyser?
    – AldenG
    Apr 26, 2022 at 20:30
  • your first step should have been to use the rewrite analyser, however the page you mentioned was a critical piece of information I didn't know about. The rewrite rule analyser will probably reveal the problem and would have answered all the questions I asked instantly as well as immediatley demonstrating most of what I explained
    – Tom J Nowell
    Apr 26, 2022 at 20:33
  • There's a high chance now that this is the canonical URL redirection filter. If that's the case then you can turn that filter off but there are SEO and other consequences that are highly undesirable. I'd strongly advise against hiding things in the name of simplicity, it's not helpful. But until you've tried the rewrite rule analyser I can't be sure. Be very specific with your terminology, explain in detail, and don't omit or hide code. E.g. it's unclear if you're using a template redirect filter or template locate filter, your current approach may not be viable because of the use of a page
    – Tom J Nowell
    Apr 26, 2022 at 20:34
  • I have tried using Url Rewrite Analyzer, but my rule is not listed there and it never hits my code that creates it. I don't know what those filters are -- I'm a vue programmer, not a WP guy :-) I still don't understand what permalinks have to do with rewriting urls. The permalink is always /[page provided by admin]/. Why would it change? So how do I investigate this canonical URL filter and get around it? When I put /event/1051 in the analyzer it rightly calls event the pagename, but wrongly calls 1051 the page. Without my rule loaded, I would expect this.
    – AldenG
    Apr 26, 2022 at 23:46
  • Okay, I had to flush permalinks to see my rule. The regex is event/(\d*)/?$ and the substitution lists eventId as the capture group (\d*) but it is crossed out in red. Why?
    – AldenG
    Apr 27, 2022 at 2:36

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.