TransWikia.com

Custom Rewrite Rule Removing Query String

WordPress Development Asked by appshine on November 28, 2021

I’m trying (and failing) to use rewrite rules to redirect shorter/prettier URLs to the right page AND include values in the query string.

WP is installed at https://example.com, and the plugin creates a page called ‘foo’ which uses a value ‘bar’ passed in the query string to generate the content from custom database tables.

So an example full URL would be:

https://example.com/foo/?bar=XXXXXX

The ‘bar’ value would always be a string of between 6 and 8 alphanumeric chars with at least 1 dash(-).

I want to use rewrite rules (but am open to other suggestions) so that a shorter URL can be used, such as:

https://example.com/f/XXXXXX

I have tried using add_rewrite_rule as follows:

function jr_rewrite_add_rewrites(){
    add_rewrite_rule(
            'f/([[:ascii:]]+)/?$', 
            '/index.php?pagename=foo&bar=$matches[1]',
            'top'
        );
}

add_action( 'init', 'jr_rewrite_add_rewrites');

And, when I flush the rewrite rules by clicking save on the Permalinks Settings page in the Dashboard, the rule is added to the htaccess file just fine:

# BEGIN WordPress
# The directives (lines) between `BEGIN WordPress` and `END WordPress` are
# dynamically generated, and should only be modified via WordPress filters.
# Any changes to the directives between these markers will be overwritten.
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteBase /
RewriteRule ^index.php$ - [L]
RewriteRule ^f/([[:ascii:]]+)/?$ /index.php?pagename=foo&bar=$matches[1] [QSA,L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule . /index.php [L]
</IfModule>

# END WordPress

However, when I try to access:

https://example.com/f/XXXXXX

the page is just redirected to:

https://example.com/foo/

and is missing the needed bar=XXXXXX querystring so the relevant content does not load.

Can anyone please point out where I am going wrong wiht this or suggest an alternative?

2 Answers

In addition to what mozboz helpfully suggested above, I was able to use Wordpress's rewrite functoinality to make things work by using add_rewrite_tag() to recognise the bar variable and also get_query_var() to access the value rather than trying to access $_GET['bar'].

So the code I ended up with was:

function foobar_rewrite_rules(){
        add_rewrite_tag(
            '%bar%',
            '(.{6})'
        );

        add_rewrite_rule(
            '^f/(.{6-8})$',
            'index.php?pagename=foo&bar=$matches[1]',
            'top'
        );
}

add_action( 'init', 'foobar_rewrite_rules');

and then, because the page needed to work whether using the 'pretty' URL or the 'ugly' one with the full page address and query strings intact, I just had to check and choose between the $_GET version and the get_query_var() version as follows:

$bar_value = (empty($_GET['bar'])) ? (get_query_var('bar', FALSE)) : ($_GET['bar']) ;

So glad to have gotten this working, thanks for the help!

Answered by appshine on November 28, 2021

Two parts to this answer:

  1. There are multiple things going wrong with your current example, and some of them are caused by Wordpress's rules making things more complicated. If you don't mind editing your .htaccess file directly, try this. It avoids having to deal with some Wordpress magic that isn't making things easier here. It should do what you want, or be close enough that you can tweak it to do what you want:
    <IfModule mod_rewrite.c>
        RewriteEngine On
        RewriteRule ^f/(.{6-8})$ foo/?bar=$1 [NC,L]
    </IfModule>

You'll need to remove your plugin code, remove the line that's in .htaccess (although I guess this should happen automatically), and add this above the Wordpress section

Note, this isn't a redirect. The URL in the browser won't change, but the URL that PHP sees 'behind the scenes' will be the rewritten one.

  1. If you're interested to try to fix this still using add_rewrite_rule() there are a few things that need fixing. Here's an updated try, although I can't easily test this:
    add_rewrite_rule(
            '^f/(.{6-8})$', 
            'index.php?pagename=foo&bar=$matches[1]',
            'top'
        );
  • Don't escape /
  • Remove leading / on index.php (this is possibly why it got added as a rule in .htaccess instead of running in Wordpress itself, which it should have)
  • Remove unneccessary /?
  • Make it specifically 6-8 characters as per your post
  • Simplify the matched character to . (any character). You could make this e.g. [a-zA-Z0-9] if you want to limit to those characters as that's explicit and clear

The other thing here is are you 100% sure that pagename=foo is the correct way to arrive at this URL. I'm not sure if that's how index.php works so you'd need to check that.

Answered by mozboz on November 28, 2021

Add your own answers!

Ask a Question

Get help from others!

© 2024 TransWikia.com. All rights reserved. Sites we Love: PCI Database, UKBizDB, Menu Kuliner, Sharing RPP