Same Permalink for Different WordPress Objects with add_rewrite_rule

Have you ever found yourself in a situation where you need to present two different WordPress objects, like a custom […]

Have you ever found yourself in a situation where you need to present two different WordPress objects, like a custom post type and a taxonomy, under the same URL structure? If you’ve tried simply using add_rewrite_rule, you already know it’s not straightforward. I recently encountered this very challenge while working on a client’s website. The client needed to display pages and a “cities” taxonomy, both accessible at the top level of the URL structure:

  • /{pagename}
  • /{city_term_slug}

But, achieving this requires a more nuanced approach than the standard rewrite rules.

In this post, I’ll guide you through my solution, which involved using a custom query parameter “page_or_city” and hooking into the pre_get_posts action to dynamically set the WordPress query (WP_Query) based on the existing slug.

Step-by-Step Tutorial

1. Adding a Custom Rewrite Rule:

First, we need to introduce a custom rewrite rule to capture the URL pattern. The add_rewrite_rule function is used to intercept URL requests and map them to WordPress’ query variables. In this case, we’re capturing any URL segment (denoted by ^([^/]*)/?) and forwarding it as a page_or_city query variable.

The ^([^/]*)/? regex captures any non-slash characters and passes them to index.php?page_or_city=$matches[1]. This tells WordPress to interpret the URL using the page_or_city parameter. The ‘top’ flag ensures this rule takes precedence over WordPress’s default rules. More about rewrite rules can be found in the WordPress Codex.

2. Registering the Custom Query Variable:

WordPress needs to know about custom query variables for them to be used within the WP_Query object. This is done using the query_vars filter.

Here, page_or_city is added to WordPress’s list of recognized query variables. The filter query_vars allows us to add, remove, or modify query variables before WordPress processes the URL query. For more information, see the query_vars filter documentation.

3. Modifying the Main Query Using pre_get_posts:

The pre_get_posts action hook is used to alter the main query before it is executed. We use this to change the query parameters based on our custom page_or_city variable.

This code first checks if the captured slug (page_or_city) corresponds to an existing page using get_page_by_path. If it finds a page, it sets the query to load that page. If not, it checks for a term in the ‘cities’ taxonomy using get_term_by. Depending on the result, it modifies the query parameters, either loading a page or a taxonomy archive. The pre_get_posts action is a powerful tool for altering query behavior and is well-documented in the WordPress Developer Resources.

Important: After adding or modifying these functions, you must visit the Permalinks settings page in WordPress and resave the settings to flush and regenerate rewrite rules.

Full Code

Conclusion

Working with WordPress’s URL structures for different types of content can be challenging, especially when they share the same pattern. By using a combination of add_rewrite_rule, custom query variables, and the pre_get_posts action, we can flexibly and efficiently handle overlapping URL patterns for various content types. This approach ensures that our website can handle URLs dynamically, offering a seamless user experience while maintaining the clarity and organization of our WordPress site.