Сейчас мы с вами реализуем один из интересных функционалов для нашего интернет-магазина, а именно вывод сгруппированных характеристик товара. К сожалению, автор miniShop2 не предусмотрел такую возможность из коробки. Но мы же с вами не лыком шиты, верно?
Реализовывать вывод сгруппированных характеристик мы будем на основе сниппета msProductOption, который идет в комплекте с miniShop2. Приведу сразу код модернизированного сниппета getcharacters:
<?php
$product = !empty($product) && $product != $modx->resource->id
? $modx->getObject('msProduct', array('id' => $product))
: $modx->resource;
if (!($product instanceof msProduct)) {
return "[msProductOptions] The resource with id = {$product->id} is not instance of msProduct.";
}
if ($data = $product->getOne('Data')) {
$optionKeys = $data->getOptionKeys();
}
if (empty($optionKeys)) {
return '';
}
$productData = $product->loadOptions();
$options = array();
$catoptions = array();
foreach ($optionKeys as $key) {
// Filter by key
if (!empty($onlyOptions) && $onlyOptions[0] != '' && !in_array($key, $onlyOptions)) {
continue;
} elseif (in_array($key, $ignoreOptions)) {
continue;
}
$option = array();
foreach ($productData as $dataKey => $dataValue) {
$dataKey = explode('.', $dataKey);
if ($dataKey[0] == $key && (count($dataKey) > 1)) {
$option[$dataKey[1]] = $dataValue;
}
}
$option['value'] = $product->get($key);
// Filter by groups
$skip = !empty($groups) && !in_array($option['category'], $groups) && !in_array($option['category_name'], $groups);
if ($skip || empty($option['value'])) {
continue;
}
$options[$key] = $option;
if($option["type"] == 'combo-boolean'){
if($option['value'][0] == 1 || $option['value'][0] == "Да"){
$option['value'][0] = "Да";
}else{
$option['value'][0] = "Нет";
}
}
if(strlen($option['value'][0])){
$catoptions[$option['category']]['name'] = $option['category_name'];
$catoptions[$option['category']]['items'][] = $option;
}
}
if($tpl){
$pdoTools = $modx->getService('pdoTools');
return $pdoTools->getChunk($tpl, array(
'cats' => $catoptions,
));
}else{
echo "<pre>";
print_r($catoptions);
echo "</pre>";
}
Надеюсь, вы заметили, что модернизация коснулась только конца сниппета, следовательно, принимает он все те же параметры, что и msProductOption. Код сниппета нужно сохранить в файле core/elements/snippets/getcharacters.php. Все логику модернизации я подробно расскажу в видео к этому уроку. А мы с вами тем временем должны создать чанк cat_option.tpl:
{foreach $cats as $cat}
<h4 class="table-title">{$cat.name}</h4>
<table class="table table-bordered table-middle table-dark">
<tbody>
{foreach $cat.items as $option}
<tr data-key="{$option.key}" data-value="{$option.value[0]}">
<td style="width: 70%;">
{$option.caption}
</td>
<td style="width: 30%; text-align: center;">
{if $option_type == "combo-options"?}
{var $values = $value | split}
{foreach $values as $val}
<span class="label label-default">{$val}</span>
{/foreach}
{$option_measure_unit}
{else}
{if $option.value is array}
{$option.value | join : ', '}
{else}
{$option.value}
{/if}
{if $option.measure_unit?}
{$option.measure_unit}
{/if}
{/if}
</td>
</tr>
{/foreach}
</tbody>
</table>
{/foreach}
На данном чанке у вас должна нарисоваться полная картина всех преимуществ Fenom и логики его работы. Я сам лично сделал ни один подобный функционал. Согласитесь, что все довольно гибко, главное знать всю логику работы. А нам с вами осталось вызвать сниппет в шаблоне карточки товара, для вывода наших характеристик:
{'@FILE snippets/getcharacters.php' | snippet : [
'tpl' => '@FILE chunks/cat_option.tpl'
]}
Сейчас мы реализуем отзывы о товаре. Данный блок мы уже разбирали в уроке “Отзывы о товаре в MODx Revo” и здесь у нас принцип не изменится. Мы также будем использовать компонент EasyComm из modStore.pro. Для реализации отзывов о товаре просто перепишем вызовы сниппетов на Fenom синтаксис. И тогда у нас часть шаблона с вкладками примет следующий вид:
<div class="product-tabs">
<ul class="nav nav-tabs responsive" id="myTab" role="tablist">
<li class="nav-item">
<a class="nav-link active" id="characters-tab" data-toggle="tab" href="#characters" role="tab" aria-controls="characters" aria-selected="true">Характеристики</a>
</li>
<li class="nav-item">
<a class="nav-link" id="delievery-tab" data-toggle="tab" href="#delievery" role="tab" aria-controls="delievery" aria-selected="false">Доставка и оплата</a>
</li>
<li class="nav-item">
<a class="nav-link" id="reviews-tab" data-toggle="tab" href="#reviews" role="tab" aria-controls="reviews" aria-selected="false">Отзывы</a>
</li>
</ul>
<div class="tab-content" id="myTabContent">
<div class="tab-pane fade show active" id="characters" role="tabpanel" aria-labelledby="characters-tab">
{'@FILE snippets/getcharacters.php' | snippet : [
'tpl' => '@FILE chunks/cat_option.tpl'
]}
</div>
<div class="tab-pane fade" id="delievery" role="tabpanel" aria-labelledby="delievery-tab">
{$_modx->getPlaceholder('+delieveryinfo')}
</div>
<div class="tab-pane fade" id="reviews" role="tabpanel" aria-labelledby="reviews-tab">
<div class="customer-review">
{$_modx->runSnippet('!ecMessages', [])}
</div>
<div class="leave-review">
{$_modx->runSnippet('!ecForm', [])}
</div>
</div>
</div>
</div>
Заметили, что мы еще вывели информацию о доставке и оплате из конфигурации ClientConfig? Думаю, что вы сами сможете создать данный параметр и заполнить его тестовой информацией. А как это сделать я покажу в видео.
БОНУС! Хотите, чтобы сниппет в поиске у вас выглядел примерно так:

