Алоха, спортсмены! Сегодня мы с вами сделаем программное оформление заказа 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. Спасибо, за внимание!