This is a fairly common use case in a lot of E-commerce projects, User has purchased something before, and needs to re-order. Or, a they've has added items to their shopping cart, and we need to email / SMS them a link reminding them to complete the purchase.
I’ve been looking for a solution for Abandoned Cart Recovery for a while now, but one without all the bells and frills that come in the extensions online.
Just needed a simple link to restore the cart contents. After a lot of googling and playing around with the cart, I got it to work.
If you’re looking for a way to recover a customer’s cart contents - here’s the step by step for the same.
We need to work with the CartController file, so lets make a copy of this in our local folder.
This is my file:
1 2 3 4 5 |
- local -- Mage --- Checkout ---- controllers ----- CartController.php |
Getting to the Code:
Pass the order_id in the checkout/cart URL, so in the CartController indexAction we have access to 2 more parameters:
order_id and key
Note: We’re gonna use a key here to confirm the user has indeed clicked on our link and not modified it in any way. A quick option is to use a md5 hash of the order_id with a salt keyword.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 |
$url_params = $this->getRequest()->getParams(); if (isset($url_params['order_id']) && isset($url_params['key'])) { //Check that the key matches the order_id passed if ($url_params['key'] == md5($salt . $url_params['order_id'])) { //Retrieve the Quote Id from Order Object: $order = Mage::getModel('sales/order')->loadByIncrementId($url_params['order_id']); $quote_id = $order->getQuoteId(); if ($quote_id) { //Retrieve the quote: $old_quote = Mage::getModel('sales/quote')->load($quote_id); //Use convert_order to convert the order address object into a quote address object $convert_obj = Mage::getSingleton('sales/convert_order'); $billing_address = $convertObj->addressToQuoteAddress($order->getBillingAddress()); $shipping_address = $convertObj->addressToQuoteAddress($order->getShippingAddress()); //Get the session & cart variables $session = Mage::getSingleton('core/session'); $cart = Mage::getSingleton('checkout/cart'); //Retrieve individual items & populate the cart with each $items = $order->getAllVisibleItems(); foreach ($items as $item) { try { $product = Mage::getModel('catalog/product')->load($item->getProductId()); $options = $item->getProduct()->getTypeInstance(true)->getOrderOptions($item->getProduct()); $info = $options['info_buyRequest']; $request = new Varien_Object(); $request->setData($info); $cart->addProduct($product, $request); } catch (Exception $e) { Mage::getSingleton('core/session')->addError($e->getMessage()); $this->_redirect('checkout/cart'); } } $cart->save(); //Load the address into the checkout session try { $checkout = Mage::getSingleton('checkout/session')->getQuote(); $checkout->setBillingAddress($billing_address); $checkout->setShippingAddress($shipping_address); } catch (Exception $e) { Mage::getSingleton('core/session')->addError($e->getMessage()); $this->_redirect('checkout/cart'); } //Update cart after everything done $session->setCartWasUpdated(true); } else { Mage::getSingleton('core/session')->addError('Sorry, there seems to have been an error. Please try again or Contact Support.'); } //Redirect the user back to the cart so they can successfully proceed with checkout //If we don’t a user refreshing the page would lead to adding the same product over and over again. $this->_redirect('checkout/cart'); } } |
And that’s it. We now have an easy URL ready to use which will populate the cart session back, and a user can picked up when he left off.
How do you invoke this URL? Simple, head over to your Email Templates Section and duplicate your order email. Modify the contents. For example, you may want to remove off the “Payment Method” section, and instead add a Button that says “Complete your Purchase”.
For sending out the emails, I added a simple manual trigger to my order page that reads like this:
Since this is a temporary feature I’ve just shifted the email trigger code outside of my Magento and this is my send-email file:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 |
//Get the Order Details: $order_id = $_GET['order']; //$_GET['order'] should be increment order id $order = Mage::getModel('sales/order')->load($order_id); //Configure the Email: $template_id = 29; // Enter you new template ID $sender_name = Mage::getStoreConfig('trans_email/ident_support/name'); //Get Sender Name from Store Email Addresses $sender_email = Mage::getStoreConfig('trans_email/ident_support/email'); //Get Sender Email Id from Store Email Addresses $sender = array('name' => $sender_name, 'email' => $sender_email); // Set recepient information $recepient_email = $order->getCustomerEmail(); $recepient_name = $order->getCustomerName(); // Get Store ID - I need this since I'm doing it outside of Magento $store_id = Mage::app()->getStore()->getId(); // Set variables that can be used in email template $vars = array('customer_name' => $order->getCustomerName(), 'customer_order_number' => $order->getIncrementId(), 'order' => $order); // Send Transactional Email $mail = Mage::getModel('core/email_template'); $mail->addBcc('add-your-bcc-address@here.com'); $mail->sendTransactional($template_id, $sender, $recepient_email, $recepient_name, $vars, $store_id); Mage::getSingleton('core/session')->addSuccess('The order email was sent!'); Mage::app()->getResponse()->setRedirect($_SERVER['HTTP_REFERER']); Mage::app()->getResponse()->sendResponse(); exit; |
This was because we wanted to do it manually and not automate it as yet.
I will be automating it at some point in the future, but for now, this works well for us. If you are looking to automate it, I’d add a cron job to check up the status of the orders every X minutes, and check for the “pending” or payment failed orders and then trigger the sending of this email.
Note: While converting the order object to quote object, you won't get the email ID by default, as it’s not part of the convert configuration. To get the user’s email ID, in the Mage/Sales/etc/config.xml file you need to add the following to the sales_convert_order_address xml block:
123 <email><to_quote_address>*</to_quote_address></email>
If you've got any modifications to the code or suggestions, drop them in the comments below.
That's all folks!