Below is the original question, and while it's related to what the issue ends up being, it's tangential. Please see the edits starting with number 2 for more useful background information

On our site, we have some CMS pages that explain correlation between two different categories. As such, the URLs tend to be similar to those catalog page URLs.

  • An example CMS URL:
    • "brand/category.html"
  • The category which matches:
    • "category"

Is there a setting in Magento to force category route matching to be more strict?

EDIT: I should note, though it feels obvious: These are just example names

EDIT 2: If it's helpful, all catalog pages have URLs relative to root (website.com/subcat) where subcat is a child of another category. This behavior is different from the default in other Magento installs. (Note: this isn't preferred, and it's unclear as to why it's happening).

EDIT 3: After more digging, I found a quote from an article by Fabrizio Branca on URL keys in 1.13:

Before 1.13/1.8 any CMS page with a url-key that was also used as a category or product url-key would be evaluated first. This way you could easily replace the main categories by cms landing pages. This has changed now. Even though the CMS controller is processed first, the product and category urls will be evaluated before the routing process starts, making it much harder to display cms content in a clean way instead.

EDIT 4: Result of more research:

  • "legitimate category" exists, and by default is accessible at /a
  • "legitimate other category" exists as well, and is at b
  • regardless of the relationship between these two categories, either can be accessed using the other as its parent (a/b works fine, as does b/a).
    • note that a/b shows products of b and b/a products of a
  • However, b/b does not work, nor does non-existant-category/a

What I'm looking for is a URL structure similar to the previous Magento versions (IE category/subcategory), without losing the benefits of background indexing that 1.13 gives.

  • I think you will need to explain "Is there a setting in Magento to force category route matching to be more strict" a bit more.
    – benmarks
    May 31, 2013 at 17:35
  • Well, clearly Magento is making assumptions by matching the request website.com/brand/category.html to the route website.com/category. My question is how to make that not happen.
    – mpw
    May 31, 2013 at 18:46
  • There is no native programmatic connection between SEF category URLs and CMS page URLs.
    – benmarks
    May 31, 2013 at 19:15
  • I appreciate that you're sticking with me on this, but I am not sure how to use that comment to help find a solution.
    – mpw
    May 31, 2013 at 20:42
  • You're asking about a setting of "strictness" for category URLs, and you provide a context for this question involving CMS pages. There is no such native connection in Magento, so we'll have to know more about your question, your environment (customizations, etc.). Routes for these entities are based on data in entirely different tables, and there are separate router classes for each.
    – benmarks
    May 31, 2013 at 21:22

4 Answers 4


