13

By default URL Key on product page is Global scoped.

EDIT: As suggested by FlorinelChis the scope can be changes in Manage attributes. However this breaks the store view switcher behavior.

This is has been tested on 1.7.0.2 with samples data and "Add store code to URL" enabled:

  1. edit a product and set a different url for a particular storeview (french)
  2. Re-index
  3. Open product page on the site on english store view
  4. Switch to french: you will have the page URL containg /French/
  5. Switch back to english -> 404 page error ( the url miss the store code /default/

    how to make it work correctly with store view/language switch ?

Details:

  • URL for english : /default/sony-vaio-vgn-txn27n-b-11-1-notebook-pc.html
  • URL for french : /french/sony-vaio-vgn-txn27n-b-11-1-notebook-pc-french.html

If I'm on english site on this page -> /default/sony-vaio-vgn-txn27n-b-11-1-notebook-pc.html

Then I switch to french:

I got this URL (the store code is missed):
MAGEDOMAIN/sony-vaio-vgn-txn27n-b-11-1-notebook-pc-french.html

So magento re-write the url correctly but miss the store code for some reason

Reference:

For sure this is related to /core/model/store.php and /core/model/url/rewrite.php, and in particular to those methods:

Mage_Core_Model_Url_Rewrite::rewrite
Mage_Core_Model_Store::getCurrentUrl

UPDATE

If you are on 1.9.1 @Vinai fix will not work, check the new answer I have added

  • which Magento version are you using? – FlorinelChis Feb 13 '13 at 12:47
  • Magento 1.7.0.2 – Fra Feb 13 '13 at 12:48
  • Tim I'm currently testing some answer and will accept them after confirm they are working. – Fra Feb 13 '13 at 13:08
12

The problem is a bug in the model Mage_Core_Model_Url_Rewrite_Request (Magento 1.8) and Mage_Core_Model_Url_Rewrite (earlier versions).

The section of core code in 1.8 looks like this:

    // Section from Mage_Core_Model_Url_Rewrite_Request::_rewriteDb()

    $fromStore = $this->_request->getQuery('___from_store');
    if (!$this->_rewrite->getId() && $fromStore) {
        $stores = $this->_app->getStores();
        if (!empty($stores[$fromStore])) {
            $store = $stores[$fromStore];
            $fromStoreId = $store->getId();
        } else {
            return false;
        }

The Bug: the value of the query parameter is the store code, (in my case de, en or fr). The keys of the array returned by app->getStores() are the numeric store IDs. Thats why if (!empty($stores[$fromStore])) { always fails.

Once that bug is fixed, another bug becomes apparent later in the same method (I think only in 1.8):

$targetUrl = $this->_request->getBaseUrl() . '/' . $this->_rewrite->getRequestPath();

The request objects base url always is the Magento base_url, without the store code. Using $currentStore->getBaseUrl() instead there fixes that bug, too.

Once those two issues are fixed the language switcher works fine. Here is an extension which does exactly that for Magento 1.8 (CE): https://github.com/Vinai/VinaiKopp_StoreUrlRewrites

In Magento 1.7 the issue might be something different. I still thought I'd add this answer, just in case google brings somebody else here who is running 1.8 or newer.

  • do you think the fix I have implemented is safe ? – Fra Nov 22 '13 at 12:58
  • To be honest, I haven't looked into the cause for the issue in 1.7. Implementing a fix without understanding exactly what is causing the behavior is always risky. – Vinai Nov 22 '13 at 16:42
  • sorry reopening this discussion after 2 years but I'm again on this bug ... on 1.9.1 the issue is with the if condition $this->_rewrite->getId() ... basically for the second store view magento manage to load a rewrite and so It doesn't trigger the redirect ... however this rewrite has the wrong id_path ( product id is +1 ) so it load a 404 – Fra Jun 10 '15 at 17:36
4

Actually I found a workaround for this issue on Magento 1.7.0.2 if you are running Magento 1.8 looks to Vinai's detailed explanation:

It looks that part of the problem is related to the request controller Mage_Core_Controller_Request_Http.

If you look at line 161 there is this condition:

                elseif ($storeCode !== '') {
                    $this->setActionName('noRoute');
                }

Commenting it out fix the 404 error when I switch to a different Store in a category/product pages.

However for some unknown reason some time the store code is missed in the response Url but this is not causing issue anymore as both url works now:

  • MAGEDOMAIN/sony-vaio-vgn-txn27n-b-11-1-notebook-pc-french.html
  • MAGEDOMAIN/sony-vaio-vgn-txn27n-b-11-1-notebook-pc.html

It is stil not clear to me if the comment of this condition can cause other issue

  • I can confirm this works for me as well - whenever switching to another language when viewing a product, I would get a 404. This corrected it, and does as you said, omit the store code from the URL which is strange. I can't imagine this is the best solution as editing the core controller like this can't be good, I was wondering if you ever ended up finding another solution? – waffl Aug 8 '13 at 22:49
  • you don't need to edit any core file, you can create your own module and rewrite that class/method. – Fra Aug 10 '13 at 9:02
  • 1
    Mage_Core_Controller_Request_Http cannot be rewritten in a module. – benmarks Dec 9 '13 at 18:43
4

Some updated info for Magento 1.9.1

The bug @Vinai pointed out looks solved in this version anyway for other reason the functionality is still broken ( for configurable products )

The problem real problem is probably here Mage_Catalog_Model_Resource_Url however I don't have time and I dont' want to touch a such delicate part of the core.

Explanation for a workaround:

The entry point is always this classMage_Core_Model_Url_Rewrite_Request and in particular the method _rewriteDb()

How _rewriteDb() works:

  1. First it try to load the request for the current store

(139): $this->_rewrite->loadByRequestPath($requestCases);

  1. then if I cannot find it (no id) and has a ___from_store parameter

(142): if (!$this->_rewrite->getId() && $fromStore) {

  1. try to load a rewrite for the ___from_store:

(152): $this->_rewrite->setStoreId($fromStoreId)->loadByRequestPath($requestCases);

  1. if it find it, it use the id_path to load the one for the current store:

(159): $this->_rewrite->setStoreId($currentStore->getId())->loadByIdPath($this->_rewrite->getIdPath());

Everything looks fine however there is an issue in the url_rewrite data and so with the index functionality ( at least for configurable products ):

  • even if we are switching store and the new store has different url a rewrite at line 139 is loaded.

The problem is that this rewrite points to the wrong id_path ( instead of pointing to the configurable product id it is pointing to one of its simple product id )

Now a workaround is to remove the !$this->_rewrite->getId() condition and so magento try to find a redirect always when there a $fromstore parameter

  • The best would be to fix the catalog_url index and remove the wrong rewrite it creates.

Here the code for the fast workaround ( you will need to create a module and rewrite Mage_Core_Model_Url_Rewrite_Request class by your self):

protected function _rewriteDb()
    {
        if (null === $this->_rewrite->getStoreId() || false === $this->_rewrite->getStoreId()) {
            $this->_rewrite->setStoreId($this->_app->getStore()->getId());
        }

        $requestCases = $this->_getRequestCases();
        $fromStore = $this->_request->getQuery('___from_store');

        if ($fromStore) {
            $stores = $this->_app->getStores(false, true);
            if (!empty($stores[$fromStore])) {
                /** @var $store Mage_Core_Model_Store */
                $store = $stores[$fromStore];
                $fromStoreId = $store->getId();
            } else {
                return parent::_rewriteDb();
            }

            $this->_rewrite->setStoreId($fromStoreId)->loadByRequestPath($requestCases);
            if (!$this->_rewrite->getId()) {
                return parent::_rewriteDb();
            }

            // Load rewrite by id_path
            $currentStore = $this->_app->getStore();
            $this->_rewrite->setStoreId($currentStore->getId())->loadByIdPath($this->_rewrite->getIdPath());

            $this->_setStoreCodeCookie($currentStore->getCode());

            $targetUrl = $currentStore->getBaseUrl() . $this->_rewrite->getRequestPath();
            $this->_sendRedirectHeaders($targetUrl, true);
        }

        if (!$this->_rewrite->getId()) {
            return parent::_rewriteDb();
        }

        $this->_request->setAlias(Mage_Core_Model_Url_Rewrite::REWRITE_REQUEST_PATH_ALIAS,
            $this->_rewrite->getRequestPath());
        $this->_processRedirectOptions();

        return true;
    }
3

URL Key is an attribute. You can edit it from: Catalog -> Attributes -> Manage Attributes. Search for url_key and click on it. Edit url_key attribute

Change the Scope and Save.

Now you can have different URL keys for products on each store view.

  • I have updated the question, you answer is good but it is not working – Fra Feb 13 '13 at 14:14
  • when you switch the store you should land on that store homepage not the product page. – FlorinelChis Feb 13 '13 at 14:52
  • The place where you land is the same where you start from: if you are on a category page you should land on the same page in the different language – Fra Feb 13 '13 at 21:07
1

So you want to change the URL for each store view?

At present, you modified the product URL at the score scope for your French store to be different to your English store? And when you switch between the two, you get a 404. This would be expected behaviour.

Magento won't store different URL rewrites for other store views. So when you hit /french/product1 on the French store, the URL will match in the table and it will load. But when you hit it in the English store, there will be no match and thus will 404.

What it sounds like you need is to just "Add store codes to URL" - which will leave your URL keys alone, but prefix all respective URLs with your store code. This should then allow your store switcher to function.

  • 1
    as confirmed by Vinai this is a bug – Fra Nov 22 '13 at 13:04

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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