[MODX] Подсказки по работе и заготовки для MiniShop2

Пример вывода msProducts

[[!msProducts?
  &limit=`7`
  &parents=`19`
  &depth=`10`
  &includeThumbs=`360x270`
  &includeTVs=`1`
  &tpl=`tpl.msProducts.action.item.GO`
  &where=`{"Data.old_price:!=":"0"}`
]]

Добавить превьюшки

Медиа - Управление медия - MS2 Images - thumbnails (Чтобы не было обрезки надо указать zc : 0)

[[+image]] — плейсхолдер для большого изображения при выводе в msProducts.

Если нужно сделать несколько вариантов изображения, то вот примерно такой код нужно разместить в thumbnails:

{
"tiny":{"w":100,"h":100,"q":90,"zc":"1","bg":"ffffff"},
"210x210":{"w":210,"h":210,"q":90,"zc":"1","bg":"ffffff"},
"normal":{"w":550,"h":550,"q":90,"zc":"1","bg":"ffffff"}
}

Показать товары в древе ресурсов

Системные настройки - minishop2 - Показывать в дереве по умолчанию (ms2_product_show_in_tree_default)

Файл, который отвечает за обработку событий по Ajax, отправляемых на /assets/components/minishop2/action.php, в частности cart/add cart/change cart/remove cart/clean cart/get order/add order/submit order/getcost order/getrequired order/clean order/get оказывается плагином, который называется miniShop2.


Пара фильтров для вывода msProducts

  • &where=`{"Data.old_price:!=":"0"}` — Вывести товары с особой ценой
  • &where=`{"Data.new":"1"}` — Вывести товары с отметкой Новый
  • &where=`{"Data.popular":"1"}` — Вывести товары с отметкой Популярный
  • &where=`{"Data.favorite":"1"}` — Вывести товары с отметкой Особый

Добавить в корзину несколько товаров

В моем случае попытка запустить цикл скриптом увенчалась неудачей. Решил не писать костыли вроде СетТаймаут, и закрыть вопрос чуть более правильно.

Вносим изменения в палагин miniShop2: внутри case OnLoadWebDocument добавляем что вроде:

case 'cart/add/multiple': 
$ids = explode(",", $_POST['ids']);
foreach($ids as $id){
	$response = $miniShop2->cart->add($id, 1, $_POST['options']);
}
break;

По-хорошему следовало бы внедриться в файл assets/components/minishop2/js/web/default.js И там настроить правильную запаковку, отсылку и обработку данных, но заморачиваться с этим сейчас нет времени и желания, поэтому закроем костылем. Костыль не страшный. Просто мы сами сделаем все операции с данными:

// HTML код для данного скрипта решил не выкладывать, т.к. все равно верстка индивидаульна. Пробежитесь по скрипту, просто главное логику понять
$(".order-trigger").click(function(){ // это типа кнопка "положить в корзину много товаров"
	pw = $('.product-wrapper').find('.ms2_product'); 
	prodIds = []; //айдишники товаров (именнотоваров, а не ресурсов)
	pw.each(function(){ // находим каждый товар
    var t = $(this);
    var thisCheck = t.find('.checked-product').prop('checked');
    if(thisCheck){
      prodIds[prodIds.length] = parseInt(t.find('.product_id').val());
    }
	});
  var data =[ // такой массив ожидается на сервере
    {name: 'ids',	value: prodIds},
    {name: 'count',	value: '1'},
    {name: 'options',	value: '[]'},
    {name: 'ms2_action',	value: 'cart/add/multiple'},
    {name: 'ctx',	value: 'web'},
  ];
	console.log(data);
	$.ajax({
		type: "POST",
		data: data,
		url:'/assets/components/minishop2/action.php',
		dataType:'json',
		success: function(data){
      if(success == true){
        $.jGrowl("Товары комплекта добавлены в корзину",{ theme: 'ms2-message-success' }); // выводим сообщение об успешной операции
      }
		},
		error: function (xhr, ajaxOptions, thrownError){
			console.log(xhr.responseText);
		}
	});
	
});

Изменить цену товаров в корзине minishop2 при добавлении определенного товара

В частности в моем случае задача была такая:

Если добавлен «товар» «Установка», то стоимсоть всех товаров в корзине увеличивается на 15%.

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

Открываем код сниппета msCart и начинаем ваять костыль!

// Находим в коде
$cart = $miniShop2->cart->get();

// и сразу после вставляем:
$ustanovka = false;
foreach($cart as $k => $v){
  if($v['id'] == 39){ // Это id товара, который являет собой услугу "Установка" цифра соотвествует id ресурса
    $ustanovka = true;
  }
}
/********/

// Далее по коду ищем что-то такое:
foreach ($cart as $k => $v)

И после него вставляем :
if($ustanovka){
	$v['price'] = $v['price']*1.15;
}

Фильтрация mFilter

Пример вывода:

