Оформление заказа в корзине: адаптация тем дизайна

Дмитрий Елшин

В Shop-Script 8 появился ещё один способ оформления заказа — на одной странице с корзиной. Расскажем, как адаптировать темы дизайна для поддержки нового режима, а также о возможностях для работы с корзиной и оформлением заказа.

Пример оформления заказа в корзине. Тема дизайна "Default".

Подключение оформления заказа в корзине

Создайте файл order.html в теме дизайна для приложения Shop-Script и объявите его в theme.xml. Пример файла можно посмотрить в исходном коде темы дизайна «Дефолт».

В настройках витрины для настройки «Вид оформления заказа» выберите «Оформление заказа в корзине».


Витрина должна уметь поддерживать и пошаговое оформление заказа. Для формирования актуальных ссылок на корзину или страницу оформления используйте методы шаблонов Webasyst:

{$wa->shop->checkout()->cartUrl( $absolute = false )} {* ссылка на корзину *} 
{$wa->shop->checkout()->url( $absolute = false )} {* ссылка на страницу оформления заказа *}

Оформление

Файл order.html решает две задачи:

  1. Отображение пустой корзины, когда покупатель ещё не выбрал товары для покупки.
  2. Отображение корзины и формы оформления заказа с помощью методов шаблонов:
    • Блок корзины
      <div id="js-order-cart">
          {$wa->shop->checkout()->cart([
             "wrapper" => "#js-order-cart"
          ])}
      </div>
      
    • Блок оформления заказа
      <div id="js-order-form">
          {$wa->shop->checkout()->form([
             "wrapper" => "#js-order-form"
          ])}
      </div>
      

Допустимые параметры для этих методов:

  • wrapper string Обязательный параметр, содержащий селектор контейнера блока. На этот элемент будут ссылаться события и ему будут присваиваться data-атрибуты, необходимые для оформления заказа.
  • DEBUG bool Выводит в консоли браузера информацию о ходе работы. Значение по умолчанию — false.
  • adaptive bool Включает применение внутренних адаптивных стилей к элементам блока. По умолчанию — true.

При успешном оформлении заказа пользователь автоматически перенаправляется на страницу с адресом checkout/success/.

Доступные события JavaScript

Корзина

  • wa_order_cart_ready: корзина загрузилась, контроллер инициировался. В параметрах передается ссылка на контроллер.
  • wa_order_cart_changed: содержимое корзины было изменено на сервере. В параметрах передаются обновлённые данные с сервера.
  • wa_order_cart_rendered: корзина визуально обновлена на основе данных с сервера. В параметрах передаются обновлённые данные с сервера.
  • wa_order_cart_cleared: корзина очищена. В параметрах передаются обновлённые данные с сервера.
  • wa_order_cart_reloaded: DOM корзины перезаписан. В параметрах передается ссылка на новый контроллер.

Форма оформления заказа

  • wa_order_form_ready: форма загрузилась, контроллер инициировался. В параметрах передается ссылка на контроллер.
  • wa_order_form_changed: DOM некоторых блоков формы перезаписан. В параметрах передаются обновлённые данные с сервера.
  • wa_order_form_(auth | region | shipping | details | payment | confirm)_changed: DOM соответствующего блока формы перезаписан. В параметрах передаются обновлённые данные с сервера.
  • wa_order_form_reloaded: DOM формы перезаписан. В параметрах передается ссылка на новый контроллер.
  • wa_order_form_created: в параметрах передаются обновлённые данные с сервера.

Если вам требуются дополнительные события, напишите о них в комментариях.

Особенности и рекомендации

Версии браузеров

Страница оформления заказа в корзине работает в большинстве последних версий браузеров Chrome, Firefox, Safari и Edge и Internet Explorer не ниже 11-й версии.

