Алоха, спортсмены! Сегодня мы с вами сделаем программное оформление заказа miniShop2, минуя его сниппеты. Плюс данного способа в том, что мы с вами польностью можем задать свою логику оформления заказа, что будет некой индивидуальной фишкой нашего лендинга.
Для начала я создал новый шаблон “Товар” и “Категория товаров” оставил их пустыми. Сделал я это на тот случай, если в дальнейшем сайт масштабируется из лендинга в многостраничник. Так же необходимо в системных настройках, в разделе miniShop2 указать данные шаблоны по умолчанию для новых категорий и товаров (это настройки ms2_template_category_default и ms2_template_product_default).
Когда мы это сделали, можем создавать в корне нашего сайта категорию товаров и в ней наши 6 карточек товара. У вас должно получиться примерно, как у меня:
Теперь я вам должен пояснить логику, по которой у нас все будет работать. У нас будут выведены товары с кнопкой “Купить”, по нажатию на которую будет открываться модальное окно заказа товара со следующими полями:
- Имя пользователя
- Телефон
- Комментарий к заказу
Когда пользователь заполнит все поля, данные с формы отправятся на техническую страницу, на которой у нас будет валидация заполненных полей формы и оформление заказа. Ответ мы будем отдавать в формате JSON, как и в случае с формой подписки. Думаю, что вам стал понятен принцип работы данного блока.
Теперь давайте выведем наши товары на главной странице. Для этого нам необходимо создать чанк “productTpl” со следующим содержимым:
<div class="col-md-4 col-sm-6">
<div class="product-single text-center">
{if $image?}
<img src="{$image}" alt="{$pagetitle}" title="{$pagetitle}" class="img-responsive"/>
{else}
<img src="{'assets_url' | option}components/minishop2/img/web/ms2_small.png"
srcset="{'assets_url' | option}components/minishop2/img/web/ms2_small@2x.png 2x"
alt="{$pagetitle}" title="{$pagetitle}"/>
{/if}
<h4>{$pagetitle}</h4>
<h3>{$price} <span>руб.</span></h3>
<a href="#offer{$id}" data-toggle="modal" data-target="#offer{$id}"><i class="icofont icofont-cart"></i> Buy Now</a>
</div>
</div>
В данном чанке у нас используется шаблонизатор Fenom, поэтому не пугайтесь незнакомых тегов.
И в месте вывода товаров нам необходимо вызвать сниппет msProducts со следующими параметрами:
[[msProducts? &parents=`5` &tpl=`productTpl` ]]
Отлично! Мы с вами вывели наши товары. Теперь нам нужно создать еще один чанк “productModalTpl”, в котором мы будем выводить модальное окно. Каждому товару у нас будет соответствовать свое модальное окно.
<div class="modal fade" id="offer{$id}" tabindex="-1" role="dialog" aria-labelledby="offer{$id}">
<div class="modal-dialog" role="document">
<div class="modal-content">
<form action="[[~12]]" method="POST" class="ajax_form_offer" id="offermodalform{$id}">
<input type="hidden" name="pagetitle" value="[[*pagetitle:htmlent]]">
<input type="hidden" name="id" value="{$id}">
<input type="hidden" name="href" value="[[~[[*id]]? &scheme=`full`]]">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">×</span></button>
<h4 class="modal-title" id="myModalLabel">Buy Now {$pagetitle}</h4>
</div>
<div class="modal-body">
<div class="message"></div>
<div class="form-group hidden">
<label>Имя</label>
<input class="form-control" name="user" placeholder="" type="text">
</div>
<div class="form-group hidden">
<label>Имя</label>
<input class="form-control" name="username" placeholder="" type="text">
</div>
<div class="form-group">
<input type="text" name="name" class="form-control" placeholder="Name">
</div>
<div class="form-group">
<input type="email" name="email" class="form-control" placeholder="Email">
</div>
<div class="form-group">
<input type="text" name="phone" class="form-control" placeholder="+7 (999) 123-45-67">
</div>
<div class="form-group">
<textarea class="form-control" name="text" cols="30" rows="10"></textarea>
</div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-default" data-dismiss="modal">Close</button>
<button type="submit" class="btn btn-primary">Submit</button>
</div>
</form>
</div>
</div>
</div>
Класс! Теперь по клику на кнопку “Buy Now” у нас будет открываться соответствующее модальное окно. В атрибуте тега form action у меня прописан идентификатор ресурса, в котором вызван сниппет-обработчик заказа.
Также нам нужно вызвать сниппет msProducts после чанка Modals в шаблоне:
[[msProducts?
&parents=`5`
&tpl=`productModalTpl`
]]
Следующим шагом будет создание ресурса, в котором мы будем обрабатывать заказ. Я скопировал наш ресурс с обработкой подписки и назвал его “Оформление заказа”, а внутри вызвал пока не существующий сниппет “setoffer”:
Класс! Теперь создаем сниппет “setoffer” и можно пока написать валидацию данных:
<?php
$output = array();
$output['success'] = true;
// проверяем, что идет ajax запрос
if(isset($_SERVER['HTTP_X_REQUESTED_WITH']) && !empty($_SERVER['HTTP_X_REQUESTED_WITH']) && strtolower($_SERVER['HTTP_X_REQUESTED_WITH']) == 'xmlhttprequest') {
// проверяем антиспам поля и ID ресурса
if($_REQUEST["user"]=='' && $_REQUEST["username"]=='' && $_REQUEST['id']){
// проверяем поле name
if($_REQUEST['name']==''){
$output['success'] = false;
$output['message'] = "Заполните все обязательные поля";
$output['fields'][] = "name";
}
// проверяем поле email
if($_REQUEST['email']==''){
$output['success'] = false;
$output['message'] = "Заполните все обязательные поля";
$output['fields'][] = "email";
}
// проверяем поле phone
if($_REQUEST['phone']==''){
$output['success'] = false;
$output['message'] = "Заполните все обязательные поля";
$output['fields'][] = "phone";
}
// если проверка прошла успешно - оформляем заказ
if($output['success']){
$output['success'] = true;
$output['message'] = "Ваш заказ оформлен";
}
}else{
$output['success'] = false;
$output['message'] = "Данные не прошли проверку валидности или у вас не указан ID товара";
}
}else{
$output['success'] = false;
$output['message'] = "Данные не прошли проверку валидности, попробуйте позже";
}
echo json_encode($output);
И в чанке scripts напишем отправку наших данных на сервер с помощью jQuery. Получится он должен аналогично скрипту для подписки пользователя:
$('.ajax_form_offer').submit(function(e){
e.preventDefault();
var msg = $(this).serialize();
var url = $(this).attr("action");
$.ajax({
type: "POST",
url: url,
data: msg,
dataType: "json",
success: function(data){
if(data.success){
miniShop2.Message.success(data.message);
}else{
miniShop2.Message.error(data.message);
}
}
})
});
Теперь можно побаловаться и попробовать поотправлять заказы. Валидация введенных данных проходит успешно можно приступать к оформлению заказа. Но сначала создадим текстовый шаблон и создадим ресурс, в котором нужно разместить вызов сниппета msGetOrder. Полный код сниппета setoffer будет следующий:
<?php
$output = array();
$output['success'] = true;
// проверяем, что идет ajax запрос
if(isset($_SERVER['HTTP_X_REQUESTED_WITH']) && !empty($_SERVER['HTTP_X_REQUESTED_WITH']) && strtolower($_SERVER['HTTP_X_REQUESTED_WITH']) == 'xmlhttprequest') {
// проверяем антиспам поля и ID ресурса
if($_REQUEST["user"]=='' && $_REQUEST["username"]=='' && $_REQUEST['id']){
// проверяем поле name
if($_REQUEST['name']==''){
$output['success'] = false;
$output['message'] = "Заполните все обязательные поля";
$output['fields'][] = "name";
}
// проверяем поле email
if($_REQUEST['email']==''){
$output['success'] = false;
$output['message'] = "Заполните все обязательные поля";
$output['fields'][] = "email";
}
// проверяем поле phone
if($_REQUEST['phone']==''){
$output['success'] = false;
$output['message'] = "Заполните все обязательные поля";
$output['fields'][] = "phone";
}
// если проверка прошла успешно - оформляем заказ
if($output['success']){
// инициализируем miniShop2
$scriptProperties = array(
'json_response' => true,
'max_count' => 1000,
'allow_deleted' => false,
'allow_unpublished' => false
);
$miniShop2 = $modx->getService('minishop2','miniShop2', MODX_CORE_PATH . 'components/minishop2/model/minishop2/', $scriptProperties);
// опции товара, если они необходимы
$option = array();
/*$option = array(
"option1" => "value1",
"option2" => "value2",
);*/
// инициализируем miniShop2 в текущем контексте
$miniShop2->initialize($modx->context->key, $scriptProperties);
// чистим корзину
$miniShop2->cart->clean();
// добавляем товар в корзину
$arr = json_decode($miniShop2->cart->add($_REQUEST["id"],1,$option), true);
// логируем каждый шаг
$modx->log(E_ERROR, print_r($arr,1));
// формируем заказ
$miniShop2->order->add('receiver', $_REQUEST['name']);
$miniShop2->order->add('email', $_REQUEST["email"]);
$miniShop2->order->add('phone', $_REQUEST["phone"]);
$miniShop2->order->add('comment', $_REQUEST["text"]);
$miniShop2->order->add('payment', 1);
$miniShop2->order->add( 'delivery', 1);
$orderfeed = $miniShop2->order->submit();
$arr = json_decode($orderfeed,true);
// логируем каждый шаг
$modx->log(E_ERROR, print_r($arr,1));
if($arr['success']==true&&$arr["data"]["msorder"]){
$output["location"] = $modx->makeUrl(13,'',array('msorder' => $arr["data"]["msorder"]));
}
$output['success'] = true;
$output['message'] = "Ваш заказ оформлен";
}
}else{
$output['success'] = false;
$output['message'] = "Данные не прошли проверку валидности или у вас не указан ID товара";
}
}else{
$output['success'] = false;
$output['message'] = "Данные не прошли проверку валидности, попробуйте позже";
}
echo json_encode($output);
И мы немного модернизировали скрипт отправки данных на сервер:
$('.ajax_form_offer').submit(function(e){
e.preventDefault();
var $btn = $('.ajax_form_offer button[type=submit]').button('loading');
var msg = $(this).serialize();
var url = $(this).attr("action");
$.ajax({
type: "POST",
url: url,
data: msg,
dataType: "json",
success: function(data){
if(data.success){
miniShop2.Message.success(data.message);
if(data.data.msorder){
window.location.href = "[[~13]]?msorder="+data.data.msorder;
}
}else{
miniShop2.Message.error(data.message);
}
}
})
});
Таким вот незатейливым образом мы с вами реализовали свою логику при оформлении заказа miniShop2. Спасибо, за внимание!