I want to create clean URLs for my WordPress site that let me change post titles without breaking links. I’m looking for a way to set up URLs where WordPress only uses the numeric ID to find the post, ignoring everything else in the URL path.
My goal is to have URLs like these all point to the same article (let’s say post ID 789):
Basically I want the same behavior as many popular sites where you can change the text part of the URL and it still works as long as the ID is correct.
I’ve been trying different approaches with my htaccess file but can’t get it working:
RewriteEngine on
RewriteBase /
# Standard WordPress rules
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule . /index.php [L]
# My attempt at custom routing
#RewriteRule ^([0-9]+)/?([a-zA-Z0-9\-]+)/?$ index.php?p=$1 [QSA]
The custom rule doesn’t seem to work when I uncomment it. Has anyone successfully implemented this type of flexible URL structure in WordPress?
WordPress processes its own rewrite rules before hitting your custom htaccess rules - that’s your problem. I fixed this by creating a plugin that hooks into the query parsing stage. Use the request filter to catch URLs with that numeric pattern and override the query variables before WordPress tries matching its standard permalink structure. Here’s what works: make a small plugin that detects when the first URL segment is numeric, then force WordPress to treat it as a post ID lookup no matter what comes after. This skips permalink matching completely. Unlike the functions.php method, you’re intercepting the actual query parsing instead of just adding rewrite rules that might clash with existing ones. Way more reliable than messing with rule precedence in htaccess or the rewrite API.
You’re fighting WordPress instead of working around it. I hit this same problem on a project where we needed bulletproof URLs that survived content updates.
I built automation that sits outside WordPress completely. When someone hits those flexible URLs, it intercepts the request before WordPress even sees it, grabs the ID, validates against the database, and serves the right content.
You can handle redirects, caching, and A/B testing without WordPress permalink headaches. I used Latenode since it connects directly to your database and processes requests in milliseconds. No plugin conflicts or rewrite rule priorities to mess with.
Just set up a webhook that catches the URL pattern, parses the ID, queries your posts table, and either serves content or redirects to the canonical URL. Works every time and scales way better than PHP solutions.
Your htaccess rule needs to go before WordPress’s rules, not after. Move your custom rule above the WordPress block and tweak the syntax:
RewriteEngine on
RewriteBase /
# Custom ID-based routing - must come first
RewriteRule ^([0-9]+)(/.*)?/?$ index.php?p=$1 [QSA,L]
# Standard WordPress rules
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule . /index.php [L]
Main changes: moved it above WordPress rules, added the L flag so it stops processing when matched, and fixed the regex to better catch optional trailing paths. I’ve used this exact setup on client sites where SEO teams constantly change URLs but old ones still need to work. Just test on staging first - htaccess changes can break things fast.
yep, totally feel you on that! wordpress does prioritize its own rules so your custom ones can get overlooked. a couple of things to try: flush_rewrite_rules() right after your rule or just hit the permalinks page once to refresh. oh, and make sure your rule is above the standard ones!
been there! wordpress caching plugins can mess with custome rewrites. try disabling any caching (w3 total cache, wp rocket, etc.) while testing your rules. also check if your host has server-level caching - it might be serving old versions of your .htaccess changes.
I faced a similar challenge when implementing custom URLs for posts. While using .htaccess is common, the internal handling by WordPress is essential here. You should add a custom rewrite rule directly in your theme’s functions.php. For instance:
function custom_id_rewrite_rule() {
add_rewrite_rule('^([0-9]+)/?(.*)$', 'index.php?p=$matches[1]', 'top');
}
add_action('init', 'custom_id_rewrite_rule');
Importantly, after updating this rule, remember to flush the rewrite rules via Settings > Permalinks by clicking Save Changes. This step is crucial for the new rules to take effect. In my experience, this method has worked seamlessly, allowing WordPress to disregard the additional text while still processing the post ID. Just make sure to back up your site first to avoid any mishaps.
WordPress’s query parsing is probably running before your custom logic kicks in. I hit this exact issue migrating from an old CMS with numeric URL IDs. What fixed it was using the parse_request action hook instead of rewrite rules. Write a function that checks if the first URL segment is numeric, then directly set the query variables to load that post ID. This skips the whole permalink matching system. In your functions.php: hook into parse_request, use regex to grab the numeric ID from REQUEST_URI, then manually set the query vars for that post. WordPress never tries matching its standard permalink patterns because you’re intercepting during request parsing. Way cleaner than wrestling with htaccess precedence and rewrite conflicts.