Forum Moderators: phranque

Message Too Old, No Replies

Rewrite WordPress permalink

         

Murasaki

4:23 am on Feb 7, 2009 (gmt 0)

10+ Year Member



Hi,

I'm having trouble with url rewrite. I'm using WordPress with pretty permalink turned on and I'm trying to rewrite /category/xyz/ to /blog/category/xyz/.

I've tried using either one of the following rules but neither works. And somehow it works when I tried R=301 redirect.

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

RewriteRule ^blog/category/([^/]+)/$ /category/$1/ [L]

What is it that I'm doing wrong? And how come it works when I do R=301?
Thanks in advance.

jdMorgan

3:20 pm on Feb 7, 2009 (gmt 0)

WebmasterWorld Senior Member 10+ Year Member



Please define "works" and "doesn't work" -- You have given no indication of what the problem is.

  • How did you test (what URLs did you type)?
  • What were the results (on-screen, server access log, server error log)?
  • How did those results differ from what you expected?

    The most common problem when rewriting from a "virtual directory" URL to a different directory-level path is that on-page links to images, CSS, and JavaScript files will not work if those links are given in page-relative format. This is because it is the client (e.g browser) which resolves relative links, and the browser thinks that those objects will be located relative to the directory (in this example "/blog/category/<something>/" in its address bar. So those page-relative links won't be resolved correctly.

    The simplest way to fix this problem is to use server-relative or canonical links; That is, use <img src="/images/logo-gif"> or <img src="http://www.example.com/images/logo-gif"> instead of <img src="images/logo-gif">

    Jim

  • Murasaki

    5:05 pm on Feb 7, 2009 (gmt 0)

    10+ Year Member



    Sorry for the unclear post. I've also noticed a mistake in my first post.

    I wanted to modify the wordpress permalink structure and I've tried it with 2 different rules:

    1. Rewrite to wordpress permalink, /blog/category/xyz/ to /category/xyz/
    RewriteRule ^blog/category/([^/]+)/$ /category/$1/ [L]

    2. Rewrite to query string, /blog/category/xyz/ to /index.php?=category_name=xyz
    RewriteRule ^blog/category/([^/]+)/$ /index.php?category_name=$1 [L]

    I've tried typing the url (http://mydomain.com/blog/category/xyz/) in the address bar as well as linking it in html (both href="/blog/category/xyz/" and href="mydomain.com/blog/category/xyz/"), but all I get is 404 Not Found.

    I then tried redirecting by adding R=301 to both rules to double check if there was anything wrong and somehow both worked, meaning it redirected to the page that I wanted it to display.

    So my questions are:
    1. What am I doing wrong?
    2. How come it works when redirecting but not rewriting?

    Thanks!

    jdMorgan

    5:45 pm on Feb 7, 2009 (gmt 0)

    WebmasterWorld Senior Member 10+ Year Member



    Look at your server error log (not the access log), and note the filepath that is being referenced as non-existent. It is likely that your server is configured to inject extra path information (i.e. an additional directory level or two) into the filepath when the resource is referenced as a URL (i.e. when you externally redirect) instead of as a server-root-relative filepath (when you internally rewrite). If this is the case, then you will need to note the extra path information, and include it using a RewriteBase directive at the top of your code (just after "RewriteEngine on".

    I'm not sure why some servers are set up this way, but some are. I see it as an error in the DocumentRoot specification, but there must be some plausible reason why hosts do this.

    Jim

    g1smd

    6:47 pm on Feb 7, 2009 (gmt 0)

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



    RewriteRule ^blog/category/([^/]+)/$ /category/$1/ [L]

    I would assume that rule is back to front (as coded it only works if user requests "example.com/blog/category/foo and server tries to get the content from /category/foo inside the server), but as jd notes you need to be very clear as to which bit represents an external URL and which is the server filepath. Infact, if you are wanting to use a new URL for the content, shouldn't the target of your rewrite be a dynamic internal filepath like /index.php?category_name=$1 or something.

    A rewrite works like this:

    RewriteRule "what-the-user-requested" "where-it-is-inside-the-server" [L]

    Murasaki

    7:05 pm on Feb 7, 2009 (gmt 0)

    10+ Year Member



    @jdMorgan
    I couldn't find the server error log but I think you're right about the extra path info. I've just tried the same rewrite rule on another host and it worked just the way i wanted it.

    @g1smd
    The /category/$1/ is the permalink structure from wordpress and I was just trying to see if it would work that way instead of a query string. I also had a rule that rewrite to query string in case it didn't work.

    Anyway, I got it working on another host so its all good now. Thanks for the replies.

    [edited by: Murasaki at 7:19 pm (utc) on Feb. 7, 2009]

    Murasaki

    8:00 pm on Feb 7, 2009 (gmt 0)

    10+ Year Member



    I've just realised that I've made a mistake when I tried it on another host... I had a different permalink setting on that wordpress installation which has the exact permalink that I wanted for the category case so I thought it worked for both /blog/category/xyz/ to /index.php?=category_name=xyz and /blog/category/xyz/ to /category/xyz/.

    I've fixed the wordpress settings and now I'm getting the same result as before (Page not found).

    I'm a little curious though. If it's extra path injected by the server that is causing the problem, then how come it works for R=301 but not rewrite?

    [edited by: Murasaki at 8:01 pm (utc) on Feb. 7, 2009]

    jdMorgan

    8:46 pm on Feb 7, 2009 (gmt 0)

    WebmasterWorld Senior Member 10+ Year Member



    Actually, I answered that question above, and it's not easy to re-state in other terms.

    If you cannot get the server error logs, then to be blunt, you need a new Web host. If you are going to be getting into technical things like mod_rewrite, you need a host that supports basic debugging resources like error logging. Otherwise, you will spend far more time than the savings of a "cheap host" will compensate for.

    Go back to your external redirect rule temporarily, and modify it like this:

    RewriteRule ^blog/category/([^/]+)/$ http://www.example.com/test?DocumentRoot_plus_URL-path=%{DOCUMENT_ROOT}%{REQUEST_URI}&Request_Filename=%{REQUEST_FILENAME} [R=302,L]

    Request your /blog/category/xyz/ URL, ignore the resulting 404 error, and report back here with the test query string values that you see in the browser address bar.

    We are simply using a bogus URL-path ("test") and some temporary query string name/value pairs to get the server to tell us where in the filesystem it is trying to find files.

    I specified a 302 redirect so that if search engine spiders come around while this rule is in place, they will recognize it as a temporary redirect, and not screw up your search listings by listing this test URL in search results... (!)

    Jim

    Murasaki

    2:44 pm on Feb 9, 2009 (gmt 0)

    10+ Year Member



    Jim,

    I took your advice and got a new host. I had a look inside the error log and these are all I found that has /blog/category/.../ in them. I don't think these errors are from the rewrite rule though. It doesn't seem like the error log records it when I get a page not found. I don't know what the reason is but I could only guess that it's because of wordpress. It goes to the custom 404 page, and if I delete that custom 404 page it goes to index.

    [Mon Feb 09 05:07:24 2009] [error] [client 124.171.xx.xx] File does not exist: /home/yoakenij/public_html/404.shtml, referer: http://example.com/blog/category/uncategorized/
    [Mon Feb 09 05:07:24 2009] [error] [client 124.171.xx.xx] File does not exist: /home/yoakenij/public_html/2009, referer: http://example.com/blog/category/uncategorized/

    I've tried that rule you suggested in your previous reply and this is what I got:
    http://example.com/test?DocumentRoot_plus_URL-path=/home/yoakenij/public_html/blog/category/uncategorized/&Request_Filename=/home/yoakenij/public_html/blog/category

    I've also tried adding the rewrite rule through wordpress according to their documentation but that didn't work out either.

    I don't know if this helps but when I turned off permalink in wordpress and used the original rule (RewriteRule ^blog/category/([^/]+)/$ /?category_name=$1 [L]), the rewrite worked.

    Thanks
    Joe

    [edited by: eelixduppy at 12:56 am (utc) on Feb. 10, 2009]
    [edit reason] exemplified [/edit]

    Murasaki

    2:50 pm on Feb 9, 2009 (gmt 0)

    10+ Year Member



    I just had a thought after typing that last reply. Maybe I should just turn off permalink in wordpress and do the whole site manually...

    [edited by: Murasaki at 3:33 pm (utc) on Feb. 9, 2009]

    jdMorgan

    8:16 pm on Feb 9, 2009 (gmt 0)

    WebmasterWorld Senior Member 10+ Year Member



    As shown by the temporary query string data, you've got some other rule --or perhaps mod_negotiation or AcceptPathInfo-- that is stripping the "/uncategorized" from the filepath...

    Please post all of your rules (after changing your domain name to "example.com"), and tell us what version of Apache you are using.

    Jim

    Murasaki

    10:48 pm on Feb 9, 2009 (gmt 0)

    10+ Year Member



    My apache version is 2.2.11 (Unix)

    <IfModule mod_rewrite.c>
    RewriteEngine On
    RewriteBase /

    ### SEARCH ###
    RewriteCond %{THE_REQUEST} ^[A-Z]{3,9}\ /(index\.php)?\?s=(.+)?\ HTTP/
    RewriteRule ^(index\.php)?$ /search/%2/? [R=301,L]
    # Add a trailing slash
    RewriteRule ^search/([^/]+)$ /search/$1/ [R=301,L]

    #RewriteCond %{THE_REQUEST} ^[A-Z]{3,9}\ /(index\.php)?\?category_name=([^/]+)\ HTTP/
    #RewriteRule ^(index\.php)?$ /blog/category/%2/? [R=301,L]
    #RewriteRule ^blog/category/([^/]+)/$ /?category_name=$1 [L]

    RewriteRule ^blog/category/([^/]+)/$ http://example.com/test?DocumentRoot_plus_URL-path=%{DOCUMENT_ROOT}%{REQUEST_URI}&Request_Filename=%{REQUEST_FILENAME} [R=302,L]

    # BEGIN WordPress
    RewriteCond %{REQUEST_FILENAME} !-f
    RewriteCond %{REQUEST_FILENAME} !-d
    RewriteRule . /index.php [L]
    # END WordPress

    </IfModule>

    Thanks
    Joe

    [edited by: jdMorgan at 2:47 pm (utc) on Feb. 10, 2009]
    [edit reason] example.com [/edit]

    jdMorgan

    2:45 pm on Feb 10, 2009 (gmt 0)

    WebmasterWorld Senior Member 10+ Year Member



    I don't see a rule that corresponds to your stated goal:
    I'm having trouble with url rewrite. I'm using WordPress with pretty permalink turned on and I'm trying to rewrite /category/xyz/ to /blog/category/xyz/.

    This rule

     RewriteRule ^blog/category/([^/]+)/$ /?category_name=$1 [L] 

    Rewrites any request for /blog/category/xyz to /?category_name=xyz. That is, it will rewrite either a client or an internal request for the URL-path /blog/category/xyz to the DirectoryIndex file at the root of your site (your "home page") as defined by DirectoryIndex, with a query string of "xyz".

    When discussing mod_rewrite, it is critical to identify and state the requested URL (the linked URL that the browser requests) and the internal filepath that you want the server to associate with that URL. That is not clear here, and it's impossible to work with this stuff if both of those paths are not clearly identified.

    So, please re-read what I wrote about what that rule does, and note the use of the terms "URL-path" and "file." Is that what you wanted?

    Also, be aware that your 404 page won't be used at all; Any request for any URL that does not resolve to an existing file will be passed to your WordPress script, and wordpress must be configured to properly identify URLs for which it can or cannot return the correct content. If it cannot return correct content for the requested URL, then WordPress itself must issue a 404 response code and the contents of a "404 page" for the user to read.

    Jim

    [edited by: jdMorgan at 2:47 pm (utc) on Feb. 10, 2009]

    Murasaki

    3:49 pm on Feb 10, 2009 (gmt 0)

    10+ Year Member



    I'm having trouble with url rewrite. I'm using WordPress with pretty permalink turned on and I'm trying to rewrite /category/xyz/ to /blog/category/xyz/.

    I'm sorry I should have edit it. That was a mistake and I corrected in my second post. Sorry for the confusion.

    My original goal when I started this topic was to use either
    RewriteRule ^blog/category/([^/]+)/$ /?category_name=$1 [L]
    to rewrite /blog/category/xyz/ to /?category_name=xyz
    or,
    RewriteRule ^blog/category/([^/]+)/$ /category/$1/ [L]
    to rewrite /blog/category/xyz/ to /category/xyz/

    I included that second rule because with permalink turned on, wordpress already do the rewrite from /category/xyz/ to /?category_name=xyz and so I wanted to try if it would work the same as my first rule. But then I decided later to just use the first rule.

    RewriteCond %{THE_REQUEST} ^[A-Z]{3,9}\ /(index\.php)?\?category_name=([^/]+)\ HTTP/
    RewriteRule ^(index\.php)?$ /blog/category/%2/? [R=301,L]
    RewriteRule ^blog/category/([^/]+)/$ /?category_name=$1 [L]

    You mentioned in your previous reply that something is stripping the /xyz/ part off /blog/category/xyz/. I have no idea why it is doing this, could you please give me some suggestions?

    http://example.com/test?DocumentRoot_plus_URL-path=/home/yoakenij/public_html/blog/category/uncategorized/&Request_Filename=/home/yoakenij/public_html/blog/category

    Thanks
    Joe

    [edited by: Murasaki at 3:59 pm (utc) on Feb. 10, 2009]

    jdMorgan

    6:42 pm on Feb 10, 2009 (gmt 0)

    WebmasterWorld Senior Member 10+ Year Member



    Again, I have to ask you to clearly specify what is a URL, and what is a filepath or filename. As noted by g1smd in the 5th post of this thread, we could both be going about this entirely backwards, because this point is not clear.

    An external 301 redirect tells the client (browser or robot) that the content has moved to a new URL, asks it (not tells it) to re-request the content from a new URL, and terminates the current HTTP request. The syntax is

     RewriteRule ^old-URL-path$ http://www.example.com/new-URL-path [R=301,L] 

    The client browser will (normally) update its address bar and re-request the content from the new URL given on the right side of this rule.

    An internal rewrite does not inform the client, and takes place entirely within the context of the current HTTP request -- instead simply telling the server where to find the file associated with the requested URL. The syntax is

     RewriteRule ^requested-URL-path$ /non-default-server-filepath [L] 

    So, we need to see clear statements like "I want to redirect client requests for URL-path /xyz to URL http://www.example.com/abc" or "When I get a request for URL-path xyz, I want to serve content from filepath /abc".

    Think in terms of what URL the server receives in a request from the client, because this is where the redirect or rewrite process starts.

    Otherwise, we can go around and around, and members will run out of time or simply lose interest in this thread...

    Also, WordPress doesn't technically rewrite *anything*. You may be referring to the action of some additional code in an .htaccess file located in the WordPress subdirectory, or possibly to an "Alias" directive installed in your .httpd.conf file by the WordPress installer, but WordPress is a content-handler and therefore cannot do "a rewrite". It can issue a redirect, or it can "print" modified links on your HTML pages, but it cannot by definition do an internal rewrite.

    I'm not trying to be pedantic here, but just stating the facts in hopes of clarifying things.

    Since it'll be impossible to get anything resolved here unless you understand what is going on and can comunicate your requirements completely and concisely, perhaps some more basic info is needed:

    Wordpress now outputs "friendly" URLs in the links that appear on your HTML pages. A user clicks on one of those links, and their browser sends a request to your server for that "friendly" URL. The request is passed through the server config files, where it might be redirected to a new URL, rewritten to a non-default server filepath, or "Aliased" to a non-default directory-path. If none of these things happen, the request is passed to your top-level .htaccess file. Within that file, your mod_rewrite code may redirect that URL to a new URL, or rewrite it to a non-default server filepath, as described above.

    As long as no external redirect is invoked in your top-level .htaccess file, the request is then passed to the next .htaccess file (if any) in the subdirectory path of the now-updated server filepath. Within that file, your mod_rewrite code may redirect to a new URL, or again rewrite to a different non-default server filepath, as described above.

    This continues until the subdirectory containing the file is reached and the .htaccess file in that last subdirectory has been processed. At this point, the content-handling phase is invoked, and the file is served -- or if that file is a script, it is executed to produce a new HTML page to send back to the client/browser.

    Note that the setting of RewriteOptions inherit can affect whether the server behaves as described above; If the server is configured without the "inherit' setting, then mod_rewrite code in higher-level .htaccess files won't be executed; only the mod_rewrite code in the requested file's final subdirectory will execute.

    So, given that process, it is critical that you (and the members here) understand your goals and requirements in terms of what URL is in the link on your HTML page and will be requested from your server, and what new URL you want that requested URL redirected to... Or what URL is in the link on your HTML page and will be requested from your server, and what internal server filepath you want to call to provide the HTML content for that requested URL. So again, "I want a client request for URL '/xyz' to be externally redirected to new URL http://www.example.com/abc", or "I want a client request for URL '/xyz' to be rewritten to server-filepath /path-to-file-abc".

    The link on the HTML page in the browser *defines* the URL, and nothing you can do in the server can change that. All that the server can do is either to redirect the client to another URL when the original URL is requested, or to provide content in response to that requested URL from some server filepath that is different from what that filepath would be if the rewrite code was not present.

    So the HTML page defines URLs used on the Web, you (the Webmaster) define files and filepaths inside the server, and the server's fundamental and primary job is to translate URL requests to filepaths, so that Web clients do not have to know what OS your server uses, or what your server filepaths look like.

    HTH,
    Jim

    Murasaki

    1:23 am on Feb 11, 2009 (gmt 0)

    10+ Year Member



    At the moment with permalink on, a client request for URL '/category/xyz/' rewrites to '/index.php?category_name=xyz'.

    I simply want to change the client request URL (without turning off permalink) from '/category/xyz/' to '/blog/category/xyz/'. So that a client request for URL '/blog/category/xyz/' (http://example.com/blog/category/xyz/) will be rewritten to the same query string '/index.php?category_name=xyz' (http://example.com/index.php?category_name=xyz). And when I click on the link that has URL of http://example.com/blog/category/xyz/, it will give me the 'xyz' category page.

    I hope this is clearer
    Joe

    [edited by: Murasaki at 1:25 am (utc) on Feb. 11, 2009]

    Murasaki

    5:02 am on Feb 12, 2009 (gmt 0)

    10+ Year Member



    Just putting together the things I've tried so far to hopefully make the problem clearer.

    Apache version:

    Apache/2.2.11 (Unix) mod_ssl/2.2.11 OpenSSL/0.9.8b mod_auth_passthrough/2.1 mod_bwlimited/1.4 FrontPage/5.0.2.2635

    And these are the rules in my .htaccess file placed at root (No .htacess in sub-directories):
    <IfModule mod_rewrite.c>
    RewriteEngine On
    RewriteBase /

    ### SEARCH ###
    RewriteCond %{THE_REQUEST} ^[A-Z]{3,9}\ /(index\.php)?\?s=(.+)?\ HTTP/
    RewriteRule ^(index\.php)?$ /search/%2/? [R=301,L]
    # Add a trailing slash
    RewriteRule ^search/([^/]+)$ /search/$1/ [R=301,L]

    RewriteCond %{THE_REQUEST} ^[A-Z]{3,9}\ /(index\.php)?\?category_name=([^/]+)\ HTTP/
    RewriteRule ^(index\.php)?$ /blog/category/%2/? [R=301,L]
    RewriteRule ^blog/category/([^/]+)/$ /index.php?category_name=$1 [L]

    #RewriteRule ^blog/category/([^/]+)/$ http://example.com/test?DocumentRoot_plus_URL-path=%{DOCUMENT_ROOT}%{REQUEST_URI}&Request_Filename=%{REQUEST_FILENAME} [R=302,L]

    # BEGIN WordPress
    RewriteCond %{REQUEST_FILENAME} !-f
    RewriteCond %{REQUEST_FILENAME} !-d
    RewriteRule . /index.php [L]
    # END WordPress

    </IfModule>

    To do this:

    At the moment with permalink on, a client request for URL '/category/xyz/' rewrites to '/index.php?category_name=xyz'.

    I simply want to change the client request URL (without turning off permalink) from '/category/xyz/' to '/blog/category/xyz/'. So that a client request for URL '/blog/category/xyz/' (http://example.com/blog/category/xyz/) will be rewritten to the same query string '/index.php?category_name=xyz' (http://example.com/index.php?category_name=xyz). And when I click on the link that has URL of http://example.com/blog/category/xyz/, it will give me the 'xyz' category page.

    I have tried the following:

    RewriteCond %{THE_REQUEST} ^[A-Z]{3,9}\ /(index\.php)?\?category_name=([^/]+)\ HTTP/
    RewriteRule ^(index\.php)?$ /blog/category/%2/? [R=301,L]
    RewriteRule ^blog/category/([^/]+)/$ /index.php?category_name=$1 [L]
  • Have tried both with and without 'index.php' before the query string in the substitution term of the 2nd rewrite rule.
  • With Wordpress permalink ON. Resulted in page not found.
  • With Wordpress permalink OFF. Category page displayed.

    RewriteRule ^blog/category/([^/]+)/$ /index.php?category_name=$1 [R=301,L]
  • With Wordpress permalink ON. Client request URL redirected to query string and category page displayed.
  • I've also tried R=302 and that worked too.

    RewriteRule ^blog/category/([^/]+)/$ http://example.com/test?DocumentRoot_plus_URL-path=%{DOCUMENT_ROOT}%{REQUEST_URI}&Request_Filename=%{REQUEST_FILENAME} [R=302,L]
  • Client request URL redirected to http://example.com/test?DocumentRoot_plus_URL-path=/home/username/public_html/blog/category/xyz/&Request_Filename=/home/username/public_html/blog/category
  • '/xyz/' is stripped from the filepath.
  • Same result with Wordpress permalink On and Off.

  • I have also tried adding this rewrite rule: ^blog/category/([^/]+)/$ /index.php?category_name=$1 through wordpress internally according to the documentation but it did not work out.

    At the moment I'm trying to find out why '/xyz/' is been stripped from the filepath but not sure if it is the one that's causing the problem.
    The only part that uses REQUEST_FILENAME is the Wordpress rules

    RewriteCond %{REQUEST_FILENAME} !-f
    RewriteCond %{REQUEST_FILENAME} !-d
    RewriteRule . /index.php [L]

    I'm not entirely sure what that single 'dot' does in the above rule (I know that a 'dot' matches any single character). Are those rules simply rewriting the client request URL to the root index.php file when the request is not a real file or directory?

    But no matter what it does, it shouldn't be interfering with my rewrite rule right? (Please correct if I'm wrong)

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

    Since the above rule works when I make it a 301/302 redirect, wouldn't that mean that there is no problem with RewriteRule reading the client request URL 'http://example.com/blog/category/xyz/' where as REQUEST_FILENAME is missing the part for the query string value (/home/username/public_html/blog/category). Unless having R=301/302 changes anything relating to reading the client request URL.

    Joe

    [edited by: Murasaki at 5:13 am (utc) on Feb. 12, 2009]

  • tomda

    6:23 am on Feb 12, 2009 (gmt 0)

    WebmasterWorld Senior Member 10+ Year Member



    You can use the plugin called "WordPress RewriteRules Viewer" from AskApache.

    Read the codex from Wordpress http://codex.wordpress.org/Using_Permalinks

    You can also try to add the rules in the Wordpress internal system by using the add_filter function and the "rewrite_rules_array" hook. Do some googling to get some example or get code for existing plugin.

    add_filter('rewrite_rules_array', array('your_function','your_option'));
    or
    add_filter('rewrite_rules_array','yourawesomefunction');

    Note that:

    If you apply new rewrite rules using the rewrite_rules_array filter you need to ensure that you refresh the rewrite rules that Wordpress has stored in a hidden option. You do this by simply resaving the Permalink Structure under the Options menu in the admin area of your WP install.

    Murasaki

    6:56 am on Feb 12, 2009 (gmt 0)

    10+ Year Member



    I'm already using that plugin :)

    I did try to add the rewrite rule through wordpress couple of days ago but it didn't work. I'll try again though.

    Thanks for the reply
    Joe

    Murasaki

    2:46 pm on Feb 12, 2009 (gmt 0)

    10+ Year Member



    I got it working with Wordpress' rewrite_rules_array hook.

    Thank you all for your help.
    Joe