Мы с вами реализовали блок с отзывами, поэтому сможем сделать аналогичную штуку. Просто добавьте вот этот блок после блока с ценой в шаблоне товара:
<div class="hidden" itemprop="aggregateRating" itemscope itemtype="http://schema.org/AggregateRating">
<span itemprop="ratingValue">{$_modx->runSnippet('!ecThreadRating', ['tpl' => 'ratingTpl'])}</span> звезд -
основано на <span itemprop="reviewCount">{var $output = '!ecMessagesCount' | snippet: ['tpl' => 'ratingTpl'])} {$output ?: '1'}</span> отзывах
</div>
Данный блок с микроразметкой, позволит вам получить звездочки в Google.
&loadModels=`easycomm` &where=`{"class_key":"msProduct"}` &leftJoin=`{ "ecThread": { "class": "ecThread", "on": "msProduct.id = ecThread.resource" } }` &select=`{ "msProduct": "*", "ecThread": "ecThread.rating_simple AS rating, ecThread.count AS reviews" }`'loadModels'=>'easycomm', 'where' => ['class_key' => 'msProduct'], 'leftJoin' => ["ecThread" => [ "class" => "ecThread", "on" => ["msProduct.id = ecThread.resource"] ] ], 'select' => ['msProduct' => '*', 'ecThread' => 'ecThread.rating_simple AS rating, ecThread.count AS reviews'], ])}[2] => Array ( [id] => 10 [key] => product_table_col_01 [caption] => Первая колонка таблицы [description] => Первая колонка таблицы [measure_unit] => [category] => 15 [type] => combo-options [properties] => [product_id] => 154 [value] => Array ( [0] => 123 [1] => 321 [2] => 656 [3] => 565 [4] => 1233445 ) [category_name] => полное описание товара ) [3] => Array ( [id] => 11 [key] => product_table_col_02 [caption] => Вторая колонка таблицы [description] => Вторая колонка таблицы [measure_unit] => [category] => 15 [type] => combo-options [properties] => [product_id] => 154 [value] => Array ( [0] => бла бла бла [1] => бл [2] => бла бла [3] => и ещё [4] => asf qwe r ) [category_name] => полное описание товара )