Рекомендации по оформлению

  • В файле order.html реализуйте вёрстку контейнеров для корзины и формы заказа. Важно предусмотреть их адаптивность для мобильных устройств и других устройств с малой шириной экрана.
  • Ширина каждого блока не менее 375px.
  • При ширине экрана свыше 900px блоки выравниваются по горизонтали.
  • Каждый блок содержит стандартные адаптивные стили. Если разработчику требуется написание собственных стилей адаптации, передайте параметр "adaptive" => false при формировании HTML-кода блока.
  • Рекомендуется не делать серьёзных структурных изменений в стилях CSS в оформлении элементов. Некоторые JavaScript-скрипты зависят от свойств элементов (пример: слайдер с фото).
  • Рекомендуется не изменять JavaScript-логику внутренних контроллеров и взаимодействовать посредством событий, которые выполняются на "wrapper", указанный при формировании HTML-кода блока.

График работы магазина

В Shop-Script 8 график работы магазина настраивается более гибко, чем раньше, поэтому тема дизайна теперь должна уметь обработать массив данных о днях и часах работы магазина и показать результат посетителям сайта. Информацию о графике работы возвращает метод

{$wa->shop->schedule()}

В возвращаемом массиве элемент с ключом current_week содержит подмассив элементов, которые соответствуют дням недели. Каждый день недели здесь — массив со следующими ключами:

  • name string: название дня недели
  • work bool: флаг, обозначающий рабочий день
  • start_work string: время начала работы
  • end_work string: время окончания работы
  • end_processing string: время окончания обработки заказов

В этом массиве учитываются настройки для дней недели и дополнительных рабочих и выходных дней.

Массив, возвращаемый методом {$wa->shop->schedule()}, содержит, кроме current_week, также следующие элементы:

  • mode string: значение 'default' (используется общий график работы магазина) или 'custom' (используется собственный график работы в настройках оформления заказа в корзине для этой витрины)
  • timezone string: Идентификатор временной зоны, выбранной в настройках графика работы
  • week array: массив настроек для каждого из дней недели без учёта дополнительных рабочих и выходных дней
  • extra_workdays array: массив информации о дополнительных рабочих днях — каждый в виде массива с ключами
    • date: дата в формате DATE SQL
    • start_work
    • end_work
    • end_processing
  • extra_weekends array: массив дат дополнительных выходных дней в формате DATE SQL

Пример использования данных графика работы есть в исходном коде темы дизайна «Дефолт».

Формы авторизации, регистрации и восстановления пароля

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

{* Авторизация *}
{$wa->loginForm($error, [
    'show_oauth_adapters' => true
])}

{* Регистрация *}
{$wa->signupForm($errors, [
    'show_oauth_adapters' => true
])}

Обмен данными между формами и сервером происходит в формате JSON. Благодаря этому удобно встраивать формы во всплывающие диалоги.

При взаимодействии пользователя с формой обрабатываются следующие события JavaScript:

  • wa_auth_form_loaded: форма авторизации загрузилась.
  • wa_auth_form_change_view: DOM формы изменился (например, показались сообщения об ошибках, появилось поле для ввода кода и т. п.).
  • wa_auth_contact_logged: контакт авторизован. В качестве параметра передаётся объект contact с единственным полем id.
  • wa_auth_set_password: событие, сообщающее о возможности перехода на форму setpassword. В параметрах передаётся строка hash — у этого значения ограниченное время жизни, оно необходимо для установки нового пароля. Без валидного хеша форма setpassword вернёт ошибку 404.
  • wa_auth_reset_password: новый пароль установлен.
  • wa_auth_resent_password: пароль отправлен пользователю.
  • wa_auth_contact_signed: контакт зарегистрировался. В качестве параметров передаются флаг password_sent — был ли отправлен пароль пользователю в режиме генерации пароля, и объект contact с единственным полем id. При возникновении ошибки параметр contact может иметь тип undefined.
