Tell me more ×
Magento Stack Exchange is a question and answer site for users of the Magento e-Commerce platform. It's 100% free, no registration required.

UPDATE
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.

share|improve this question
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 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 at 18:46
There is no native programmatic connection between SEF category URLs and CMS page URLs. – benmarks May 31 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 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 at 21:22
show 5 more commentsadd comment (requires an account with 50 reputation)

3 Answers

up vote 4 down vote accepted
+50

(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:

<frontend>
    <events>
        <!-- fire observer for different event -->
        <controller_front_init_before>
            <observers>
                <cms>
                    <class>Mage_Cms_Controller_Router</class>
                    <method>initControllerRouters</method>
                </cms>
            </observers>
        </controller_front_init_before>
        <!-- disable the original observer -->
        <controller_front_init_routers>
            <observers>
                <cms>
                    <type>disabled</type>
                </cms>
            </observers>
        </controller_front_init_routers>
    </events>
</frontend>

See if this solves the problem.

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

share|improve this answer
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 at 13:18
1  
Just don't name any CMS page "admin" or whatever your admin frontName is :-) – benmarks Jun 4 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 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 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 at 15:15
show 5 more commentsadd comment (requires an account with 50 reputation)

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.

http://magento.example.com/catalog/category/view/id/8

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

core_url_rewrite

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.

share|improve this answer
I may have a solution, see my answer – benmarks Jun 2 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 at 22:52
@mpw I don't know. My approach is debug these things from the bottom up. – Alan Storm Jun 3 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 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 at 19:29
show 1 more commentadd comment (requires an account with 50 reputation)

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) {
            $object->setData($result);
            $this->unserializeFields($object);
            $this->_afterLoad($object);

            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.

share|improve this answer
Just glad to not be alone in this! If we find a solution, I'll be sure to report it. – mpw Jun 5 at 20:11
add comment (requires an account with 50 reputation)

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

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