In this instance, I had a client site with static HTML files in the root and a WordPress blog in the /wordpress/ folder. The old site was using the classic ‘website.tld/?p=123’ URL format, where ‘123’ is the ID of the post.
In the rebuild, the point was three fold:
- Get all the static HTML pages into WordPress and editable;
- Give the blog posts a more useful SEF URL structure; and
- Move everything into the domain root (not down in a /wordpress/ folder).
Luckily for me, WordPress does a good job at matching that ‘123’ ID with the new ‘/2015/12/20/fancy-post-stub/’ structure all on its own—if only the query was looking in the correct directory!
A simple ‘RewriteRule ^wordpress/(.*)$ /$1 [R=301,L]’ in your .htaccess file should work, right? Nope! The trouble is, because the old URL is a query string, you need to detect the query as its own string, then append it to your new URL.
In .htaccess, see my last three lines:
# BEGIN WordPress <IfModule mod_rewrite.c> RewriteEngine On RewriteBase / RewriteRule ^index\.php$ - [L] RewriteCond %{REQUEST_FILENAME} !-f RewriteCond %{REQUEST_FILENAME} !-d RewriteRule . /index.php [L] </IfModule> # END WordPress RewriteCond %{QUERY_STRING} ^p=([0-9]+)$ RewriteRule ^wordpress/?$ http://website.tld/?p=%1 [R=301,L] RewriteRule ^wordpress/$ http://website.tld [R=301,L]
Voila!
Closing thoughts:
- This setup allows me to keep the old /wordpress/ directory with all of its uploaded media files, so I don’t have to create redirects for any linking that’s already out there. For that, I deleted everything else from that directory, aside from anything in /wordpress/wp-content/uploads/.
- You’ll notice I also specified as much of the query string as possible and restricted the value to numbers only—i.e., ‘p=([0-9]+)’ rather than being lazy with ‘(.*)’ for the whole thing. This was more for future thinking, in case there was something else I needed to redirect for some reason, and to have it point elsewhere. It was also because I like my regular expressions to be as specific as possible for best practice, to prevent unintended consequences. I know the IDs are numbers only, so I’m only accepting numbers.
- Lastly, I added the catch-all for the /wordpress/ directory to redirect to the root if nothing follows it. Note the $ is the end of the string, so my ‘/wordpress/wp-content/uploads/something/’ URLs still go untouched.
Hopefully this is helpful to the Internet. I’m pretty good with mod_rewrite, but this was something I had to troubleshoot because I’d not used {QUERY_STRING} before.