[[!mFilter2?
  &parents=`[[*id]]`
  &element=`msProducts`
  &limit=`21`
  &includeThumbs=`240x180`
  &includeTVs=`1`
  &filters=`
  ms|price:number
  ,ms|vendor:vendors`
  &toPlaceholders=`my.`
  &tpl=`tpl.msProducts.row.GO`
  &tplFilter.outer.default=`tpl.mFilter2.filter.outer.GO` // кастомный tpl
  &tplFilter.outer.ms|price=`tpl.mFilter2.filter.slider`  // стандартный tpl (обратить внимание на "ms|price" - это связь с фильтром из параметра "filters")
  &tplFilter.row.ms|price=`tpl.mFilter2.filter.number`    // стандартный tpl
]]

Изменение цены при добавлении в корзину minishop2

Цена в minishop2 по курсу валюты

  • Создаем TV usd_price:
    Тип: чекбокс;
    возможные значения: Да==1||Нет==0;
    Значение по умолчанию: Нет==0.
  • Создаем системную настройку: ms2_usd_value, значение — 80 (нынешний курс валюты)
  • Создаем плагин на событие msOnBeforeAddToCart

Код плагина (не забыть установить системное событие):

if ($modx->event->name == 'msOnBeforeAddToCart') {
  $tv = $modx->getObject('modTemplateVar', array('name' => 'usd_price'));
  $modx->log(xPDO::LOG_LEVEL_ERROR, $tv->getValue($product->get('id'))); // для дебага
  $modx->log(xPDO::LOG_LEVEL_ERROR, $modx->getOption('ms2_usd_value')); // для дебага
  if($tv->getValue($product->get('id')) != 0){
    $newPrice = (int)$modx->getOption('ms2_usd_value') * (int)$product->get('price');
    $product->set('price', $newPrice);
  }
}

Поместить параметр вывода в плейсхолдер

Речь идет о том, чтобы в санке бала возможность вывести какой-то параметр, который был передан при вызове сниппета. К примеру параметр tpl будет доступен в [[+property.tpl]]. И так со всеми параметрами.

Эта штука реализована в MIGX и иногда бывает крайне полезна. К примеру в проекте у меня есть шаблон вывода товаров, он одинаковый везде, но кое-где нужно использовать класс col-xs-3, а где-то col-xs-4. Делать под это условие с привязкой за шаблон, или тем более создавать отдельный чанк не хочется. Куда проще - передать класс при вызове сниппета.

Но такого функционала в msProducts не предусмотрено. Ок, добавим - нужно просто скопировать часть кода ниже в код сниппета msProducts:

// Этот код разместить перед блоком "Processing rows" (...if (!empty($rows) && is_array($rows)) {...):
$properties = array();
foreach ($scriptProperties as $property => $value) { 
  $properties['property.' . $property] = $value;
}

// Эту строчку добавить перед $tpl = $pdoFetch->defineChunk($row)... В общем перед выводом всех данных в чанк
$row = array_merge($row, $properties);

Разная цена в зависимости от кол-ва товара в корзине

Код плагина:

Стоит отметить, что поля price500/price5/price4/price3/price2 были созданы предварительно.

switch ($modx->event->name) {
  case 'msOnChangeInCart': case 'msOnAddToCart': case 'msOnRemoveFromCart':
  $tmp = $cart->get();
  //$modx->log(xPDO::LOG_LEVEL_ERROR, print_r($tmp, true));
  foreach ($tmp as $key1 => $value) {
    if ($product = $modx->getObject('msProduct', $value['id'])) {
      $quantity = $value['count'];
      if ($quantity > 499) { $tmp[$key1]['price'] = $product->get('price500'); }
      elseif ($quantity > 99) { $tmp[$key1]['price'] = $product->get('price5'); }
      elseif ($quantity > 49) { $tmp[$key1]['price'] = $product->get('price4'); }
      elseif ($quantity > 29) { $tmp[$key1]['price'] = $product->get('price3'); }
      elseif ($quantity > 9) { $tmp[$key1]['price'] = $product->get('price2'); }
      else {
        $realPrice = $product->get('price');
        $tmp[$key1]['price'] = $realPrice;
      }
    }
  }
  //$modx->log(xPDO::LOG_LEVEL_ERROR, $realPrice);
  $cart->set($tmp);
  break;
}

Расширение свойств классов MiniShop2

Переходим в папку core/components/minishop2/custom/ и выбираем подходящее место для файлика - в зависимости от того, что мы саобираемся расширять. Допустим это будет order. Создаем файл с любым названием, которое оканчивается на .class.php.

Внутри этого файлика пишем

class msOrderHandlerMy extends msOrderHandler{
  // И тут уже можно переопределить существующий метод, либо создать свой.
}

После этого переходим в системные настройки MiniShop2, и там указываем имя вашего класса (мой пример msOrderHandlerMy) в настройке ms2_order_handler_class, или ms2_cart_handler_class для нового msCartHandler

Родные методы храняться в файлах:
core/components/minishop2/model/minishop2/msorderhandler.class.php
core/components/minishop2/model/minishop2/mscarthandler.class.php
core/components/minishop2/model/minishop2/msdeliveryhandler.class.php
core/components/minishop2/model/minishop2/mspaymenthandler.class.php

