Magento – Showing different stores based on customer group

customer-groupmultistorestore-view

I want customers in the wholesale customer group to see our wholesale store, and I want everyone else to see the default retail store. I tried the solution found here, and it successfully showed customers the correct store, but when I tried to change the theme for the wholesale store, it wasn't finding my theme and kept falling back to base/default.

After digging through the core code, I came up with a solution of my own which appears to work just the way I want it to, but I want to make sure that I'm not doing something that will cause problems that I'm not seeing. I also would be interested in better solutions to my problem if anyone has one.

I copied app/code/core/Mage/Core/Model/App.php to app/code/local/Mage/Core/Model/App.php and modified only the function _checkGetStore.

Original:

/**
 * Check get store
 *
 * @return Mage_Core_Model_App
 */
protected function _checkGetStore($type)
{
    if (empty($_GET)) {
        return $this;
    }

    /**
     * @todo check XML_PATH_STORE_IN_URL
     */
    if (!isset($_GET['___store'])) {
        return $this;
    }

    $store = $_GET['___store'];
    if (!isset($this->_stores[$store])) {
        return $this;
    }

    $storeObj = $this->_stores[$store];
    if (!$storeObj->getId() || !$storeObj->getIsActive()) {
        return $this;
    }

    /**
     * prevent running a store from another website or store group,
     * if website or store group was specified explicitly in Mage::run()
     */
    $curStoreObj = $this->_stores[$this->_currentStore];
    if ($type == 'website' && $storeObj->getWebsiteId() == $curStoreObj->getWebsiteId()) {
        $this->_currentStore = $store;
    }
    elseif ($type == 'group' && $storeObj->getGroupId() == $curStoreObj->getGroupId()) {
        $this->_currentStore = $store;
    }
    elseif ($type == 'store') {
        $this->_currentStore = $store;
    }

    if ($this->_currentStore == $store) {
        $store = $this->getStore($store);
        if ($store->getWebsite()->getDefaultStore()->getId() == $store->getId()) {
            $this->getCookie()->delete(Mage_Core_Model_Store::COOKIE_NAME);
        } else {
            $this->getCookie()->set(Mage_Core_Model_Store::COOKIE_NAME, $this->_currentStore, true);
        }
    }
    return $this;
}

Modified:

/**
 * Check get store
 *
 * @return Mage_Core_Model_App
 */
protected function _checkGetStore($type)
{
    $store = "default";
    if(Mage::getSingleton('customer/session')->isLoggedIn())
    {
        $groupId = Mage::getSingleton('customer/session')->getCustomerGroupId();
        $group = Mage::getModel('customer/group')->load($groupId);
        if($group->getCode() == "Wholesale")
        {
            $store = "wholesale_en";
        }
    }

    if (!isset($this->_stores[$store])) {
        return $this;
    }

    $storeObj = $this->_stores[$store];
    if (!$storeObj->getId() || !$storeObj->getIsActive()) {
        return $this;
    }

    /**
     * prevent running a store from another website or store group,
     * if website or store group was specified explicitly in Mage::run()
     */
    $curStoreObj = $this->_stores[$this->_currentStore];
    if ($type == 'website' && $storeObj->getWebsiteId() == $curStoreObj->getWebsiteId()) {
        $this->_currentStore = $store;
    }
    elseif ($type == 'group' && $storeObj->getGroupId() == $curStoreObj->getGroupId()) {
        $this->_currentStore = $store;
    }
    elseif ($type == 'store') {
        $this->_currentStore = $store;
    }

    if ($this->_currentStore == $store) {
        $store = $this->getStore($store);
        if ($store->getWebsite()->getDefaultStore()->getId() == $store->getId()) {
            $this->getCookie()->delete(Mage_Core_Model_Store::COOKIE_NAME);
        } else {
            $this->getCookie()->set(Mage_Core_Model_Store::COOKIE_NAME, $this->_currentStore, true);
        }
    }
    return $this;
}

I removed the check for the variable ___store in GET requests because I don't want the wholesale store to be accessed that way. Will this do everything that I want? I want the wholesale customer group to always see only the wholesale store, and I want everyone else to always see only the retail store (default). And I don't want any method of switching between stores other than logging in as a wholesale customer.

Even if this solution is an effective one, I am interested in a solution that is more upgrade friendly. I couldn't use Magento to rewrite this particular class, so now I'll have to take extra steps to make sure it gets updated during magento updates.

EDIT:

This change has caused these errors every time the magento cron runs:

2014-02-14T11:00:01+00:00 ERR (3): Warning: strpos(): Empty needle  in /###/lib/Zend/Controller/Request/Http.php on line 504
2014-02-14T11:00:01+00:00 ERR (3): Warning: strpos(): Empty needle  in /###/lib/Zend/Controller/Request/Http.php on line 510
2014-02-14T11:00:01+00:00 ERR (3): Warning: session_start(): Cannot send session cookie - headers already sent  in /###/app/code/core/Mage/Core/Model/Session/Abstract/Varien.php on line 123
2014-02-14T11:00:01+00:00 ERR (3): Warning: session_start(): Cannot send session cache limiter - headers already sent  in /###/app/code/core/Mage/Core/Model/Session/Abstract/Varien.php on line 123

Also, another person was unable to access the magento admin until I reverted this change. He said that clicking login just brought him back to the login page with no error message. I was able to log in to admin using the same credentials (from a different IP address).

Best Answer

Magento's core implementation of store view selection logic leaves a bit to be desired, but as you found out your solution is heavy-handed and has several knock-on effects.

There are several extensions which handle this functionality for you. Outside of moral opposition to using third-party extensions you should look into those as well-tested modifications with dedicated support.

If you want to build this yourself though you should start with an event observer on controller_action_predispatch which is fired on every request.

Related Topic