(Thought I'd posted an answer similar to Alan's, but I hadn't. Sitting here in LocalStorage. But, I can tag onto his answer with an interesting solution theory.)

The CMS router adds itself to the Front Controller instance by observing the controller_front_init_routers event after the Admin and Standard routers are added. With a little config XML, it would be possible to switch this to the controller_front_init_before event, thereby adding the CMS router first, meaning its match()ing logic will run before the others.

To test this theory, drop the following into app/etc/local.xml:

        <!-- fire observer for different event -->
        <!-- disable the original observer -->

See if this solves the problem.

Incidentally, the CMS router will adjust the request path in the same way as the URL rewrite model.

  • This is excellent. While I don't think there's anything to be done about the odd new method of category routing, giving CMS pages the first chance to match goes a long way.
    – mpw
    Jun 4, 2013 at 13:18
  • 2
    Just don't name any CMS page "admin" or whatever your admin frontName is :-)
    – benmarks
    Jun 4, 2013 at 19:10
  • Ok, Nevermind. This isn't actually working. To make sure that I'm not crazy frontend is properly nested as config->frontend, yes?
    – mpw
    Jun 5, 2013 at 14:47
  • Yes. Ensure that it's being loaded, but you can set a breakpoint, drop a Mage::log() call (or echo or whatever) Mage_Core_Controller_Varien_Action::addRouter() to see the order in which the router classes are added.
    – benmarks
    Jun 5, 2013 at 15:03
  • I can only see the addRouter method in Mage_Core_Controller_Varien_Front. Regardless, the order according to the log output was: admin, standard, cms, default.
    – mpw
    Jun 5, 2013 at 15:15

I've seen a lot of interesting implementations (some good, some bad) by SEO specialists who didn't have a Magento background throughout the years. It sounds like you may be running into problems with some custom code you don't understand. The high level answer to your question may be "Contact the person who wrote the SEO code and/or installed the extension you don't understand", or find a Magento consultant to take a look and quickly dissect it for you.

Your question, even with its clarification, is still too confusing. Literally speaking, no, there's no setting in Magento to "force category routing to be more strict". I'm going to explain, in broad terms, how category routing works vs. CMS routing in a standard Magento system. This will (hopefully) give you enough information to ask a new question in terms we'll be able to understand it by. Also, I've written extensively on Magento's request dispatch before, so if you're interested on the nitty gritty details I'd start there.

Category Routing

There is, strictly speaking, no "category" routing in Magento. On a site with SEO Friendly URLs turned off, a category listing page looks like this.


When SEO friendly URLs are on, Magento (in an indexing process) creates between one and several entries in the


table for that category. The request_path column is the import one here. When Magento is deciding how to handle a particular URL, it will first look in this table. If the current URL matches the request_path, Magento will change its internal representation of the URL so it look like the target_path column.

So, in the sample data, there's a row that looks like this

*************************** 1. row ***************************
url_rewrite_id: 17
      store_id: 1
   category_id: 8
    product_id: NULL
       id_path: category/8
  request_path: electronics/cell-phones.html
   target_path: catalog/category/view/id/8
     is_system: 1
       options: NULL
   description: NULL
1 row in set (0.01 sec)

When Magento sees the url http://magento.example.com/electronics/cell-phones.html, it matches this row because the request_path variable is electronics/cell-phones.html. It then changes its internal representation of the URL to the target_path (catalog/category/view/id/8). Then, Magento handles the URL normally.

That's probably a bit much to follow if you're not used to it, but the important thing to take away is the system that decides how to handle the URL doesn't care that it's a category URL, it just cares that there's an entry in the core_url_rewrite table. This same table is used for product name URLs. Many SEO extensions and custom code solution use this table as well.

CMS Page Routing

After Magento finishes referencing the core_url_rewrite table, what happens next is

  1. It checks for any Admin application page matches (manage products, manage categories, etc.)

  2. It checks for any Frontend application page matches (product listing page, the above mentioned category listing page, etc.)

  3. If numbers 1 & 2 contain no matches, it then looks for a CMS page match.

Magento doesn't use the core_url_rewrite table for CMS pages. Instead, if is reaches step number 3, it tries to match the URL with the URL Key set on the CMS page object. (it would be more accurate to say that when Magento is looking for a CMS page match, it's operating on a URL already modified by the core_url_rewrite process — but things are already confusing enough)

The important take aways here is: CMS matching happens only after a category page match has failed.

It sounds like you may have external processes modifying the core_url_rewrite table, or may have a custom router object added to your system the does extra routing, or maybe even a non-magento system doing things to change URLs.

I'm afraid there's no quick and easy answer for your situation.

  • I may have a solution, see my answer
    – benmarks
    Jun 2, 2013 at 22:27
  • I don't believe that any custom code is affecting the category URL rewriting (though I'll be taking a hard look at the core_url_rewrite table). From the very start of development, I can recall that subcategory would match /subcategory.html (as opposed to category/subcategory.html) -- even before any outside code was brought in. (\n) Suppose this could've been useful earlier on, but is it possible that there was a change in EE 1.13 that could be causing this?
    – mpw
    Jun 2, 2013 at 22:52
  • @mpw I don't know. My approach is debug these things from the bottom up. Jun 3, 2013 at 5:17
  • Just checked the core_url_rewrite table. It's empty. Could this have anything to do with my issues?
    – mpw
    Jun 3, 2013 at 11:50
  • 1
    As far as I can tell, core_url_rewrite is not used in 1.13, though I'm not sure about that. I think that only enterprise_url_rewrite is used now.
    – Josh
    Jun 5, 2013 at 19:29