Динамически обновлять цены при изменении кол-ва в корзине

Эта задача наиболее актуальна при разных ценах на товары в зависимости от кол-ва. (см. пункт выше)

Нам надо будет подправить JS файлик assest/components/minishop2/js/web/default.js, а также расширить класс msCartHandler (см. выше)

Создаем файлик по инструкции:

class msCartHandlerMy extends msCartHandler{
  public function status($data = array())
  {
    $status = array(
      'total_count' => 0,
      'total_cost' => 0,
      'total_weight' => 0,
    );
    $status['cart'] = $this->cart; // Добавляем только эту строчку к оригинальному методу
    foreach ($this->cart as $item) {
      if (empty($item['ctx']) || $item['ctx'] == $this->ctx) {
        $status['total_count'] += $item['count'];
        $status['total_cost'] += $item['price'] * $item['count'];
        $status['total_weight'] += $item['weight'] * $item['count'];
      }
    }
    $status = array_merge($data, $status);

    $response = $this->ms2->invokeEvent('msOnGetStatusCart', array(
      'status' => $status,
      'cart' => $this,
    ));
    if ($response['success']) {
      $status = $response['data']['status'];
    }

    return $status;
  }
}

Переходим теперь к файлику assets/components/minishop2/js/web/default.js. Находим status: function (status) {, и там через console.log(status); для начала убеждаемся, что получаем данные о корзине, и о каждом товаре.

И теперь в этом методе уже куда угодно сортируем полученные данные. Например так:

$.each(status.cart, function(key, value) {
	$("#" + key).find(".price").text(miniShop2.Utils.formatPrice(value.price));
});
// Я разместил перед вот этой строчкой:
// if ($(miniShop2.Order.orderCost, miniShop2.Order.order).length) {

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

  1. Евгений 13 сентября 2019, 16:13 # 0
    Добрый день.

    а не подскажете как сделать добавление/удаление товара в(из) корзину(ы) по чекбоксу на странице оформления заказа? т.е. при установке галочки определённый товар добавлялся в корзину, а при снятии этой галочки чтобы удалялся из корзины. как добавить — понятно вроде, а вот как убрать?
    1. Сергей 12 декабря 2019, 02:18(Комментарий был изменён) # 0
      Доброго времени суток, сейчас уже нет внутри OnLoadWebDocument никаких case
      Можете подсказать куда сейчас надо это вписать?
      Это по поводу «Добавить в корзину несколько товаров»
      *Комментарий будет опубликован после проверки модератором

      Комментарии easyComm

      Адель 13 мая 2018, 00:55

      По вопросу @Добавить в корзину несколько товаров@

      По костылю,
      order-trigger - класс кнопки субмит
      product-wrapper - контейнер продуктов
      checked-product - контейнер продукта
      product_id - класс инпута

      Полная разметка:

      <form method="post" class="ms2_form ajax_form">
      <div class="row ms2_product product-wrapper">
      <!--Товар-->
      <div class="col-md-6 col-lg-3 checked-product">
      <input type="hidden" name="id" value="15">
      <input type="text" name="count" class="product_id" value="1">
      <input type="hidden" name="options" value="[]">
      </div>
      <!--//Товар-->
      <!--Товар-->
      <div class="col-md-6 col-lg-3 checked-product">
      <input type="hidden" name="id" value="16">
      <input type="text" name="count" class="product_id" value="1">
      <input type="hidden" name="options" value="[]">
      </div>
      <!--//Товар-->

      <div class="col-md-3 offset-md-3">
      <button class="btn btn-default pull-right order-trigger" type="submit" name="ms2_action" value="cart/add">
      <i class="glyphicon glyphicon-barcode"></i> Заказать уборку
      </button>
      </div>

      </div>

      <input type="hidden" name="af_action" value="65f6fa23530619c59498039f76a127c9">
      </form>

      Правильно ли я логику понял?

      Адель 13 мая 2018, 00:39

      case 'cart/add/multiple':
      $ids = explode(",", $_POST['ids']);
      foreach($ids as $id){
      $response = $miniShop2->cart->add($id, 1, $_POST['options']);
      }
      break;

      При "Добавить в корзину несколько товаров" изменении приложения minishop2 ругается на разметку фенома, тк там чистый JS.

      Я не силен в феноме, быть может кто нибудь переведет его в JS.

      И по выдаче этой статьи не найти, я можно сказать душу продал пока искал что то похожее.

      Администратор

      Если феном выдает ошибки, то просто оберните JS код в {ignore} ... {ignore}.
      Это может выглядеть так:

      Василий 03 апреля 2018, 21:12

      Прошу помощи. Установил MS2 и получил проблему с превьюшками. Картинки в галерею товара загружаются, ресайзятся как указано в системных настройках. А превью не создаются. Вместо них дефолтный логотип ms2. Подскажите, где искать?

      Администратор

      Давайте попробуем разобраться. Какие настройки у вас в системе стоят и как вы пытаетесь вывести изображение? Пример кода, пожалуйста.

      Похожие статьи

      Наш сайт использует куки, нажмите «ОК» если вы не против
      OK