26 September 2011

Magento - sharing the cart between stores

EDIT: 08/01/13 - Improved store switching changes to Varien.php

When running multiple Magento stores off one install, you will probably want to have your session data share between stores. This of course includes, your cart and login status amongst other things. If you looked at System→Configuration→Web→Session Validation Settings in admin, you would be forgiven for thinking all you need to do is enable Use SID on Frontend to get this working. Unfortunately for many stores this seems often to be buggy and ineffective. In my own experience I have found it sometimes to append, and sometimes not to append the session id to the store switch urls, and when it has been appended and you switch stores it doesn't actually carry the session data over at all.

Buggy and frustrating, however with not too many lines of code you can get your stores sharing the cart and other session data reliably even if they are on different domains.

The first thing we want to do is disable the Use SID on Frontend setting as detailed above, we'll be adding the session id to the store change URL's ourselves.

Next copy
app/design/frontend/base/default/template/page/switch/stores.phtml
to
app/design/yourpackagename/yourtheme/default/template/page/switch/stores.phtml
if it isn't already there, but obviously replace yourpackagename and yourtheme with whatever package name and theme you are using on your particular store.

A lot of people will want to edit the way store switching happens as by default it's a not very exciting drop down form menu, so if you have changed this on your store you just need to target the equivalent url generation code for your store. For the sake of this tutorial I will be referring to the standard, unchanged, store code. So, open the file you just copied and in there you should see a select element:
<select id="select-store" title="<?php echo $this->__('Select Store') ?>" onchange="location.href=this.value">
 
and then a foreach loop creating the select options:
<?php foreach ($this->getGroups() as $_group): ?>
    <?php $_selected = ($_group->getId()==$this->getCurrentGroupId()) ? ' selected="selected"' : '' ?>
    <option value="<?php echo $_group->getHomeUrl() ?>"<?php echo $_selected ?>><?php echo $this->htmlEscape($_group->getName()) ?></option>
<?php endforeach; ?>
So when we select an option the onchange event handler takes us to the url being the value attribute of the option we have selected, this value attribute is what we need to edit.

To do this replace the line:
<option value="<?php echo $_group->getHomeUrl() ?>"<?php echo $_selected ?>><?php echo $this->htmlEscape($_group->getName()) ?></option>
 
with this:
<?php
    $this_session_id = Mage::getSingleton('core/session', array('name' => 'frontend'))->getSessionId();
    $this_store_url = explode('?', $_group->getHomeUrl());
    $this_store_url = $this_store_url[0] . '?SID=' . $this_session_id . '&___store=' . $_group->getCode();
?>
<option value="<?php echo $this_store_url ?>"<?php echo $_selected ?>><?php echo $this->htmlEscape($_group->getName()) ?></option>
The first line of code stores the current session id, the second line stores the url that would have been used for the value attribute, and the third line takes the value attribute url without any GET arguments and appends the session id followed by the store code. The last line of code uses the rebuilt URL as the value attribute in place of the original value.

These are all the changes we are going to need to correctly generate the store switching URLs so you can save and close this file.

Now copy
app/code/core/Mage/Core/Model/Session/Abstract/Varien.php
to
app/code/local/Mage/Core/Model/Session/Abstract/Varien.php
If you have read this post before, this is the updated section with a solution to allow the session to be properly passed across in the first page load.

In this file we are going to be making use of a one liner that is already present in this file but has not been implemented by default for some reason. This allows us to change the session id before the session is initialised so that when session_start() is called data is pulled from the previous stores session rather than a new session.

Open the file you just copied and look for the following line:
$this->setSessionId();
All we need to do here is pass the session id we have appended to the store switch url's to this method and it will set the session id for us, so change that line to the following:
if (isset($_GET['SID'])):
    $this->setSessionId($_GET['SID']);
endif;
So a few workarounds needed to patch up Magento's less than complete session handling when switching stores, but these changes should allow you to correctly pass the cart and other session data between stores even when they are on different domains.

