2

When using Commerce 2, is there a way to fill a client's cart with the contents of an (inactive) cart, by using a link? Use case: abandoned cart email.

4

There is currently no way to populate a cart from a link as a standard feature of Commerce 2.

But you could accomplish this in 2 ways.

1) With a smart template to add all items from the order to the current cart.

Create a template that takes an order number param like so:

cart/start-order?number=5bnuy8843nuy48bdy48u3bd84

In that template you would do the following:

{# @var craft \craft\web\twig\variables\CraftVariable #}

{% set number = craft.app.request.param('number') %}
{% set previousOrder = craft.orders.number(number).one() %}

{% if not order %}
  {% redirect 'shop' %}
{% endif %}

{# Get the current cart if there is one, also make sure the cart is persisted so we can add to it. #}

{% if cart is not defined %}
  {% set cart = craft.commerce.getCarts().getCart(true) %}
{% endif %}

{# Clears the current cart. This is optional as you may just want to add the items to the cart #}
{% do cart.setLineItems([]) %}

{% for oldLineItem in previousOrder.lineItems %}

  {% set lineItem = craft.commerce.lineitems.createLineItem(cart.id, oldLineItem.purchasableId, oldLineItem.options, oldLineItem.qty, oldLineItem.note) %}

  {% do cart.addLineItem(lineItem) %}

{% endfor %}

{% do craft.app.elements.saveElement(cart) %}

{%  for lineItem in cart.lineItems %}
  {{  lineItem.qty }} * {{ lineItem.description }}
{%  endfor %}

This add all items from the cart in the email link to the current cart. You would do a similar thing to populate addresses etc if you wish.

2) Alternatively, if you just want to replace the current cart in the users session with the incomplete cart you passed in from the email’s number param, you could do the following

  • Create a plugin/model with a controller action.
  • The controller action would accept an order number param (like the template example above)
  • The controller action would do the following:

Code:

$request = Craft::$app->getRequest();
$session = Craft::$app->getSession();

$number = $request->getParam('number');
$order = \craft\commerce\elements\Order:find()->number($number)->one();

if ($order && !$order->isCompleted){
  // Forget the current cart in their session.
  \craft\commerce\Plugin::getInstance()->getCarts()->forgetCart();

  $session->set('commerce_cart', $number);
  return $this->redirect('shop/cart');
}

return $this->redirect('shop/cartLoadError');

This should get you mostly there. Let me know if you have any questions.

  • Thanks for these solutions, Luke! Will there be functionality like this in Commerce (as it's a very common use case), that would make it a better choice to wait a bit? – Paul Nov 28 '18 at 12:30

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.