301 redirect instead of 404 when URL is a prefix of a post or page name?

hey all! i have an odd problem with URL routing. when i request a URL that doesn’t exist, e.g. http://localhost/foo, wordpress correctly returns a 404. however, if that URL is a prefix of a post or page name, it instead returns a 301 redirect to the post or page.

for example, if i have a post on 10/1/2010 named Food Post, it will return a 301 with Location: http://localhost/2010-10-01_food_post (my permalink structure). likewise, if i have a page named Food Page, it will return a 301 with Location: http://localhost/food_page.

you can see this in action on my live site, http://snarfed.org/ . e.g. http://snarfed.org/foo redirects to http://snarfed.org/2009-10-30_food_highlights .

turning off permalinks (ie switching to “default”) fixes it, for both posts and pages, but naturally i don’t really want to do that.

i see this on three different installations, all wordpress 3.0.1 and apache 2.2, two ubuntu lucid/mysql 5.1 and one freebsd 7.3/mysql 5.0. i’ve deactivated all plugins and removed everything from my .htaccess except the lines for wordpress below, verbatim, but no luck.

RewriteEngine On
RewriteBase /
RewriteRule ^wordpress/index\.php$ - [L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule . /wordpress/index.php [L]

thanks in advance…

1
1

This is normal, it is because redirect_canonical(), which makes sure you are always at a “canonical” URL (conforming to your permalink structure), executes redirect_guess_404_permalink() to make a best guess at a post when the URL is incomplete. If you want to prevent this, I think the best way is to hook into the redirect_canonical filter, and return false if it is a 404. Something like this:

add_filter('redirect_canonical', 'no_redirect_on_404');
function no_redirect_on_404($redirect_url)
{
    if (is_404()) {
        return false;
    }
    return $redirect_url;
}

Leave a Comment