(Note to future readers: This is fixed in WordPress 3.3, so this article is now out-of-date. See http://core.trac.wordpress.org/changeset/18541 for the patch.)

I was not aware that other people didn’t know about this until recently, but since it seems to be little known, I thought I’d write a post on the topic.

Chain LinksIn WordPress, you should never start the custom permalink string with any of these %postname%, %category%, %tag%, or %author%. (Unless you know what you’re doing, of course. :) )

Meaning that “%category%/%postname% ” is a bad custom permalink string. So is just “%postname%” for that matter.

Why? Well, it has to do with how the WordPress Rewrite system works.

Rewriting Explained

See, when you request a URL from a WordPress site, WordPress gets the URL and then has to parse it to determine what it is that you’re actually asking for.

It does this by using a series of rules that are built whenever you add new content to WordPress. Generally the list of rules is pretty small, but there are specific cases that can cause it to balloon way out of control.

Normal Rules

Let’s say you’re using a normal permalink string, like my preferred “%year%/%postname%”. The rules that are generated will look like this:

/robots.txt (for the privacy settings)
/feed/* (for normal feeds of any kind)
/comments/* (for comments feeds)
/search/* (pretty url for searches, not often used)
/category/%category% (category archives)
/tag/%tag% (tag archives)
/author/%author% (author archives)
/%year%/%month%/%day% (with each of those after year being optional)
/%year%/%postname% (this is the permalink string you define)
/%pagename% (any Page)

The way that system works is that it compares the URL it has to each of those in turn, from the top to the bottom. When one of them fits, then WordPress knows what to display and how to do it.

Note that the order I listed those in is is significant. Each one from the top down is less specific than the previous one.  For example, “robots.txt” matches only that, while “/feed/*” matches anything starting with /feed/. And so on down the list. The %postname%, %category%, %tag%, %author%, and %pagename% will match any string, but the other WordPress % ones will only match numeric fields. Like %year% is always a number.

Notice that the last one is %pagename%. This basically matches everything, because %pagename% can be anything at all. Even hierarchical pages like /plugins/whatever/something will cause this to match. It’s the fall-through position. And then, if that page doesn’t actually exist on your site, then this causes the query to trigger the 404 condition internally, which causes your theme’s 404.php to load up.

Pretty simple and straightforward, really.

Problem Rules

The problem comes in when you try to use a non-number for the beginning of your permalink string. Let’s examine those last two rules closer:

/%year%/%postname% (this is the permalink string you define)
/%pagename% (any Page)

What if you used “%category%/%postname%” for your custom permalink string? Now those last two rules are these:

/%category%/%postname% (this is the permalink string you define)
/%pagename% (any Page)

That violates our main rule, doesn’t it? That each one should be less specific than the one above it? Because %category% can match any string too, just like the %pagename% can… With this set of rules, there’s no way to view any of the Pages. Not good.

So, WordPress detects this condition and works around it. Internally, this sets a flag called “use_verbose_page_rules”, and that triggers the rewrite rebuild to make this set of rules instead:

/robots.txt (for the privacy settings)
/AAA
/BBB
/CCC (one of these for each of your Pages)
/feed/* (for normal feeds of any kind)
/comments/* (for comments feeds)
/search/* (pretty url for searches, not often used)
/category/%category% (category archives)
/tag/%tag% (tag archives)
/author/%author% (author archives)
/%year%/%month%/%day% (with each of those after year being optional)
/%category%/%postname% (this is the permalink string you define)

Now we have basically the same set of rules, except for those new ones at the top. Every Page now gets its own very specific rule, and this satisfies our main condition once again.

Pages

But what if you have a lot of Pages? I once read a post by a person who had over 50,000 Pages on his site. That is a special case obviously, but consider our lookup system. We’re going through these rules one at a time. With our first method, our rule list was only 10 rules, maximum. With this new method, you add a rule for every single Page you make. Going through 50,000 rules takes a lot longer than going through 10. And even just building that list of rules can take a long time.

Basically you’ve created a performance issue. Your Pages now won’t scale to unlimited numbers. Your site’s speed is linearly dependent on the number of Pages you have.

This is a bad thing.

Conclusion

Firstly, it’s really not any better for SEO to have the category in there, or to have just the postname there by itself. And anybody who tells you differently is wrong. If you disagree with me, then no, I’m not interested in arguing this point with you; you’re just wrong, period, end of discussion.

Secondly, shorter links are great and all, but hell, why not use a real shortlink? WordPress 3.0 now has a ShortLink API that defaults to using ?p=number links on your own domain. These will actually work for any WordPress site, even ye back unto WordPress 2.5. WordPress 3.0 just makes it nicer and easier to use these with the Shortlink API (as well as allowing plugins to make this automagically use services like wp.me or bit.ly). So use that instead.

The conclusion is, in general, just don’t do it. Leave a number, or something static, at the beginning of your permalink string and you’ll never have any sort of problems. But if you really MUST do this sort of thing, then keep your number of Pages low. Don’t try it when you have more than, say, 30-50 Pages.

Addendum

Okay, so I actually simplified things for this post. It’s actually worse than this, as verbose page rules can add much more than one rule per page, as this post demonstrates (he gets 11 per extra page!).

Shortlink:

290 Comments

  1. [...] it because it is unfriendly to users in the many contexts in which users interact with URLs.) See Otto’s technical writeup on the topic as well as this wp-testers [...]

  2. Otto,

    I have a doubt regarding new update regarding to Permalink. There is a new setting which can enable us to just use ‘Post name’ – /index.php/sample-post/

    As per your suggestion, non-number permalinks should not be set in older versions. I would like to know if there could be any trouble or if it is a good idea to chose this new permalink style(5th one)

    Thank you !

  3. [...] information like the post name or some important words related to the post itself. In this link we can read more about [...]

  4. [...] things here and there over the years that this has been a problem. One of those articles was on “Otto on WordPress” which delves into [...]

  5. [...] in WordPress. A year later the same topic came up again in the WPTavern Forums, and later I wrote a blog post about the issue in more detail. That post generated lots of questions and [...]

  6. Is there any way to show my Portfolio Categories in my permalinks, so that I can target some Portfolio Categories by a specific widget?
    Or is there a better way to do this?

    Thanks!

  7. [...] Otto (@ottodestruct) fixed the wordpress permalink issue in WordPress 3.3, when I moved christopherprice.com to a different WP install, I decided to [...]

  8. [...] Since WordPress grew up as a blog they hardcoded the URL routing logic which has resulted in some rather odious limitations in how you can design your URLS.  Drupal’s URL management is no panacea either — you can end up with a difficult to maintain [...]

  9. [...] why and is beyond the scope of this post, but if you want a good historical summary of the subject, I recommend this post on permalinks at Otto on WordPress.  You can also read the recent post I wrote on the WordPress numbering [...]

  10. Hi, What happens if I use /articles/%postname%.html ?

  11. Hello, I just googling and didn’t find any tips to solve my problem. Currently I try to make breadcrumbs by using reference on Google rich snippets – Breadcrumbs. My problem is I can’t define the permalink of category. FYI, I use some parent categories with some childs. Could you give me explanation, tips or code how to implement breadcrumbs using Google rich snippets – Breadcrumbs, thank you and I’m sorry if my question out of the topic

  12. [...] argument for those of us who love WordPress like politicians love oil (oops) is the potential danger of capitalization with regards to individual rewrite rules for each page. A practice that has been know to result in [...]

  13. [...] much head scratching I would go with Sarah’s advice. She is basing it on this post by Otto on WordPressand I think he makes a convincing argument. The thing is, so long as you make sure you include [...]

  14. I never realized about this before. I always use %category%/%postname%

    Thank you very much for enlightenment! :)

  15. [...] There are some performance issues with starting a URL structure with category or post name, but it’s being fixed. Use a cache plugin (you should anyway) and it will be fixed in WordPress version 3.3. [...]

  16. [...] things here and there over the years that this has been a problem. One of those articles was on “Otto on WordPress”which delves into [...]

  17. Hello Otto,

    After lot of reading, I’ve come to some conclusions about the “best performing” permalink structure. I posted it on WordPress.StackExchange, please take a look.

    Now that you’ve read it, can you please tell me if (at least theoretically) /%year%/%postname%/%post_id%/ could be the best permalink structure for WordPress in terms of performance?

    Thanks.

  18. Well, if there are less pages, and the creation of categories is moderated, then pretty permalinks are way to go…

  19. One issue that I have with using page ID’s as links is that I don’t know what’s going on when I look at analytics, because ID’s don’t mean anything to me

  20. Wow, wow, wow… Been so long learning for wordpress and seo but I just know about this… Thanks for giving a useful and clear explanation regarding the permalink mate…

    Bookmarked this blog for sure…

  21. I had already set the permalinks to be category/postname and I know I can use permalink redirection plugin to redirect indexed pages to the updated link structure. But what I’m concerned is the social signals. The Facebook, Twitter and other share counts is not updated when I do this redirection.

    Since social signals also impact ranking, I’m concerned about changing my permalink. Is there any way to solve this problem?

  22. [...] versions of WordPress it was recommended not to use the /%postname%/ permalink structure due to the possibility of performance issues relating to the way in which WordPress fetched [...]

  23. [...] of WordPress it was recommended not to use the /%postname%/ permalink structure due to the possibility of performance issues relating to the way in which WordPress fetched [...]

  24. Hi, I just read your article and links. I am a bit confused now after the change you mentioned in the comments on December 16th, 2011. Which then is the best permalink structure? /%year%/%postname% or just /%postname%/ Thanks for your help and great information!

  25. It doesn’t look like this article’s comments are being replied to anymore, but I thought I would try anyway. I’m wondering, with the updated information at the top: (Note to future readers: This is fixed in WordPress 3.3, so this article is now out-of-date. See http://core.trac.wordpress.org/changeset/18541 for the patch.) – is it now okay, with WordPress 3.3+, to use /%category%/%postname%/?

  26. […] much head scratching I would go with Sarah’s advice. She is basing it on this post by Otto on WordPress and I think he makes a convincing argument. The thing is, so long as you make sure you include […]

Leave a Reply

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>

Need to post PHP code? Wrap it in [php] and [/php] tags.