Forum Moderators: phranque

Message Too Old, No Replies

wordpress mod rewrite - NOOB Failing Hard!

secondary custom rewrite rule for wordpress via .htaccess

         

frankstuner

4:13 am on Oct 28, 2011 (gmt 0)

10+ Year Member



Hi,

I'm trying to make a custom mod_rewrite rule for my wordpress installation, I've already got a custom rule for my page structure which i would like to preserve.

The new custom rule i'd like to make is whenever there's a get variable like: www.mysite.com/?profile=username

I want to make it look like: www.mysite.com/username

This is my current .htacces file:
# 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

I've looked at php.net and many tutorials about mod rewriting in general and specifically for wordpress, but its all just going straight over my head, I don't understand it.
If anyone could give me some help to get some progress with this i'd really appreciate, i really want to get my head around mod_rewrite.

I'm assuming i need to create a new RewriteRule, but that's as far as i get.

Thanks
Frank

g1smd

6:26 am on Oct 28, 2011 (gmt 0)

WebmasterWorld Senior Member 10+ Year Member Top Contributors Of The Month



The new custom rule i'd like to make is whenever there's a get variable like: www.mysite.com/?profile=username

I want to make it look like: www.mysite.com/username

Mod_rewrite cannot make URLs. Mod_rewrite cannot change URLs.

URLs are defined by what is in the links on your pages.

Mod_rewrite cannot change the links on your pages.

The first step is that you alter the PHP script so that the HTML pages it produces link out to the URL format that you want users to see and use.

The next step is to implement an internal rewrite such that when something asks for the URL
www.example.com/username
the rewrite alters the internal pointer to instead silently fetch conetent from
/index.php?profile=username
.

This rule will need to go ahead of the more general "catch all" rewrite that you already have.

The final step, and this one is optional, is that if an external user requests
example.com/index.php?profile=username
or
example.com/?profile=username
they are redirected to
www.example.com/username
. This rule goes at the top of the .htaccess file.

lucy24

8:28 am on Oct 28, 2011 (gmt 0)

WebmasterWorld Senior Member 10+ Year Member Top Contributors Of The Month



While you're in there:

<IfModule mod_rewrite.c>

Throw out this and any similar "if" lines. You either have mod_rewrite or you don't.

In general, "if" constructions are for people who get prepackaged software and are afraid to look at their htaccess, so it has to be written in the most generic terms possible. If you are working on your htaccess, one of the first steps is to find out whether you've got the module you're writing for.

Keep the "RewriteEngine on" line. It will occur just once, before all your Rewrites begin.

RewriteBase /

You can toss this too. / is the default.

RewriteRule ^index\.php$ - [L]

What is this rule supposed to do? It seems to say "If there's a request for the file 'index.php', start the whole Rewrite loop over again without changing anything."

RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d

More boilerplate. Toss it. Instead, write each of your RewriteRules so they will only apply to files or directories (very rarely both in the same Rule) that need rewriting; it actually doesn't matter whether they exist or not.

RewriteRule . /index.php [L]

"If the request consists of exactly one character, point them to 'index.php' and then start the whole Rewrite cycle over again." What is this intended to do?

g1smd

9:01 am on Oct 28, 2011 (gmt 0)

WebmasterWorld Senior Member 10+ Year Member Top Contributors Of The Month



RewriteRule ^index\.php$ - [L]
skips rewriting if the request (either externally or internally) was for
/index.php
. This is the same as adding
RewriteCond %{REQUEST_URI} !^/index.php
to the following ruleset. It prevents an infinite loop (actually, the -f and -d checks also do that, so in fact this "pre-check" for
index.php
stops the very slow and unwanted -f and -d checks running after the rewrite has completed, i.e. in the next pass through of the .htaccess file for the current request).

RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d

These checks are very slow and inefficient. There is much better code suggested over at WordPress Codex, but it was rejected for inclusion in the default WordPress file for several reasons. Many of the contributors over there don't understand the negative implications of the code they have in place right now.

RewriteRule . /index.php [L]
- this is the main rewrite to serve the content. It's not "single character". As the pattern is unanchored, it is "one or more". You could say .+ but the + isn't needed.

lucy24

8:23 pm on Oct 28, 2011 (gmt 0)

WebmasterWorld Senior Member 10+ Year Member Top Contributors Of The Month



As the pattern is unanchored

D'oh! Whoops.

I thought [L] meant "stop the current pass through mod_rewrite, go back to the beginning and start over". Except that in this case we are already at the beginning.

frankstuner

7:31 am on Oct 29, 2011 (gmt 0)

10+ Year Member



Hey,

Thanks for your replies, really appreciated.

I've changed the links on my pages to the website.com/username/ format and modified the .htaccess with what i thought might work but i'm really just walking around in the dark here.

It just threw back some 404 errors.