@benmarks answer is already good. But you will still have issues if your product URLs match your CMS page URLs. The URL rewrites from the table core_url_rewrite are checked before the routers are checked - see Mage_Core_Controller_Varien_Front::dispatch:

public function dispatch()
    // [...]

    $i = 0;
    while (!$request->isDispatched() && $i++ < 100) {
        foreach ($this->_routers as $router) {
            /** @var $router Mage_Core_Controller_Varien_Router_Abstract */
            if ($router->match($request)) {
    // [...]

If a product URL matches the current path info, the path info of the request will be changed in Mage_Core_Model_Url_Rewrite_Request::_rewriteDb, so that the CMS router will not match any more even though it is called before the catalog router (if you applied @benmarks config.xml).

Fortunately, there is a nice flag called straight, which can be set on a Mage_Core_Controller_Request_Http. If the flag is set, the URL rewrites from the database will not be checked. Hence, my solution is to observe an event, which is fired early enough (controller_front_init_before) and set the straight flag on the request in it if the current path info matches a CMS page identifier:

In your config.xml:


Your observer method:

class Namespace_Module_Model_Observer

    public function controllerFrontInitBefore(Varien_Event_Observer $observer)
        /** @var Mage_Core_Controller_Request_Http $request */
        $request = $observer->getFront()->getRequest();

        $identifier = trim($request->getPathInfo(), '/');
        $pageId = Mage::getModel('cms/page')->checkIdentifier($identifier, Mage::app()->getStore()->getId());

        if ($pageId) {


Since the catalog router will not match if the the database URL rewrites are not applied, this solution should work on its own and you do not even need the config.xml of @benmarks.

Hope this helps someone - that took quite some effort to debug!

  • Very nice find.
    – benmarks
    Mar 23, 2016 at 17:53

What I'm looking for is a URL structure similar to the previous Magento versions (IE category/subcategory), without losing the benefits of background indexing that 1.13 gives.

This is a problem I've been looking at, which so far doesn't seem to have a great solution. We have some deeply nested categories, for example:

Cat A
    Cat B
        Cat C
            Cat D

Prior to 1.13, the category url would have generated as www.domain.com/cat-a/cat-b/cat-c/cat-d/, but now it generates as www.domain.com/catd. Although if you have multiple "Cat D"s, then it could generate as something like www.domain.com/catalog/category/view/s/cat-d/id/132/.

I've been tinkering with different ideas for addressing this, one thing I'm trying right now is to modify the loadByRequestPath method of Enterprise_UrlRewrite_Model_Resource_Url_Rewrite to first look for a full path, before using the default behavior. I did that by adding this method:

protected function tryLoadByFullPath($object, $paths)
    if (count($paths) > 1) {
        $_path = implode('/', $paths);

        $select = $this->_getReadAdapter()->select()
            ->from(array('m' => $this->getMainTable()))
            ->where('m.request_path = ?', $_path);

        $result = $this->_getReadAdapter()->fetchRow($select);

        if ($result) {

            return true;

    return false;

and then adding this code to the top of loadByRequestPath():

if ($this->tryLoadByFullPath($object, $paths)) {
        return $this;

It appears to work, at first glance anyway, I haven't tested it very well yet. The downside to this is that the url_key has to be manually set to the full path for every category, so you would have to set the url key for Cat D to "cat-a/cat-b/cat-c/cat-d". That's obviously not ideal.

Anyway, that's probably not very helpful, but maybe someone has a better take on this approach.

  • Just glad to not be alone in this! If we find a solution, I'll be sure to report it.
    – mpw
    Jun 5, 2013 at 20:11

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.