Site icon Hip-Hop Website Design and Development

Adding rewrite rule dynamically

I’m trying to dynamically add a rewrite rule that allows one to access any page under an alternate permalink structure of my choosing.

So for example, if the alternate permalink structure includes the slug foo/ in the first postion, I want to add a rewrite rule such that:

example.com/foo/my-page rewrites to example.com/my-page

example.com/foo/my-cool/blog/post rewrites to example.com/my-cool/blog/post

So basically, no matter whether the query is for a page, a post, or any other type of custom content, I want this content to be accessible under the /foo/ slug as well as the original non-foo URL structure.

I have written a working function that accomplishes this by..

  1. reading the URI
  2. removing the slug from he URI
  3. looping through all the existing rewrite rules
  4. matching the URI with the slug removed to an existing rewrite rule
  5. grabbing the matching groups for matched the rewrite rule
  6. compiling a new rewrite rule with the slugged URI as the source and the matched rewrite rule endpoint with matching groups replaced with their values as the destination.

Here is the code:

add_action('generate_rewrite_rules', function($wp_rewrite) {

    $slug = 'foo';

    // get the request URI
    $uri = $_SERVER['REQUEST_URI']; 

    // determine whether URI has slug in the first position
    if(preg_match('/^(/' . $slug . ')/', $uri)){

        // get the base URI by removing the slug
        $base_uri = str_replace('/goo','',$uri);

        // loop through existing rewrite rules
        foreach($wp_rewrite->rules as $src => $dest){

            // find the rewrite rule for which the base URI would have matched
            $regex_to_match = '/' . str_replace('/','/',$src) . '/';
            preg_match_all($regex_to_match, $base_uri, $matches, PREG_SET_ORDER);

            if(count($matches) > 0){

                // get the specific matching groups
                $matches = $matches[0]; 

                // compile valid regex from URI with slug to create new rewrite source
                $new_src = ($uri[0] == '/' ? substr($uri, 1) : $uri) . '?$';
            
                // replace match variables with their string values to create new rewrite destination
                for($i=1; $i<count($matches)+1; $i++){
                    $replacement = isset($matches[$i]) ? $matches[$i] : '';
                    $dest = str_replace('$matches[' . $i . ']', $replacement, $dest);
                }
                $new_dest = $dest;

                // add new rewrite rule to $wp_rewrite rules array
                $wp_rewrite->rules[$new_src] = $new_dest;

                // add the write rule
                add_rewrite_rule($new_src,$new_dest,'top');

                break;
            }
        }
    }

    return $wp_rewrite->rules;
});

This works but for some reason the generate_rewrite_rules hook is not run on every request and the callback function never fires. It only seems to run one time after I flush the permalinks. I have the Query Monitor plugin installed and am able to seem my new rewrite and verify that it is matched, but after I reload the page, it is no longer there.

I suspect it has to do with caching, and the hook is not firing after the rewrites have been initially generated.

How can I force the generate_rewrite_rules hook to fire on every request, such that my action is run?