This is the updated .htaccess
# BEGIN WordPress
RewriteEngine On
RewriteRule ^index\.php$ - [L]
RewriteRule ^/([^/]+)$ ?profile=$1 [L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule . /verlete/index.php [L]
# END WordPress

Any further help would be appreciated.

Frank

lucy24

8:25 am on Oct 29, 2011 (gmt 0)

WebmasterWorld Senior Member 10+ Year Member Top Contributors Of The Month



RewriteRule ^/([^/]+)$ ?profile=$1 [L]


This rule will never match, unless you get a malformed URL that has two consecutive slashes after the domain name. In mod_rewrite, the leading slash is implied. To match a single extensionless term, like a username,

^([^./]+)$

Can we assume for the sake of sanity that there's some code elsewhere that prevents people from using . within their usernames?

frankstuner

8:37 am on Oct 29, 2011 (gmt 0)

10+ Year Member



Yes that assumption is correct, only alphanumeric characters are allowed. no symbols at all.

g1smd

5:54 pm on Oct 29, 2011 (gmt 0)

WebmasterWorld Senior Member 10+ Year Member Top Contributors Of The Month



RewriteRule ^/([^/]+)$ ?profile=$1 [L]


The leading slash is an error. I would also mention an explicit filename for the rewrite:

RewriteRule ^([^/.]+)$ /index.php?profile=$1 [L]


Finally, I would add the "." period to the character group, so that it matches only extensionless URL requests. Are you using extensionless URLs?

lucy24

11:20 pm on Oct 29, 2011 (gmt 0)

WebmasterWorld Senior Member 10+ Year Member Top Contributors Of The Month



^([^./]+)$
and
^([^/.]+)$
are technically the same, but g1's version may run a picosecond faster because your average request contains more slashes than periods ;)

frankstuner

8:46 am on Oct 31, 2011 (gmt 0)

10+ Year Member



I've just tried that alteration and its still returning 404 errors.

Have I done something wrong here?
This is the .htaccess:
# BEGIN WordPress
RewriteEngine On
RewriteRule ^index\.php$ - [L]
RewriteRule ^([^/.]+)$ ?profile=$1 [L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule . /index.php [L]
# END WordPress

lucy24

9:28 am on Oct 31, 2011 (gmt 0)

WebmasterWorld Senior Member 10+ Year Member Top Contributors Of The Month



Let's get some examples. Your Rule breaks down into three types of requests:

/index.php >> do nothing

/{anyoneword} >> rewrite as "index.php?profile={anyoneword} (note g1's suggestion that you give an explicit filename here: /index.php rather than nothing)

{anything that doesn't exist} >> /index.php

What kinds of requests lead to the 404 page? Diagnostics are trickier with Rewrites than Redirects because the address bar doesn't say where you've been rewritten to-- or even if you've been rewritten at all. (Neither do your raw logs. A Rewrite really is invisible.) But you can start by confirming that all three patterns lead to a 404. And then we can start picking it apart.

frankstuner

3:39 pm on Nov 4, 2011 (gmt 0)

10+ Year Member



This is the .htaccess at the moment.
# BEGIN WordPress
RewriteEngine On
RewriteRule ^index\.php$ - [L]
RewriteRule ^([^/.]+)$ index.php/?profile=$1 [L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule . /index.php [L]
# END WordPress

Is that index.php page specified correctly as per g1smd's recommendation?

The request address i'm using is like this:
myurl.com/username/

I've also tried myurl.com/profile/username to no avail.

But other pages are working for example:
myurl.com - index/homepage works
myurl.com/about/ - pages in the wordpress system work (sitemap, about, contact etc... all good)

So at the moment its just the profile rewrite that is returning the 404 error.

g1smd

4:42 pm on Nov 4, 2011 (gmt 0)

WebmasterWorld Senior Member 10+ Year Member Top Contributors Of The Month



^([^/.]+)$
- requested path must not contain any slashes or periods -
example.com/username/
and
example.com/profile/username
will not match! You'll need
^profile/([^/.]+)$
here.

index.php/?profile=$1
- is looking for an
index.php
file inside a folder also called
index.php
- the slash is in the wrong place. You'll need
/index.php?profile=$1
here.

frankstuner

5:57 pm on Nov 4, 2011 (gmt 0)

10+ Year Member



So this is what I got now:
# BEGIN WordPress
RewriteEngine On
RewriteRule ^index\.php$ - [L]
RewriteRule ^([^/.]+)$ /index.php?profile=$1 [L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule . /index.php [L]
# END WordPress

for the url:
mysite.com/username/

Its still returning the 404.

when you said my "requested path must not contain any slashes or periods" do you mean the username? cause they definately are letters and numbers only.

g1smd

6:00 pm on Nov 4, 2011 (gmt 0)

WebmasterWorld Senior Member 10+ Year Member Top Contributors Of The Month



do you mean the username? cause they definately are letters and numbers only

The example username URL you quoted ends with a slash.

^([^/.]+)$
- pattern says "requested path must not contain any slashes or periods".

example.com/username
would match, but I really do advise you have usernames in a /profile/ folder.

frankstuner

10:54 pm on Nov 5, 2011 (gmt 0)

10+ Year Member



It works! Thanks so much for your help, very much appreciated.

Just out of interest, do you recommend using the /profiles/username directory because of SEO?

g1smd

11:17 pm on Nov 5, 2011 (gmt 0)

WebmasterWorld Senior Member 10+ Year Member Top Contributors Of The Month



No. I recommend it so that you can be sure that your pattern matches only valid user name requests and does not interfere with the normal running of the site.

I do remember a thread long ago where usernames were shown as root URLs and the RegEx pattern that was used allowed a user to sign up with a user name of "robots.txt" or "favicon.ico" and be a valid user.

frankstuner

3:12 pm on Nov 8, 2011 (gmt 0)

10+ Year Member



Ahh yes I see what you mean.
At the moment username's can only contain letter and numbers, so no periods. That should prevent this from being an issue i think.