
Open Settings > Permalinks in any WordPress install and you are looking at one of the most consequential screens in the dashboard. The radio buttons look trivial, but the structure you pick becomes the address of every post you ever publish. Most advice stops at "use Post name and move on" — which is correct, but it skips the part that actually bites people later: how these URLs are generated, what happens to them when you switch, and where the wheels come off. This article is about the machinery, not just the recommendation.
WordPress does not store a file called /my-post/ anywhere. Every front-end request hits a single PHP entry point, and WordPress decides what to render by parsing the URL against a set of rewrite rules — an array of regular expressions mapping URL patterns to query variables. A request for /my-post/ gets matched and internally rewritten to something like index.php?name=my-post. The "ugly" query string never disappears; it is just hidden from the visitor.
The piece that makes the pretty URL reach index.php in the first place lives at the web-server layer, and it differs by stack:
mod_rewrite and an .htaccess file in your web root. When you save a non-default permalink structure, WordPress writes a small block between # BEGIN WordPress and # END WordPress markers that funnels any request not matching a real file or directory into index.php..htaccess. The equivalent is a try_files $uri $uri/ /index.php?$args; directive in the server block. This is why managed hosts like Kinsta, WP Engine, and Cloudways (all nginx-based) ship this rule preconfigured — and why a plugin that claims it can "fix your permalinks by editing .htaccess" does nothing on those hosts. There is no .htaccess for it to touch.So pretty permalinks are a two-layer system: the server hands every clean URL to WordPress, and WordPress's internal rewrite rules turn that URL back into a query. Understanding this split explains nearly every permalink bug you will ever hit.
WordPress caches the compiled rewrite rules in the rewrite_rules row of the wp_options table. It does not rebuild them on every request — that would be wasteful. It rebuilds (flushes) them when something forces it to, most notably when you visit Settings > Permalinks and click Save Changes. That is the entire reason the folk remedy "just go to Permalinks and hit Save" fixes so many 404s after a migration or a plugin change: you are flushing the rule cache.
This matters most when you register a custom post type or a custom taxonomy. Their rewrite rules only exist after a flush. If you add a CPT and its archive throws a 404, you have not broken anything — you simply have not flushed. In code the call is flush_rewrite_rules(), and the correct place for it is the plugin or theme activation hook, never on every page load, because flushing is expensive.
The custom structure field accepts tokens like %postname%, %year%, %monthnum%, %day%, %category%, %author%, and %post_id%. Two are worth a specific warning:
%category% embeds the category slug in the URL. The operational cost is not abstract: when a post belongs to multiple categories, WordPress picks one (lowest ID) for the URL, and recategorizing a post changes its permalink. On a site that reorganizes its taxonomy as it grows, this generates a steady trickle of broken URLs that you must redirect.%postname%" warning you may have read is legacy. Before WordPress 3.3 (released in 2011), a structure starting with %postname% forced a slow, verbose rewrite ruleset because WordPress could not distinguish a post URL from a page URL cheaply. That performance penalty was fixed over a decade ago. In 2026 you can safely lead with %postname%; treat the old warning as historical, not current guidance.WordPress decides the trailing slash for you based on whether your structure ends in a slash, and then it 301-redirects the other form to the canonical one. If your structure is /%postname%/, a request to /my-post redirects to /my-post/. This is handled by the canonical redirect function and is good for SEO because it prevents two URLs serving identical content. The practical takeaway: do not fight it, and do not hand-build internal links in the non-canonical form, or every one of them eats a needless redirect hop.
For sites with multiple content types — a recipe site, a course platform, a case-study library — the clean URLs come from the rewrite argument in register_post_type(). Two keys do the heavy lifting:
'slug' => 'recipes' sets the base segment, producing /recipes/chocolate-cake/.'with_front' => false strips your global permalink prefix from the CPT URL. If your blog runs on /blog/%postname%/ and you leave with_front at its default true, your recipes inherit the prefix and become /blog/recipes/chocolate-cake/ — almost never what you want.Choose these slugs deliberately, because changing a CPT slug later invalidates every URL for that type at once. And remember the flush: after registering or changing a CPT's rewrite args, you must flush rewrite rules (re-save Permalinks, or run the activation flush) or the new URLs will 404.
Changing the permalink structure on a published site is genuinely expensive, which is why "pick it correctly on day one" is the real advice. If you must migrate, the work is concrete and tool-specific:
/%year%/%monthnum%/%postname%/ to /%postname%/ — a single regex RewriteRule in .htaccess can cover the whole set at the server layer, which is faster than per-URL database lookups but unforgiving if your old URLs were not perfectly uniform.UPDATE.Expect a temporary dip while search engines reprocess the URLs, and budget real hours for QA — broken internal links and missed redirects are where these projects actually go wrong, not the permalink setting itself.
For the overwhelming majority of sites, /%postname%/ remains the right call in 2026: it is clean, it decouples the URL from dates and categories, and it survives editorial reorganization without generating redirects. Reach for a date-based structure only when publication date is part of the content's identity (a news desk), and reach for %category% only when your taxonomy is genuinely stable and meaningful in the address bar. Whatever you choose, set it before you publish, register your custom post types with intentional slugs and with_front => false, and remember that almost every "my URLs are 404ing" panic is solved by flushing the rewrite rules.
Site
Tools
We do not sell your email. We do not spam.
© 2026 RevealTheme. All rights reserved.