Here is how I was able to keep the cart between websites.
The solution is not fully tested yet but for me it seams to work.
[Update]
Warning: I seams that this solution doesn't work with multiple currencies installed. See comments from MichaĆ Burda
[/Update]
If someone tries it please let me know the result and eventual bugs that appear.
Preconditions:
- 'Use SID on Frontend' must be st to 'Yes' (System->Configuration->Web->Session Validation Settings)
Magneto already allows you to keep the quote (cart) between store views from the same website.
I tried to manipulate this feature into letting me keep the cart between all websites (store views).
How is the quote kept in $_SESSION?
Magento keeps the quote id in the $_SESSION like this:
$_SESSION['quote_id_5'] = 34;In the code above, 34 represents the quote id and 5 represents the website it (not store view id).
So it's basically like this:
$_SESSION['quote_id_{WEBSITE_ID}'] = {QUOTE_ID};This means that the quote is different for each website.
Now for the actual code:
I've created a new extension called Easylife_Sales.
The extension has a fail-safe, in case it doesn't work as expected, it's behavior can be disabled from the configuration area. but more on this later.
Extension files:
app/etc/modules/Easylife_Sales.xml - declaration file
<?xml version="1.0"?> <config> <modules> <Easylife_Sales> <active>true</active> <codePool>local</codePool> <depends> <Mage_Sales /><!-- so it's loaded after Mage_Sales --> <Mage_Checkout /><!-- so it's loaded after Mage_Checkout --> </depends> </Easylife_Sales> </modules> </config>app/code/local/Easylife/Sales/etc/config.xml - configuration file
<?xml version="1.0"?> <config> <modules> <Easylife_Sales> <version>0.0.1</version> </Easylife_Sales> </modules> <global> <models> <sales> <rewrite> <observer>Easylife_Sales_Model_Observer</observer> <quote>Easylife_Sales_Model_Quote</quote> </rewrite> </sales> <checkout> <rewrite> <session>Easylife_Sales_Model_Checkout_Session</session> </rewrite> </checkout> </models> <helpers> <sales> <rewrite> <data>Easylife_Sales_Helper_Data</data> </rewrite> </sales> </helpers> </global> <frontend> <events><!-- this section is not mandatory, explanations later --> <sales_quote_collect_totals_before> <observers> <easylife_sales> <class>sales/observer</class> <method>checkProductAvailability</method> </easylife_sales> </observers> </sales_quote_collect_totals_before> </events> </frontend> <default> <checkout> <options> <persistent_quote>1</persistent_quote><!-- this is for the fail-safe --> </options> </checkout> </default> </config>app/code/local/Easylife/Sales/Helper/Data.php - override the default sales helper to add the fail-save method
<?php class Easylife_Sales_Helper_Data extends Mage_Sales_Helper_Data{ public function getIsQuotePersistent(){ return Mage::getStoreConfigFlag('checkout/options/persistent_quote'); } }app/code/local/Easylife/Sales/Model/Checkout/Session.php - override the default checkout session in order to change the session key for the quote
<?php class Easylife_Sales_Model_Checkout_Session extends Mage_Checkout_Model_Session{ protected function _getQuoteIdKey() { if (Mage::helper('sales')->getIsQuotePersistent()){//if behavior is not disabled return 'quote_id'; } return parent::_getQuoteIdKey(); } }app/code/local/Easylife/Sales/Model/Quote.php - override the quote model to share between all websites
<?php class Easylife_Sales_Model_Quote extends Mage_Sales_Model_Quote{ public function getSharedStoreIds(){ if (Mage::helper('sales')->getIsQuotePersistent()){//if behavior is not diasabled $ids = Mage::getModel('core/store')->getCollection()->getAllIds(); unset($ids[0]);//remove admin just in case return $ids; } return parent::getSharedStoreIds(); } }app/code/local/Easylife/Sales/etc/system.xml - this allows you do disable the functionality in case something is wrong.
<?xml version="1.0"?> <config> <sections> <checkout> <groups> <options> <fields> <persistent_quote translate="label" module="sales"> <label>Keep cart between websites</label> <frontend_type>select</frontend_type> <source_model>adminhtml/system_config_source_yesno</source_model> <sort_order>100</sort_order> <show_in_default>1</show_in_default> <show_in_website>0</show_in_website> <show_in_store>0</show_in_store> </persistent_quote> </fields> </options> </groups> </checkout> </sections> </config>We are almost done. At this point the following happens. If you have a product in cart, you change the website and the product is not available in the new site the product is still in the cart. If you want this behavior then there is no problem. All you need to do is to remove these lines from config.xml
<observer>Easylife_Sales_Model_Observer</observer>and
<events><!-- this section is not mandatory, explanations later --> <sales_quote_collect_totals_before> <observers> <easylife_sales> <class>sales/observer</class> <method>checkProductAvailability</method> </easylife_sales> </observers> </sales_quote_collect_totals_before> </events>In my case I wanted to remove from cart (permanently) the products that are not available in that website. if you want this behavior add the following file: app/code/local/Easylife/Sales/Model/Observer.php - this will remove from cart the products that are not valid on the current store.
<?php class Easylife_Sales_Model_Observer extends Mage_Sales_Model_Observer{ public function checkProductAvailability($observer){ if (!Mage::helper('sales')->getIsQuotePersistent()){ return $this; } $quote = $observer->getEvent()->getQuote(); $currentId = Mage::app()->getWebsite()->getId(); $messages = array(); foreach ($quote->getAllItems() as $item){ $product = $item->getProduct(); if (!in_array($currentId, $product->getWebsiteIds())){ $quote->removeItem($item->getId()); $messages[] = Mage::helper('catalog')->__('Product %s is not available on website %s', $item->getName(), Mage::app()->getWebsite()->getName()); } } foreach ($messages as $message){ Mage::getSingleton('checkout/session')->addError($message); } return $this; } }Well that's about it. Enjoy and let me know how it turns out.
Marius.
Hi !
ReplyDeleteI've tried your extension, but when I flushed the cash it showed me a fatal error for "getQuoteId() on a non-object" ... I'm working on Magento 1.4.1.0
Thanks for helping, hope it'll help you back ;)
I'm not sure this works on 1.4. I only tested and managed to make it work only on 1.7 (and ee 1.12)
DeleteHi
ReplyDeletenice extension.
Is there trouble printing the invoice
The invoice is generated without problems, but when printing stays on a blank page...
i hope found the solution ;)
thanks
To be honest, I didn't test the invoice printing. I did this for a website that managed the invoices shipments and credit notes outside Magento so I didn't bother to check. I will test and come back with a solution. Until then make sure that this code generated the error. Disable the extension and try to print an invoice. See if the error reproduces.
Deletehi
ReplyDeleteI have two website in magento 1.7.0.2.
I used this module but its not working in checkout cart in magento 1.7.0.2.
When I add Product in website1 and then when I check website2 it shows empty cart.
Did you set 'Use SID on Frontend' to 'Yes'? (System->Configuration->Web->Session Validation Settings). If you did you can try skipping the last part (the observer that removes the products from the quote). If that doesn't work either...I'm out of ideas. Sorry.
Deletethanks for your rply..
ReplyDeletebut i want if one product is not availble in one website but shown this products in both website cart...
hi
ReplyDeleteplz reply me as early as possible.
I want to show cart same for two website if product is not availble in any website.
Like I said...this code worked for me, I didn't test it very much on different Magento versions and different configurations. I really have no idea why it doesn't work for you. Maybe this helps you debug the issue: http://magento.stackexchange.com/questions/428/fundamentals-for-debugging-a-magento-store
DeleteHi, can you tell me if this works with different currencies. I'll be immensely grateful. I've been trying to find the best solution. As far I managed to share a cart between websites - but... on one shop I must have all the products (that's bot very convenient, but bearable - the ones from second store are added to a category that is not visible on store), however the second thing is currency. I would like to operate on 2 currencies, unfortunately when I allow different currency it completely messes with the mechanism. Once again I'll be very grateful if you could tell me if it works with 2 currencies :))
ReplyDeleteYou might be on to something here. I didn't test with multiple currencies. Can you give more details about "completely messes with the mechanism"? What exactly happens when you change the currency? Please give a scenario step by step and describe the result you are getting.
Deletewith my solutions (not yours, to be clear):
ReplyDeleteI have 2 available currencies: PLN and Euro
When you change to PLN everything is still added in the cart with euro prices (because alphabetically euro is before Zloty(PLN), so when you want to buy things in PLN you can't check out with this currency but only with euro.
I have 2 different websites with 2 different Store View (polish, english) - right now I was forced to turn off second currency (euro) for english store views
Thanks for the scenario. I will try to reproduce it and if/when I come up with a solution I will post it.
DeleteMarius I've just tested your solution and everything works like a charm, including currencies ! BIG THANKS
ReplyDeletehttp://gold.yasmeen.pl
http://nowysklep.yasmeen.pl
You can check it here
Works perfect Maurius. You are a real saviour.
ReplyDeleteOne of my clients have a store with three different websites under same domain but with different sub-directories (http://www.domain/ => USD store , http://www.domain/ represents EURO store). They have different prices in different currency (No conversion). This makes sure if i change the websites , the right price with the right currency adds for the products in the cart.
Thanks a lot for this simple module ;-)
You really deserve a beer for this simple module, your answers on stackexchange and all the above ModuleCreator.
Where can we download this extension?
ReplyDeleteBest,
Miha
I didn't make this an extension, because I didn't get to test much. I've only developed it for a specific project I was working on and it turned out to solve the issue on that project. But you can find the full code in this post. Maybe it works for you also.
DeleteHi,
ReplyDeleteThanks for hard work, actually i want the opposite of everyone is looking for, i am looking to restrict cart sharing in store level in same website, i mean if user add to cart 1 product from store A and the used store switcher (magento slandered) to move to store B, (both A & B under same website) here exactly i want to keep him logged in (if registered) and clear his cart so when he is in store B the cart is empty
Note: setting a warning popup about loosing cart items is easy to set
So please if there is anyone has an idea about that to help us ASAP
Thanks
I didn't try what you are asking for, but I think it can be achieved following the same code as above. What you need to change is `Easylife_Sales_Model_Quote::getSharedStoreIds` to make it return only the current store id instead of all and maybe the session key for the quote `Easylife_Sales_Model_Checkout_Session::_getQuoteIdKey` to make it return `quote_id_{CURRENT STORE ID}`. Give it a try and let me know if it works or if at least gets you in the right dirrection
DeleteHi friend,Your extension works beautifully! however, I could see something and do not know if it has to do with its length. Products with more than 1 quantity it multiplies the value by the amount of shipping product, when to go to intermediate payment. Could you help me?
ReplyDeleteYour issue started after you implemented the code In this post? To make sure, just disable the "extension" and see if the issue reproduces. This never happened to me. I honestly have no idea where to start.
Deletereally is not an error in your code. the error persists even disabling the sharing cart. Thank you for your attention, the extension is wonderful!
Deletehi Marius,
ReplyDeletethanks for your work. I used it in 1.8.0 and works fine!
Hi,
ReplyDeletethis extension works great, thanks! However it doesn't seem to be working for users that are NOT logged in?
Are you able to help me configure this so it does?
Does this work for 1.8 ... ?
ReplyDeleteI can't tell you for sure. I haven't tested on 1.8. If you try it please post here the results.
Deletehi,
ReplyDeleteI'm trying to use this features and I can't get it work while using FLAT category and FLAT products.
If the products is not available at the website the cart is empty, if the product is available, it works great.
Can some send met his extension?
ReplyDeleteSorry but there is no extension. It is just the code shown above. I didn't make it an extension because it was not fully tested with all the possible site/cart configurations. It may not work on certain conditions, but it may serve you as a starting point.
DeleteIn version 1.8.1 works perfectly as long as Use Flat Catalog Product & Use Flat Catalog Category are both set to No. Otherwise cart is empty if product is not available on the website you are changing to.
ReplyDeleteI didn't try it, but I thing you are right. And I see why. When using the flat catalog, the products that are not available in a certain store view are not indexed in the flat tables. So when switching websites, if a product in cart is not found in the new store it can remain in the cart. I have no idea how you can overcome this other than disabling flat catalog.
DeleteThat does sound correct. I went with disabling the flat catelog at this stage.
DeleteMy only problem now is if you click on a product in the cart that belong's to a different website it try's to locate the product on the current website instead of linking back to the original website.
Yeah...I think this is a totally different problem. The product links from the cart always link to the product in the current website. I have no idea how to overcome this. Maybe keep a reference to the store view it was added on in a separate field and try to build the url in the cart based on that reference. But I'm not sure this will work.
DeleteManaged to get it sorted out. Probably not the cleanest way, but it will do for now. If anyone else need's the solution just follow below.
DeleteEdit template/checkout/cart/item/default.phtml and add the following code:
$productStoreId=implode("",$_item->getProduct()->getStoreIds());
And then change $this->getProductUrl()
to
$this->getProduct()->setStoreId($productStoreId)->getProductUrl()
Hey... that actually looks nice and simple.
Deletethank you,it working!Can you separate the order order of goods corresponding to their stores . that will be perfect
ReplyDeleteI have tried to replicate your extension however I am getting
ReplyDeleteMage registry key "_singleton/sales/observer" already exists
Any ideas on how to fix?
Did you clear the cache? check if the file names are properly upercased or lowercased.
DeleteI'm having the same issue. Triple checked the files names (copy pasted every file/folder name from your blog)
DeleteI keep getting: Mage registry key "_singleton/sales/observer" already exists
It's fixed when I remove Easylife_Sales_Model_Observer and the other block of code but then the extension does nothing for me.
I've got a deadline for this Monday and I really don't know how to fix this. Hope you can help me out.
Hi, I get the same error, everything is ok with file names? Any ideas?
ReplyDeleteI am getting this error by using your code when i try to add a product in cart Fatal error: Call to a member function setStoreId() on a non-object in /home/bmessg/public_html/teamwear1/app/code/core/Mage/Checkout/Model/Session.php on line 122
ReplyDeleteI' getting the same error as the Post of November 18, 2015 3:48:00 PM.
ReplyDeleteMage registry key "_singleton/sales/observer" already exists
Cache has been cleared multiple times and filenames have been copy&pasted... Only /code/core/Mage/Sales/etc/config.xml has the same sales/observer class registered.
Magento v1.9.2.1
Thanks for any idea!
Ok when removing Easylife_Sales_Model_Observer.
DeleteThanks for this.
ReplyDeleteIn our setup, we set all products to belong to all stores. Both stores share one root catalog. Using the code given here allowed the cross cart functionality to work 100%. However, and issue with having products assigned to both sites is search results. The products from the other store appear in the current store search results.
I overcame this by limiting the search collection to all active categories in the current site. End result is correct products as each site has its own active categories set in the root catalog.
Listen to event: catalog_product_collection_apply_limitations_after
code:
public function catalog_product_collection_apply_limitations_after(Varien_Event_Observer $observer)
{
$collection = $observer->getCollection();
$hasApplied = $collection->getFlag('not_available_set');
if (empty($hasApplied)
&& $collection instanceof Mage_CatalogSearch_Model_Resource_Fulltext_Collection
) {
$helper = Mage::helper('catalog/category');
// sorted by name, fetched as collection
$categoriesCollection = $helper->getStoreCategories('name', true, false);
$categoryIds = $categoriesCollection->getAllIds();
// adjust collection and sort not available products to the end.
$collection->joinField(
'category_id', 'catalog/category_product', 'category_id',
'product_id = entity_id', null, 'left'
)
->addAttributeToFilter('category_id', array('in' => $categoryIds))
->setFlag('not_available_set', true);
$collection->getSelect()->distinct();
$collection->getSelect()->group('e.entity_id');
}
return $this;
}