57 comments:

  1. it is nice post.Hussey , i want some help from you.I used it in magento 1.6.0.0 CE .But at live server ,the session is not sharing and cart is not working.cart worked when we cart a product from default store and then cart product from second store and cart is working and session is not share.other time when did not cut any product from default store and go to second store add to cart a product here cart showed empty and give me any solution for it.

    ReplyDelete
  2. Unfortunately I haven't tested this code for version 1.6 of Magento, but if I was you I would get hold of an IDE such as NetBeans if you haven't got one already and step through the code changes you have made to make sure they are doing what you need them too.

    ReplyDelete
  3. Hi I'm also interesting in getting your help with our multi-store setup. The cart is not being shared. I don't trust myself to make this changes myself. Also our template doesn't have any drop-down to change the store, so we'd like to design our own "tab" style interface. I thought we'd just link to the other store, but I guess we need to do something a bit more sophisticated. So hope you could help with that too.

    Are you unable to handle work for version 1.6?

    Cheers
    Max Hodges
    contact us! support.whiterabbitjapan.com

    ReplyDelete
  4. Hi Max,

    Working on 1.6+ is not a problem, but my reply to Amit just notes that the above hasn't been tested for compatibility with that version. However as long as the core code with respect to the changes above has not been modified overly much I don't see any reason why it won't work.

    Yes I can help you resolve your cart sharing issues and build in store switching tabs, but it won't be until at the very earliest half way through January, and probably later than that. If you can't wait that long then I would suggest trying out the above changes on a development copy of your store and see if it is successful or not.

    ReplyDelete
  5. Hi..hussey marry Christmas and wish you happy new year . Again i want some help from you.I used it in magento 1.6.0.0 CE .In live server ,i have 3 store(1 default store i,e magento default and other 2 store new created ) for main website and each store has different domain name and each store has own store view .Problem is that when i cart a product from default store and then goes to cart product from second store/ third and cart is working and session is not share and goes to checkout from second or third store then ,after onepage login ,checkout redirecting to cart page (failure URL of checkout).If i want to did not cart any product from default store and then goes to cart product from second store/ third and cart show empty cart.I assumed that either it is ssl problem or admin panel setting problem or session accessing problem and give me any solution for it.

    ReplyDelete
  6. Hi Amit, I'm not entirely clear on what your problem is, however if you want to get in touch you can send me an email using the contact form on my site linked above and we can talk about it further.

    ReplyDelete
  7. This worked very well for me. Thank you.

    ReplyDelete
  8. Hi Mark, great - glad the solution is working well for you.

    ReplyDelete
  9. session http_host did not set for first time,if i refresh the home again then http_host for store is set ,that is problem for me.

    ReplyDelete
  10. Hi Hussey, this might be a challenge.

    I have one auto login for different users. At this time they see each others cart content and can remove or add products to it. It is all in the same shop and same store view.

    It would be nice to have like a machine_id to seperate the session and cart content.
    Do you know solution?

    ReplyDelete
  11. What exactly do you mean by different users? Different people on the same machine, different people on the same LAN, different people in completely different WAN locations etc?

    While I would recommend using different sessions for different users (at the moment it sounds like they are sharing sessions) you could still implement a workaround dependent on the available user data if separate sessions is not practical.

    ReplyDelete
    Replies
    1. Hi Hussey,

      What happens is a single signon which different people on different machines do not see themselfs but by button are loggedin. (SAP SRM)

      So they all login and are customer@shop.nl, as soon if 2 people are logged in at the same time with this account they share the same shopping cart(session).

      What i am looking for is a way to add machine_id or something to seperate the session/

      Delete
    2. Hi Robin,

      I think that approach is unfortunately bound to cause problems that realistically aren't going to be that easy or quick to resolve. Personally I would instead go with either creating a customer programmatically based on something like IP, or by using an extension that does it for you at checkout or similar.

      Delete
    3. Hi Hussey,

      Thanx for your anwser. However is there a way to extend a session with a machine id by changing session.php?

      Delete
    4. For multiple users to 'share' a session but still have separate session data would I think require extensive reworking of Magento's session handling across probably quite a number of different files and I think you would end up with something that is pretty hacked together and very buggy.

      If you want a definitive answer then I would say yes it would be possible, but I really wouldn't recommend it - storing multiple users data in a single session pretty much going against the whole idea of a session in the first place.

      Equally trying to generate different sessions for each using would cause just as many issues with them all sharing a login.

      Delete
  12. I had looked every where for this, and it is working beautifully for me on http://www.medione.com.au adn http://www.medione.co.nz

    On to .co.uk now thanks heaps.

    ReplyDelete
    Replies
    1. Great, glad the solution is working out for you.

      Delete
  13. I tried this in Magento 1.6.0.1 but where the store code should appear in the url it is just blank ie. http://mystore.com/?SID=hsa3drb53qhsb02qs2kp1s21d7&___store=

    Any ideas?

    ReplyDelete
    Replies
    1. I wrote this based on Magento 1.4.1.1 so it's possible that the core code in version 1.6.0.1 has changed sufficiently to break this solution. I would step through the code in a debugger and make sure that you are getting the correct values returning at each stage.

      Delete
    2. Hi Hussey, I am also facing the same issue!

      Delete
    3. Found resolution for the same :

      In version 1.6.1.0, replace "$_group->getCode()" in

      $this_store_url = $this_store_url[0] . '?SID=' . $this_session_id . '&___store=' . $_group->getCode();

      with

      $_group->getDefaultStore()->getCode()

      Delete
    4. Ok thanks for the input, I'll test this on later versions and change the solution accordingly.

      Delete
  14. Hi Hussey,
    I have an issue with sharing cart on two stores (same website) with different domains. I am using magento V 1.6.2. I have used above solution provided by you but not worked.
    My website url is www.99lens.com
    Please help me in this.
    Ajay

    ReplyDelete
    Replies
    1. Hi Ajay,

      I wrote this to work under Magento 1.4.1.1 and have not tested it under 1.6.2.0. It sounds like either there are other factors involved for your install, or the core code in this area has changed sufficiently between 1.4.1.1 and 1.6.2.0 to break this solution. To determine which I would run a diff against the 1.4.1.1 and 1.6.2.0 core files used here to see how much has changed, if very little relevant code has changed I would say the problem is probably not going to be with the Magento version and is instead related to some other customisation in your install.

      Delete
    2. Hi Hussey,
      Thanks for your response.
      I am close to solution. I have add SID in store url. And cart is shared where SID is in url. But it not shared where SID not in URL. SO is there any way where we can add SID in all urls like categories, products, cms pages etc.


      Ajay

      Delete
    3. Hi Ajay,

      The only URL's that should have an SID argument are the store switch URL's. It's only purpose is to indicate which session to load on store switch and when found the session indicated by the argument is loaded for that new store.

      If the session is not being shared for you, adding the SID argument to all URL's is not the solution.

      Delete
    4. Hi Hussey,
      You are right it is working with store switch url's.
      Your solution works with my application.
      Thanks

      Delete
    5. Hi Ajay,

      Great, glad you got it working.

      Delete
  15. Hi Hussey,

    please help I cant make it. I am having multiple stores in the same website. I do want to share customer account details and session over those stores but i do NOT want to share the shopping cart. So basically once you switch to another store shopping cart at least need to be cleared.

    I wanted to make that with cookie domain and path settings but what ever I do I cant make it...

    ReplyDelete
    Replies
    1. Hi there,

      Unfortunately all user related data, including cart contents is in the same session which is stored to a single session data file. This means you can't pick and choose which session data you want to include if you pull it across in this way.

      You will have to approach the problem in a different way I think. There are various ways in which you can remove items from the cart, so you could do this when switching stores, but it would of course cause problems when switching back to the original store as those cart items would then be removed.

      So it sounds to me like you only really need to keep the user login status on store change rather than share the entire session. I would probably do something along the lines of, if the user is logged in, then append a randomly generated GET request string to the end of the store change urls (rather than the SID), then on store change verify this string, and then automatically log the user in without requiring credentials. As this would essentially allow the user to be become logged in using a GET request.

      This would be an easy approach however bear in mind it allows a user to become logged in via a GET request which although constructed with a random string, still cannot be considered fully secure. A better approach would be to perhaps store a token to the database against the current user but this would require a more in depth solution using a module.

      Delete
  16. Hi Hussey,

    Am using Magento ver. 1.6.1.0. Tried your code but not able to see any dropdown on frontend! Please assist.

    Thanks
    Vishal

    ReplyDelete
    Replies
    1. Hi Vishal,

      This page is intended only as a guide to correctly append and use the right string to URL's for a store switcher you already have showing on your store, it's not a guide on how to add the actual switcher itself.

      I'm sure there is plenty of advice on how to do this out there, and you can also look at the setup of the default Magento install which includes the switcher.

      Delete
  17. Hi Hussey

    I followed the steps but don't have the cart sharing, on 1.7.0.2 though.

    By switcher I take it just a link to the other site would work?

    Also my sites have different products but I put test products in a default category to make sure they were available on the other sites.

    ReplyDelete
    Replies
    1. I haven't explicitly tested this solution on 1.7.0.2 - it was originally written for 1.4, however comments above report it working for 1.6, so I would expect it to work for 1.7 also. With sufficient time however I will be checking all of my solutions against the latest Magento CE version to confirm they work and alter them as necessary.

      If possible I would suggest you try the solution on a clean install of 1.7.0.2 as this will be the best way of telling how it functions.

      Delete
  18. Thanks Hussey, It helped a lot!

    ReplyDelete
  19. I'm able to transfer the cookie/SID so when I move from site1.cm to site2.com it doesn't create a new cookie but takes the old one...

    example: on store1 i have: a cookie ( urlln3e0l8m0cm6e84gli0q802 ) when moving to site2 I've a SID attached to the url thats the same as the cookie ( urlln3e0l8m0cm6e84gli0q802 ) and when I check the cookie on site2 it's the same as the SID and the cookie on site1 ( urlln3e0l8m0cm6e84gli0q802 ) the only thing that changes is the domain instead of site1 it's site2... but that's fine because for security reasons cookies can't be shared between domains... And in the session folder there's only one file created ( sess_urlln3e0l8m0cm6e84gli0q802 )

    so I do not understand why magento do show me nothing in the cart or doesn't keep me signed in when I move from site to site?!?!

    ReplyDelete
    Replies
    1. This solution is considered to work, so if you have followed the changes as above and it's not working as expected for you, there is probably something else affecting things. As a proof of concept I would try it out using a clean Magento install.

      Delete
  20. does this also work for "SITES" or it only works for "STORES"? (Sites with different domains)

    ReplyDelete
    Replies
    1. As stores are grouped under sites, it will work if you are running your stores under different sites yes.

      Delete
    2. And actually reading your question this time, yes it will also work cross domain.

      Delete
    3. thanks for the reply!
      So if I've 2 sites and each has stores for the different languages and currency it'll share the cart and log in session?

      Thank you

      Delete
    4. Yes it should share it fine. All this solution does it essentially tell Magento to start the session using the session data collected from the previous store rather than an empty, new session. I will admit I haven't tested it with 2 different stores on different domains where one currency is not available on the other, but I don't think it should cause any issues. If in doubt, test with a clean install first if you can.

      Delete
    5. I just tried with a fresh install just set up the multisite in local and did the steps above, and I can say that with "MULTISITE" not "MULTISTORE" it doesn't want to share login session and cart (if not logged in) if you're logged it shares the cart but you have to login separately in every site.

      Delete
    6. The login status and cart contents are both stored in the same session, so if one is being carried across, the other will be also. Is the customer account accessible globally rather than just per website? (check System -> Configuration -> Customer Configuration -> Account Sharing Options).

      Delete
    7. Nope, it wasn't. but I set it to global cleared all the caches, magento, browser, server, cleared session files tried on another browser... nothing. Also tried to store session in database instead of file system, nada. That's hella strange. it's like magento doesn't connect the 2 things even if they're in the same file.
      Another thing I just noticed is that moving between sites I lose what's in the cart, e.g. put something in cart in store 1 move to store 2 add something else get back to store 1 it's gone.

      Delete
    8. It sounds to me like the solution isn't quite implemented correctly/fully. It's hard to say what the problem is in your case, but the only comment I can really add is that I have had it working reliably both in local clean install test environments, and on live client stores.

      Delete
    9. I feel dumb. but how could I merge your code above (the one in the stores.phtml) and the one found here (http://stackoverflow.com/questions/4270490/how-do-i-get-a-website-switcher-instead-of-store-switcher)

      I'm asking you because the default code in the stores.phtml file wasn't working was always null when I tried to echo it... This one is working it shows the drop down and and everything but I can't figure out how to merge it with your so It shows the SID. Can you please, PLEASE, tell me what I should change to get it to work? Thank you in advance!

      Delete
    10. BTW I get it working, but I was also right, your code works only with STORES and not with SITES. And the first of many things that can make you understand that is that the store switcher doesn't appear (returns null) if you ain't set no stores. But if you have a BASE WEBSITE with multiple stores with different domains it works...

      like this it works:
      WEBSITE - STORE NAME - STORE VIEW
      - BASE SITE - store1 - store1
      - BASE SITE - store2 - store2

      like this it doesn't work:
      WEBSITE - STORE NAME - STORE VIEW
      - SITE1 - store1 - store1
      - SITE2 - store2 - store2

      Delete
    11. Sorry for not getting back to your last query, time slipped away. Well done for getting it working, I'll do some tests of this solution for a multi store setup under the same domain and update the post where needed when I have time.

      Delete
  21. (maybe it's a server-side problem?)
    Ok, thank you sir. I'll try all over again and see... Wish me luck hahaha :)

    ReplyDelete
  22. I have 2 stores setup in 2 different Method with single magento installation.

    Method 1:
    Main store: www.mystore.com
    2nd store: www.mystore.com/brand1



    Methods 2:
    Main store: www.mystore.com
    2nd store: www.brand1.com (new domain pointed to 2nd store)


    Iam using the main store - Base and Base Link URL.
    Site is working fine, able to view the products added in each stores.


    My Issue is adding products to cart is the problem in Method 2. It shows empty cart.

    But, if I setup my 2nd store to work in Method 1 style, Iam able to add the products to cart.

    Using Magento 1.7.0.2 Version.

    Need your help please.

    ReplyDelete
    Replies
    1. Hi there,

      It sounds like there must be something you haven't done quite right - the solution works fine across different domains on the same install. Just make sure you have the SID correctly appended to the store switch URL's and then as long as you are passing that SID to the $this->setSessionId() call then it will work.

      Delete
  23. hi, i neet to empty the cart if we switch between stores.,
    Use SID on Frontend -- No. doesnt help.

    Can anyone help?

    ReplyDelete
    Replies
    1. You should create different websites for your stores - session data isn't shared between websites so each store would have a different session.

      Delete
  24. Hi,

    We have a request from one of our client, for whom we are using a magento multi store setup.

    The request is as follows:
    The client wants us to show Store 1 cart contents on Store 2 (i.e. on the Mini Cart)

    I have been looking for a solution, but I am not able to find one. Can you please guide me if this is possible.

    Thank you.

    ReplyDelete
    Replies
    1. That's exactly what this post is about, have you followed it? Also see my comment about about stores vs websites and session data.

      Delete