Master the WordPress Rewrite API to gain total control over your site's URL structure. Learn how WP_Rewrite maps requests to content without the headache.

I remember sitting at my desk three years ago, staring at a "404 Not Found" page for an hour because I’d tried to force a custom URL structure into a client's site using simple $_GET parameters. I thought I was being clever, but I was just fighting the system. Once I finally sat down and actually dug into the WordPress Rewrite API, I realized that URL routing isn't magic—it's just a sophisticated regex parser.
When a user hits your site, WordPress doesn't just look for a file named about-us.php. It looks for a match in its rewrite rules. If you've ever wondered how WordPress permalinks work under the hood, you’re essentially asking how the global WP_Rewrite object converts human-readable strings into the database queries that WP_Query Explained: How WordPress Fetches Your Content eventually executes.
At the heart of everything is the WP_Rewrite class. When you change your permalink settings in the dashboard, WordPress updates the rewrite_rules option in your database. This is a massive associative array where the keys are regular expressions and the values are query strings.
Think of it like this:
example.com/portfolio/web-design/.rewrite_rules array. It finds a regex that matches portfolio/([^/]+)/?.web-design) and maps it to a query variable, usually something like portfolio_cat=web-design.$wp_query object based on those variables and fetches the content.We first tried to build a custom routing system by hacking the .htaccess file directly. It felt like a good idea until we realized that every time we pushed a plugin update or a user saved their permalink settings, WordPress wiped our manual rules. It took about two days of refactoring to realize we should have been using add_rewrite_rule() all along.

If you need to create custom URL structures—like /events/2023/october/—you don't need to touch the server configuration. You can do it all through the API.
Here is a basic example to register a custom rule:
PHPfunction my_custom_rewrite_rules() { #6A9955">// Map /portfolio/%name%/ to index.php?portfolio_slug=%name% add_rewrite_rule( '^portfolio/([^/]+)/?', 'index.php?portfolio_slug=$matches[1]', 'top' ); } add_action('init', 'my_custom_rewrite_rules'); function my_custom_query_vars($vars) { $vars[] = 'portfolio_slug'; return $vars; } add_filter('query_vars', 'my_custom_query_vars');
Crucial note: After you add this code, you must flush your rewrite rules. You can do this by visiting the Permalinks settings page in the dashboard. Don't run flush_rewrite_rules() on every page load; it’s an expensive operation that hits the database and rebuilds the entire rules array.
While the API handles the logic, WordPress still needs to hand off the request. On Apache servers, WordPress uses .htaccess generation to force all traffic through index.php.
If you're hosting on NGINX, you don't get an .htaccess file. Instead, your server configuration (or Kubernetes Ingress: NGINX vs Gateway API for Traffic Routing) must be configured to pass requests to the PHP-FPM processor. WordPress generates the rules, but the web server performs the initial interception.

'top' as the third argument in add_rewrite_rule is usually safer. It places your rule at the beginning of the array, ensuring it’s checked before WordPress's default rules.I’m still occasionally tripped up by complex regex patterns. If I’m dealing with something particularly hairy, I use a plugin like "Rewrite Rules Inspector" to visualize the array. It saves me from guessing which rule is actually catching my request.
Next time, I’d probably spend more time validating the input parameters before they hit the database. It’s easy to get the URL routing working, but sanitizing the $matches from your rewrite rules is a step most developers skip until it's too late. The WordPress Rewrite API is powerful, but like any engine, it needs to be maintained.
Do I need to flush rewrite rules every time I change my code? Yes, but only during development. Use the "Permalinks" settings page in the dashboard to trigger a flush manually.
Why is my custom URL returning a 404?
Usually, it’s because the query_vars filter wasn't updated to recognize your custom variable, or the rewrite rules haven't been flushed.
Can I use the Rewrite API for REST routes? While you can, you shouldn't. If you're building a headless application, Extending the WordPress REST API with Custom Endpoints is a much more robust and standard way to handle data fetching.
WordPress database structure demystified. Learn how the wp_options table and WordPress metadata tables manage your site's data for better performance.