Делаем красивое уведомление при добавлении товара в корзину в Drupal Commerce

Сегодня я расскажу о том, как сделать красивое уведомление, в котором будет показываться информация об добавляемом товаре после добавления товаров в корзину в Drupal Commerce с помощью Ctools modal API.

Для начала, создадим вьюз, который будет принимать аргумент добавляемого товара и выводить информацию о нем. Это придаст гибкости и в случае необходимости изменения информации о товаре нам не надо будет лезть в код. Показывать сам вьюз я не буду - это будет маленькое домашнее задание.

После того, как создали вьюз, первым делом создаем модуль, который поможет решить поставленную задачу.

Первая функция, которая будет в нашем модуле это функция подключения всех необходимых библиотек:

/**
 * Добавление js и css файлов для модального окна.
 */
function _example_include_modal() {

  static $added = FALSE;
  if (!$added) {

    // Не добавлять библиотеки снова.
    $added = TRUE;

    // Подключаем Ctools библиотеки, которые нужны нам для задачи.
    ctools_include('modal');
    ctools_include('ajax');
    ctools_modal_add_js();

    // Создаем массив с настройками для модального окна.
    $example_style = array(
      'example-style' => array(
        'modalSize' => array(
          'type' => 'fixed',
          'width' => (int) 550,
          'height' => (int) 140,
          'contentRight' => 30,
          'contentBottom' => 0,
        ),
        'modalOptions' => array(
          'opacity' => (float) 0.8,
          'background-color' => '#000000',
        ),
        'closeText' => '',
        'closeImage' => theme('image', array('path' => ctools_image_path('close-modal.png', 'example'))), // Картинка должна лежать в папке images нашего модуля.
        'animation' => 'fadeIn',
        'animationSpeed' => 'fast',
      ),
    );
    drupal_add_js($example_style, 'setting');
  }
}

Следующим шагом для решения поставленной задачи будет написание альтера формы добавления товаров в корзину и навешивание своих обработчиков:

/**
 * Implements hook_form_FORM_ID_alter().
 */
function example_form_commerce_cart_add_to_cart_form_alter(&$form, &$form_state) {
  // Добавляем css класс для кнопки, чтобы сработали наши настройки для модального окна.
  $form['submit']['#attributes']['class'][] = 'ctools-modal-example-style';
  
  // Добавляем свой AJAX обработчик.
  $form['submit']['#ajax'] = array('callback' => 'example_add_to_cart_ajax_callback');
  
  // Добавляем свой обработчик после отправки формы.
  $form['#submit'][] = 'example_add_to_cart_form_submit';
}

Теперь создадим AJAX обработчик:

/**
 * AJAX обработчик добавления товаров в корзину.
 */
function example_add_to_cart_ajax_callback($form, &$form_state) {
  // Подключаем библиотеки, необходимые для работы модального окна.
  _example_include_modal();

  // Убираем из вывода все друпалоские сообщения.
  drupal_get_messages();
  
  // Получаем обновленное содержимое корзины.
  $cart_block = module_invoke('commerce_cart', 'block_view', 'cart');
  
  // Формируем ссылки для закрытия модального окна и продолжения покупок,
  // а так же кнопку для перехода в корзину. На самом деле эти кнопки можно и во вьюз всунуть.
  $links = array();
  $links[] = '<span class="cart-link-center"><span class="cart-link-left">' . l('Продолжить покупки', '', array('attributes' => array('class' => array('button', 'ctools-close-modal', 'cart-link-right')))) . '</span></span>';
  $links[] = '<span class="cart-link-center"><span class="cart-link-left">' . l('Оформить заказ', 'cart', array('attributes' => array('class' => array('button', 'cart-link-right')))) . '</span></span>';
  
  // Создаем рендерный массив, который потом отдадим в модальное окно.
  $modal = array();

  // Загружаем ранее созданный вьюз, первый параметр машинное имя вьюза, второй машинное имя дисплея,
  // третий параметр это id добавляемого товара, который принимает вьюз в виде аргумента.
  $modal['product']['#markup'] = commerce_embed_view('product_added_to_cart', 'master', array($form_state['values']['product_id']));

  // Добавляем в рендерный массив ссылки, которые создали ранее.
  $modal['actions'] = array(
    '#theme' => 'item_list',
    '#items' => $links,
    '#attributes' => array(
      'class' => array('cart-links'),
    ),
  );
  
  // Формируем команды для AJAX.
  $commands = array();

  // Обновляем содержимое корзины.
  $commands[] = ajax_command_html('#block-commerce-cart-cart div.content', render($cart_block['content']));

  // Выводим модальное окно. Первый параметр, заголовок модального окна, второй - его содержимое.
  $commands[] = ctools_modal_command_display('Ваши покупки', render($modal));

  return array('#type' => 'ajax', '#commands' => $commands);
}

