Сохранение корзины для пользователей


На одном из проектов появилась задача сохранять содержимое корзины для зарегистрированных пользователей, чтобы при последующей авторизации с любого компьютера они имели возможность продолжить покупки, а не добавлять все заново.

В качестве решения получился очень простой плагин, который выполняет 2 действия:
1) Сохраняет содержимое корзины в extended поля пользователя после каждого изменения корзины
2) Восстанавливает содержимое корзины перед каждой обработкой запрошенной страницы.


Возможно, появится вопрос, почему реальная корзина переписывается при каждой обработке страницы и почему нельзя это сделать только при авторизации?
В качестве ответа ситуация:
1) На одном компьютере пользователь добавил капкейк и торт
2) На втором компьютере удалил торт и добавил макаруны
3) При возвращении на первый ПК в корзине окажутся капкейк и макаруны

По коду плагина понятно, какие события нужно активировать в его свойствах.

<?php
switch($modx->event->name) {
    case 'msOnAddToCart':
    case 'msOnChangeInCart':
    case 'msOnEmptyCart':
    case 'msOnRemoveFromCart':
        if ($user = $modx->getAuthenticatedUser('web') and $ms2 = $modx->getService('minishop2')) {
            $ms2->initialize($modx->context->key);
            $profile = $user->getOne('Profile');
            $extended = $profile->get('extended');
            $extended['ms2cart'] = $ms2->cart->get();
            $profile->set('extended', $extended);
            $profile->save();
        }
        break;
        
    case 'OnWebPageInit':
    case 'OnWebLogin':
        if ( $user = $modx->getAuthenticatedUser('web') and  $ms2 = $modx->getService('minishop2')) {
            $ms2->initialize($modx->context->key);
            $profile = $user->getOne('Profile');
            $extended = $profile->get('extended');
            if ( isset($extended['ms2cart']) && !empty($extended['ms2cart']) ) {
                $ms2->cart->set($extended['ms2cart']);
            }
        }
        break;
}

Еще можно добавить сравнение текущего состояния корзины с имеющейся в профиле на случай авторизации при заполненной корзине, но это уже индивидуально.

Оформлять пакет из такого плагина бессмысленно, но если в комментариях идея будет поддержана и развита, возможно появление более функционального варианта в виде компонента.
08 августа 2016, 18:06    Воеводский Михаил   G+  
27    795 +12

Комментарии (10)

  1. Илья Уткин 08 августа 2016, 18:23 # +1
    По-моему, очень нужная вещь. У меня жена только так делает заказы — на мобильном телефоне добавляет всё, что нужно в корзину, потом лишнее убирает, а уже оформляет заказ через компьютер — так удобнее вводить адрес и данные.
    1. Воеводский Михаил 08 августа 2016, 18:27 # 0
      Илья, предлагай расширение функционала :)
      1. Илья Уткин 08 августа 2016, 18:34 # +1
        Нужно сохранять эти корзины в базе данных, с возможностью их просмотра из админки. Но вообще, есть дополнение ordersUnformed. Лучше было бы как-то связаться с автором и предложить внедрить в дополнение функционал восстановления корзин для пользователей. Или делать дублирующее дополнение, но с расширенным функционалом.
        1. Воеводский Михаил 08 августа 2016, 19:19 # 0
          Написал предложение Александру.
    2. Evgeny Epifanov 08 августа 2016, 22:11 # +1
      Очень полезный плагин.
      В качестве расширения функционала:
      — отправлять посетителю на почту письмо с содержимым корзины в автоматическом или ручном режиме.
      1. lexikon 22 ноября 2016, 12:10 # 0
        есть небольшая проблема в логике!
        Если мы формируем заказ будучи не авторизованными, а потом авторизовываемся на странице оформления заказа, то корзина заменяется и мы теряем товары, которые только что сложили.
        Для исправления необходимо чуть поправить событие OnWebLogin
        case 'OnWebLogin':
                if ( $user = $modx->getAuthenticatedUser('web') and  $ms2 = $modx->getService('minishop2')) {
                    $ms2->initialize($modx->context->key);
                    $profile = $user->getOne('Profile');
                    $extended = $profile->get('extended');
                    if ( isset($extended['ms2cart']) && !empty($extended['ms2cart']) ) {
                        $currentcart = $ms2->cart->get();
                        $cart = array_merge($currentcart, $extended['ms2cart']);
                        $ms2->cart->set($cart);
                    }
                }
                break;
        1. Воеводский Михаил 22 ноября 2016, 12:17 # 0
          Тоже нельзя сказать, что это идеальное решение. Все зависит от конкретного случая. Потому пусть будут оба варианта, а разработчики сами для себя выберут подходящий.
          1. lexikon 22 ноября 2016, 12:21 # 0
            так и есть, только индивидуально… в моем случае есть возможность авторизоваться непосредственно на странице оформления для того, чтобы заполнить все поля за пользователя, а тут получается заподлянка какая-то(сложил одно, а в заказ упало другое)

            Хорошим решением будет отличать устройства, если же устройства одни и те же — то корзину не восстанавливать! Иначе восстановить.
            1. lexikon 03 декабря 2016, 11:40 # 0
              Тут столкнулся с проблемой, msPromoCode не работает с данным решением, вообще хрень полная происходит, концов не найти) походу по событию msOnChangeInCart перезаписывает данные, которые уже обновлены.
              1. Воеводский Михаил 03 декабря 2016, 23:02 # 0
                Данное решение является лишь направлением для мысли и, естественно, легко может конфликтовать с любыми похожими алгоритмами. В качестве решения попробуйте изменит приоритеты плагинов. Если не поможет, придется самостоятельно вникать в суть конфликта.
          Вы должны авторизоваться, чтобы оставлять комментарии.