7 ноября 2018
  • BNP (Дмитрий) 4 февраля 2019 16:52

    Марк, спасибо за развернутый ответ. Буду пробовать =)

  • BNP (Дмитрий) 4 февраля 2019 20:26

    Вроде начинае тскладываться.

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

    Например:

    Object { name: "payment[html]", value: 1 }

    и все. А где тотал, сумма за доставку и прочее? =()

  • golubevmark Webasyst 5 февраля 2019 11:47

    @BNP (Дмитрий)

    controller.getFormData()

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

    На разных этапах заполнения формы набор данных разный. Например, не заполнив данные о регионе, вы не сможете узнать данные о вариантах доставки. Зависимость такая [region] > [shipping] > [details] > [payment] > [confirm].

    Я примерно понял ход ваших мыслей, вы хотите оперировать суммами через JS. Эти данные, к сожалению, нельзя получить через JS. Могу посоветовать вам использовать подход через хуки. А именно изучить shopCheckoutStep::processAll(), все что начинается с "checkout_"

  • Замковский Максим 27 февраля 2019 09:58

    Оформление заказа в корзине
    Пошаговое оформление заказа

    как в плагине узнать какой из вариантов текущий (значение checkout_version)?

  • Дмитрий Елшин Webasyst 27 февраля 2019 11:24

    Максим, можете использовать такую конструкцию:

    $route = wa()->getRouting()->getRoute();
    $checkout_version = ifset($route, 'checkout_version', 1);
    if ($checkout_version == 2 && !empty($route['checkout_storefront_id'])) {
        // In-cart checkout
    } else {
        // Multi-step checkout
    }
  • enso_studio@mail.ru 27 февраля 2019 11:42

    Максим, все что в настройках поселения задано доступно в {wa_dumpc($wa->param())}

    array(
      'app' => 'shop',
      'theme' => 'default',
      'theme_mobile' => 'default',
      'checkout_version' => '2',
      'locale' => 'ru_RU',
      'title' => '',
      'meta_keywords' => '',
      'meta_description' => '',
      'og_title' => '',
      'og_image' => '',
      'og_video' => '',
      'og_description' => '',
      'og_type' => '',
      'og_url' => '',
      'url_type' => '0',
      'type_id' => '0',
      'currency' => 'RUB',
      'stock_id' => '1',
      'public_stocks' => '0',
      'drop_out_of_stock' => '0',
      'payment_id' => '0',
      'shipping_id' => '0',
      'checkout_storefront_id' => '781f994173ef9cc48ae7cefe4c881261',
      'module' => 'frontend',
      'action' => 'order',
    )

  • Евгений Леман 2 мая 2019 00:54
    {if $wa->shop}
        {if method_exists($wa->shop, 'checkout')}
            {$_cart_url = $wa->shop->checkout()->cartUrl()}
        {else}
            {$_cart_url = $wa->getUrl('shop/frontend/cart')}
        {/if}
    {/if}

    Я может что-то не так делаю, но эта конструкция работает только внутри шаблонов магазина. При включенном оформлении в корзине, ссылка ведет на /cart/, если мы находимся на страницах сайта/блога. А если при этом магазин находится по адресу /shop/*, то и вовсе 404 ошибку получаю, т.к. продолжает кидать на /cart/.

    Вопрос. Как корректно дать в шаблонах ссылку на корзину?

  • enso_studio@mail.ru 2 мая 2019 12:11

    Евгений, а ты задумывался как вообще такая ссылка будет работать при 2х поселениях магазина?

  • Евгений Леман 2 мая 2019 15:05
    Евгений, а ты задумывался как вообще такая ссылка будет работать при 2х поселениях магазина?

    Выдавать ссылку хотя бы на первый shop в массиве поселений? Но явно не на статичный /cart/, когда поселения в корне может и не быть.

  • km 29 мая 2019 10:01

    Можно в JS отключить принудительный `calculate` и самостоятельно его дергать?

  • golubevmark Webasyst 29 мая 2019 11:01

    @km, Здравствуйте.

    Принудительно отключить calculate нельзя.

  • km 29 мая 2019 11:06

    Это конечно крайне печально. Придется извращаться с удалением и возвращением обработчиков событий(

  • Halifax 29 мая 2019 16:53

    Не понятно как поправить шапку такой корзины.
    Как получить доступ к файлу, например, чтобы сделать адаптивную верстку, или что-то изменить в шапке? 
    Никак не могу найти.

  • golubevmark Webasyst 29 мая 2019 17:02

    @Halifax, Здравствуйте. Что вы подразумеваете под "шапкой" ?

    Если речь про шапку, где написано "Корзина" и "Оформление", то это реализует тема дизайна в файле "order.html".

  • Магазинчик 25 июля 2019 14:09

    Здравствуйте. Тоже не могу понять как редактировать страницу, например:

    Как убрать текст "Этот заказ добавит +142.5 бонусных баллов, которые вы затем сможете использовать для получения дополнительных скидок." или сделать его видимым только для залогиненых пользователей, где сам этот html код не найду((

    В форме где Имя, Телефон, Адрес и т.д. добавить подсказки типа, email можно оставить пустым если нету
    (у нас ЦА женщины за 30-40-50, часто пытаются заполнить email текстом "нету" и заказ не могут оформить).

    То есть где редактировать сам блок корзины и блок оформления заказа, редактирование страниц cart и checkoute не к чему не приводят

  • golubevmark Webasyst 29 июля 2019 10:41

    @Чингис Индраев

    Как убрать текст

    У вас есть контроль над вашей темой, и над её CSS в частности. Не вижу сложности написать css правило, которое скроет этот блок.

    ..добавить подсказки..:

    Добавление подсказок для полей на данный момент не предусмотрено.

    Где редактировать сам блок корзины:

    Содержимым этого блока управляет приложение "магазин". Редактирование блока с вашей стороны не предусмотрено умышлено, но есть множество настроек в разделе "оформление заказа".

  • CiE 31 июля 2019 22:48

    День добрый. Подскажите как быть?

    Есть у меня плагин "Товары-Комплекты", чтобы он работал, я внес изменения в файл js/cart.js . Комментариями видно что добавил.

     

    $(".Cart__Form a.delete").click(function () {
    	    var that = $(this); // участок для отслеживания количества товара для плагина комплекты
    		var row = $(this).closest('div.row');
    		$.post('delete/', {html: 1, id: row.data('id')}, function (response) {
    			if (response.data.count == 0) {
    				location.reload();
    			}
    			row.remove();
    			updateCart(response.data);
    			// участок для отслеживания количества товара для плагина комплекты
    			if (typeof $.itemsetsFrontend !== 'undefined') {
                               $.itemsetsFrontend.cartDelete(that);
                            } //
    		}, "json");
    		return false;
    	});

    и 

    $(".Cart__Form input.qty").change(function () {
    		var that = $(this);
    		if (that.val() > 0) {
    			var row = that.closest('div.row');
    			if (that.val()) {
    				$.post('save/', {html: 1, id: row.data('id'), quantity: that.val()}, function (response) {
    					row.find('.item-total').html(response.data.item_total);
    					if (response.data.q) {
    						that.val(response.data.q);
    					}
    					if (response.data.error) {
    						alert(response.data.error);
    					} else {
    						that.removeClass('error');
    					}
    					updateCart(response.data);
    					// кусок кода для отслеживания количество на складе при изменении количества для плагина комплекты
                		                if (typeof $.itemsetsFrontend !== 'undefined') {
                                                   $.itemsetsFrontend.quantityChange(that);
                                            } //
    				}, "json");
    			}
    		} else {
    			that.val(1);
    		}
    	});

    Все это замечательно работало в пошаговом режиме оформления. (Тема уже имеет все настройки для работы нового одностраничного режима.)

    Но сейчас включен режим одностраничного оформления заказа и я никак не пойму в какой файл внести правку и что именно писать? Подскажите, как отловить нужные мне события изменения количества?

    Я так понимаю что яваскрипт нужно добавлять в файл partials/cart/order.htm

  • golubevmark Webasyst 1 августа 2019 10:42

    @CiE

    Я вам советую обратить внимание на следующие события, и изучить данные, что там приходят в ответе.

    • wa_order_cart_changed: содержимое корзины было изменено на сервере. В параметрах передаются обновлённые данные с сервера.
    • wa_order_cart_rendered: корзина визуально обновлена на основе данных с сервера. В параметрах передаются обновлённые данные с сервера
  • UserBot 1 октября 2019 19:43

    Где найти шаблон корзины. Мне нужно сделать во фронтенде корзины, под ценой вывод блока с фразой по условию (если id типа товара такое-то, то такая приписка html под ценой) {if $item.product.type_id==6} текст{/if}. Это никак на формирование корзины не отражается, просто доп инфа для пользователя.

    Как ее добавить в шаблон. Я не могу найти шаблон вывода.

    <div class="s-section-body">
    {$wa->shop->checkout()->cart([
    "DEBUG" => true,
    "wrapper" => "#js-order-cart"
    ])}
    </div>
  • golubevmark Webasyst 2 октября 2019 10:26

    @UserBot

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

    Есть также вариант через JS темы, который переместит html-блок из темы в корзину, но это нестабильное экспериментальное решение, его я тоже рекомендовать не буду :)

  • UserBot 2 октября 2019 14:15

    /wa-apps/shop/templates/actions/frontend - шаблон находится вот здесь. FrontendOrderCart.html - почему его нельзя было сделать в шаблоне для меня загадка. Может кому-то понадобится, как временное решение.

  • Евгений Леман 9 октября 2019 17:54

    Внутри темы можно как-то определить используемый тип оформления в текущей витрине?

  • Магазинчик 12 октября 2019 02:43

    1. Можно ли как то сделать так, что бы ВСЕ поля Адреса доставки отображались сразу, до выбора страны, региона, варианта доставки? (Либо сделать по умолчанию например Почту России)

    2. Можно ли сохранять уже заполненные поля доставки, при смене Варианта доставки? Бывает клиент заполнил поля, потом замечает, что случайно выбрал не то или по иным причинам, меняет вариант доставки и все вводит приходится заново.

    У меня есть только 1 поле "Адрес доставки" - куда клиент вводит и город и улицу и регион, так проще клиенту как показывает статистика

  • Евгений Леман 22 ноября 2019 19:51

    Все button'ы не имеют атрибута type. Опустим тот момент, что это не валидно. Проблема в том, что со стороны темы довольно сложно такое стилизовать. Особенно если стилизация сложна сама по себе + привязана к вариантам вида кнопок в настройках. button без type принято использовать как раз для того, чтобы избежать наложения общих стилей на них. Так обычно делают, например, для кнопок лево/право слайдеров или "точек" тех же слайдеров. Но тут как раз кнопки должны перенимать общие стили. Поэтому отсутствие type является скорее ошибкой.

  • golubevmark Webasyst 2 декабря 2019 12:08

    @Евгений Леман, атрибут type у кнопки не является обязательным, но в ваших словах есть здравый смысл. Я думаю в ближайшее время в шаблонах оформления заказа будут добавлены атрибуты type. Но есть момент, стили для кнопок применяются не по тегу, а по классу ".wa-button", отсюда конфликт стилей, о котором вы пишите, возникает на уровне темы, а не блока с оформлением заказа.

  • artdecomix@yandex.ru 2 марта 2020 23:42

    Здравствуйте, а как нибудь можно добавить в заказ поле комментария используя order.html или order.js , для отображения в заказе , в бэкенде ? Без плагинов и хуков?

  • kadurinho 2 марта 2020 23:44

    @Ольга Ситар, поле итак есть, в чем у вас сложности?

  • artdecomix@yandex.ru 3 марта 2020 07:42

    Мне нужно свой текст в него поместить. А настройками это поле отключено, и не должно отображаться

  • Markus 26 марта 2020 07:25

    Добрый день.
    Адаптируя тему с css разобрался. Но возникла проблема с самим оформлением заказа.
    После нажатия "Подтвердить заказ" страница подвисает, никаких ошибок не выводит, только мозила ругается страница замедляет ваш браузер.
    В логах ничего нет. Переключился на дефолтовый шаблон, там все ок.
    Заменил все файлы заказа в корзине из дефолтового шаблона в свой. Ситуация не изменилась. Висит страница и все. Явно что плагины тут не причем, потому как в дефолте все работает. Такое ощущение, что скрипты магазина на этой странице конфиликтуют со скриптами шаблона. Но ошибок или предупреждений в консоли не наблюдаю.
    В какую сторону копать?!
  • Markus 26 марта 2020 10:20

    Причина найдена. Оформление не хочет работать с jQuery v3.4. Теперь вопрос в том как подружить оформление с jQuery v3.4?!



Чтобы добавить комментарий, зарегистрируйтесь или войдите