Beautify Query Strings with Rewrites

Sometimes I’ll work on something just to see what it looks like when it’s done. I guess this Apache rewrite might be something like that — I wanted to change the WordPress search query from /?s=value to /s/value, just to make the URL look a little prettier. :) There are probably a few ways to do this, and if you’d like to share some alternatives, feel free to post a comment.

There are two parts to this problem; The first, executing a search query from an /s/value URL, is easily addressed by a rewrite and proxy command. The second problem — how to rewrite a regular search query, but not a proxied search query — is a little tricker. I decided to add an htproxy hostname to my domain with an IP of 127.0.0.1. Then in a rewrite condition, I check for the htproxy hostname, and skip the rewrite if it’s a proxied request. The htproxy hostname must be included in the website’s Apache config as a ServerAlias.


# rewrite-search.conf
# Beautify WordPress search query string with rewrites.
# by Jean-Sebastien Morisset (https://surniaulula.com/)

# sets %{server_name} to config value instead of %{http_host} value
UseCanonicalName On

# if not proxied, rewrite the wordpress search query as a path string
RewriteCond %{HTTP_HOST} !^htproxy\.
RewriteCond %{QUERY_STRING} ^s=([^&]+)&?(.*)$
RewriteRule ^/$	http://%{SERVER_NAME}/s/%1?%2 [noescape,redirect=permanent,last]

# if there's a search string in the path, then proxy the search query
RewriteRule ^/s/(.*)$ http://htproxy.%{SERVER_NAME}/?s=$1&%{QUERY_STRING} [proxy,last]

I’ve set UseCanonicalName to on so %{SERVER_NAME} will be a known fixed value. The alternative might have been to hardcode the complete host and domain name in the rewrite rules, but then I couldn’t have shared this code (as-is) between multiple websites.

I would have liked to make the RewriteCond %{HTTP_HOST} !^htproxy\. rewrite condition less generic, by using htproxy.%{SERVER_NAME} for example, but Apache refused to cooperate (might be a bug). I also tried using the %{HTTP_PROXY_CONNECTION} variable, but couldn’t find enough information on it to make it work. A test that wasn’t based on the hostname would have allowed me to skip the use of a dedicated hostname to accept proxy requests.

Find this content useful? Share it with your friends!