И последнее, что нам надо сделать, это добавить обработчик отправки формы, после добавления товаров в корзину:

/**
 * Обработчик отправки формы после добавления товаров в корзину.
 */
function example_add_to_cart_form_submit($form, &$form_state){
  $form_state['rebuild'] = TRUE;
}

Результат

Drupal Commerce add to cart AJAX
Drupal Commerce add to cart AJAX

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

Аватар пользователя kreaton
kreaton

Для данной задачи уже есть модуль :) Commerce add to cart confirmation. Выводит точно такое же окошко, которое представляет собой вьюху. С другой же стороны, самописный вариант предоставляет полный контроль над ситуацией, так что спасибо за статью!

Аватар пользователя Benya
Benya

Этот модуль работает не на AJAX:) Хотя мб можно и его быстро сделать на AJAX, я в него не вникал

Аватар пользователя danylevskyi
danylevskyi

Отличная статья! Спасибо!

Аватар пользователя Вадим
Вадим

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

Аватар пользователя Benya
Benya

Не выйдет, модуль связан с вьюхой, которая может быть у всех разной

Аватар пользователя Вадим
Вадим

Создал модуль, в файл name.module добавил весь код что содержится на этой странице.
Создал вьюшку как в "Commerce add to cart confirmation". Выходит теперь нужно поменять в коде на свои параметры и все?

Или настройка более тонкая и тут в коде еще менять и менять?

Аватар пользователя Benya
Benya
$modal['product']['#markup'] = commerce_embed_view('product_added_to_cart', 'master', array($form_state['values']['product_id']));

Вот здесь необходимо передать первым параметром название вьюхи, вторым название дисплея, третьим id продукта (если Ваша вьюха принимает его в качестве аргумента)

Аватар пользователя Sirega
Sirega
$links[] = '<span class="cart-link-center"><span class="cart-link-left">' . l('Продолжить покупки', '', array('attributes' => array('class' => array('button', '<strong>close-modal</strong>', 'cart-link-right')))) . '</span></span>';

Не закрывает почему то

Аватар пользователя kreaton
kreaton

// Картинка должна лежать в папке image нашего модуля.
маленькая поправочка - в папке images :)

Аватар пользователя Benya
Benya

Очепятка:) Спасибо поправил

Аватар пользователя Андрей
Андрей

У меня товар с атрибутами - размер, модальное окно выводит название товара только для одного атрибута - кот был 1м (тоесть если я клацаю один атрибут потом другой он глючит) в чем может быть причина?

Аватар пользователя Benya
Benya

Скорее всего в настройках вьюза проблема

Аватар пользователя Андрей
Андрей

разобрался)
мне нужен был id ноды подсунуть я поставил этот модуль https://drupal.org/project/commerce_prodnodelink
и код может кому то пригодиться

$product_id = $form_state['values']['product_id'];
$product_wrapper = entity_metadata_wrapper('commerce_product', $product_id);
$display_node_ids = $product_wrapper->display_node_ids->value();
$id = $display_node_ids[0];
Аватар пользователя Дмитрий
Дмитрий

Здравствуйте, не подскажите в чем может быть трабла? сделал все как у вас, при нажатии ссылки "Продолжить покупки" редиректит на главную страницу.

Аватар пользователя Benya
Benya

Здравствуйте, предполагаю, что где то в js может быть ошибка, смотрите консоль в браузере

Аватар пользователя Дмитрий
Дмитрий

Здравствуйте, да вы были правы, ошибка в js. возникает при нажатии на кнопку купить. не подскажете как поправить?

Uncaught TypeError: undefined is not a function VM1255:206
Drupal.behaviors.ZZCToolsModal.attach VM1255:206
(anonymous function) drupal.js?n89ax2:76
e.extend.each jquery.min.js?v=1.7.1:2
Drupal.attachBehaviors drupal.js?n89ax2:74
Drupal.CTools.Modal.modal_display VM1255:297
Drupal.ajax.success ajax.js?v=7.26:400
ajax.options.success ajax.js?v=7.26:164
a.success jquery.form.js?n89ax2:12
n jquery.min.js?v=1.7.1:2
o.fireWith jquery.min.js?v=1.7.1:2
w jquery.min.js?v=1.7.1:4
d
Аватар пользователя Дмитрий
Дмитрий

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

Аватар пользователя Benya
Benya

Это все нужно смотреть на сайте, анализировать где ошибка, в каком случае возникает и т.д

Аватар пользователя Товарищ
Товарищ

У меня неполучилось правельно завести этот модуль.
Модуль передает ID товара, а нужно Line Item id
Если создавать вьюху Commerce Line, то ID товара в качестве аргумента ничего не даёт.
Если создавать вьюху Commerce Product, то мы не получим полем (общая сумма, и количество товара)

Аватар пользователя Николай
Николай

Добрый день столкнулся с проблемой, в quick tabs в трех табах выведены товары. НА первой вкладке все работает, на второй и третьей при нажатии на купить вылетает страница по адресу quicktabs/ajax/tabs/1/view/tabs/block/2/node/
и на всю страницу идет код

[{"command":"settings","settings":{"basePath":"\/","pathPrefix":"","ajaxPageState":{"theme":"mytheme","theme_token":"1PgPxQs8oki6sbvqX1wYKjOXdVuNkV3tDIMOMFV7yHA"},"colorbox":{"opacity":"0.85","current":"{current} \u0438\u0437 {total}","previous":"\u00ab \u041f\u0440\u0435\u0434","next":"\u0421\u043b\u0435\u0434 \u00bb","close":"\u0417\u0430\u043a\u0440\u044b\u0442\u044c","maxWidth":"98%","maxHeight":"98%","fixed":true,"mobiledetect":true,"mobiledevicewidth":"480px"},"scroll_to_top":{"label":"\u041d\u0430\u0432\u0435\u0440\u0445"},"ajax":{"edit-submit":{"callback":"confirmcart_add_to_cart_ajax_callback","event":"mousedown","keypress":true,"prevent":"click","url":"\/system\/ajax","submit":{"_triggering_element_name":"op","_triggering_element_value":"\u041a\u0443\u043f\u0438\u0442\u044c"}},"edit-submit--2":{"callback":"confirmcart_add_to_cart_ajax_callback","event":"mousedown","keypress":true,"prevent":"click","url":"\/system\/ajax","submit":{"_triggering_element_name":"op","_triggering_element_value":"\u041a\u0443\u043f\u0438\u0442\u044c"}},"edit-submit--3":
итд

Что нужно сделать, чтобы и в других табах заработало?

Аватар пользователя Benya
Benya

Нужно смотреть детально, что там происходит. Гугли проблему в интернетах

Аватар пользователя Max
Max

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

Аватар пользователя Benya
Benya

мб, смотрите консоль, мб ошибки какие то

Аватар пользователя Василий
Василий

Подскажите, как решаете проблему с таблицей cache_form???

Аватар пользователя Василий
Василий

Спасибо. Пробовал https://www.drupal.org/project/optimizedb, но это не решает проблему, если товаров реально много и сайт большой и посещаемый. Поделитесь, пожалуйста, кастомным кодом или ссылкой на него. Я думаю многим пригодится!

Аватар пользователя Benya
Benya

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

Аватар пользователя Василий
Василий

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

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

Аватар пользователя Василий
Василий

Забыл ещё дописать, что при очистке по крону, возмона такая ситуация (часто встречал у себя на рабочем сайте) когда пользователь открыл страницу с ajax формами-товарами и пошел "чаю попить", но когда пришел крон отработал - записи о формах стер, клиент нажимает на кнопку купить, но ему вылетает AJAX ошибка...

Аватар пользователя Benya
Benya

Ну это довольно старая проблема. Посмотрите здесь http://xandeadx.ru/blog/drupal/751. Возможно, что то будет для вас полезным (лично сам не пользовался).

Насчет проблемы с очисткой, чистить нужно только просроченные данные, а не всю таблицу целиком (смотрите поле expire в таблице).

Аватар пользователя Василий
Василий

Знаю, чтопроблема старая, но печально, что нормально до сих пор не решенная! Это http://xandeadx.ru/blog/drupal/751 не работает если есть характеристики товара, увы.

Аватар пользователя Benya
Benya

Если для вас критично, то можно попробовать реализовать через AJAX ссылку, в обход формы (если вы конечно хорошо знаете API Drupal Commerce).

Аватар пользователя Василий
Василий

Т.е. вместо кнопки "купить" использовать ссылку?

Аватар пользователя Benya
Benya

Ну да, клик по ссылке шлет на определнный url все параметры и там обрабатываете как вам нужно

Аватар пользователя Василий
Василий

Спасибо за совет, буду пробовать. Отпишусь обязательно

Аватар пользователя олег
олег

добрый день, не могли би ви скинуть скрин вюшки потому что у меня что то не получается сделать

Аватар пользователя олег
олег

или напишите как в вюшке вывести количетсво товара?

Аватар пользователя Benya
Benya

извините, нет под рукой ничего, где можно было бы сделать скрин. Очень давно не работал с комерс