Записи с меткой "XSL"
РАЗНЫЕ МЕЛОЧИ В XSL
Разное
<img src="{dir}{image_large}" alt="{name}" width="{image_large_width}" height="{image_large_height}" />
<xsl:variable name="var_compare_id" select="."/>
<xsl:text disable-output-escaping="yes" select="."> </xsl:text>
<xsl:text> </xsl:text>
<xsl:value-of disable-output-escaping="yes" select="property_value[tag_name='short_name']/value" />
<xsl:if test="description !=''">
<xsl:value-of disable-output-escaping="yes" select="description" />
</xsl:if>
<xsl:if test="position() mod 3 = 0 and position() != last()">
<xsl:text disable-output-escaping="yes">
</tr>
<tr valign="top">
</xsl:text>
</xsl:if>
<xsl:if test="property_value[tag_name='link']/value !=''">
<xsl:value-of disable-output-escaping="yes" select="property_value[tag_name='link']/value" />
</xsl:if>
Дополнительное свойство - ссылка
property_value[tag_name='link']/value !=''
<xsl:if test="property_value[tag_name='link']/value !=''">
<xsl:value-of disable-output-escaping="yes" select="property_value[tag_name='link']/value" />
</xsl:if>
<xsl:if test="property_value[tag_name='link']/value !=''">
<a href="{property_value[tag_name='link']/value}" target="_parent" >
<img src="{dir}{image_small}" alt="{name}"/>
</a>
</xsl:if>
<xsl:if test="property_value[tag_name='short_name']/value !=''">
<xsl:value-of disable-output-escaping="yes" select="property_value[tag_name='short_name']/value" />
</xsl:if>
Дополнительное свойство - изображение
<xsl:if test="property_value[tag_name='img']/file !=''">
<a href="{property_value[tag_name='img']/file}">
<img src="{dir}{property_value[tag_name='img']/file}" alt="{name}"
width="{property_value[tag_name='img']/file_width}" height="{property_value[tag_name='img']/file_height}"/>
</a>
</xsl:if>
Ограничение количества групп в выпадающем меню
<!-- Если есть подгруппы -->
<xsl:if test="count(shop_group) > 0 and 1 > count(ancestor::shop_group)">
<ul class="left_menu gray_link gray" id="{@id}" style="display: none;">
<xsl:apply-templates select="shop_group"/>
</ul>
</xsl:if>
Выбираем последний элемент списка и назначаем ему класс last
<xsl:if test="position() mod 4 = 0 and position() > 3">
<xsl:attribute name="class">last</xsl:attribute>
</xsl:if>
Выбираем первый элемент списка и назначаем ему класс first
<xsl:if test="position() mod 1 = 0 and position() < 2">
<xsl:attribute name="class">first</xsl:attribute>
</xsl:if>
Ссылка на все товары производителя в карточке товара
<xsl:if test="shop_producer/node()">
<xsl:variable name="shop_produser_id" select="shop_producer/@id" />
<a href="{/shop/url}producer-{$shop_produser_id}" class="button">Другие товары этого производителя</a>
</xsl:if>
Ограничиваем текст по количеству знаков
<xsl:variable name="myConcatString" select="description"/>
<xsl:value-of disable-output-escaping="yes" select="substring($myConcatString, 1, 800)" /><xsl:text>...</xsl:text>
Вставляем код JAVASCRIPT в XSL
<SCRIPT>
<xsl:comment>
<xsl:text disable-output-escaping="yes">
<![CDATA[
.........код скрипта......................
]]>
</xsl:text>
</xsl:comment>
</SCRIPT>
Шаблон для условия
<xsl:choose>
<xsl:when test="">
...
</xsl:when>
<xsl:otherwise>
...
</xsl:otherwise>
</xsl:choose>
Если нет изображения, то скрываем блок на boostrap 5
<div class="d-none">
<xsl:if test="image_small != ''">
<xsl:attribute name="class">col-xs-3 col-sm-3 col-md-3 col-lg-3</xsl:attribute>
</xsl:if>
<xsl:if test="image_small != ''">
<div>
<a href="{url}">
<img src="{dir}{image_small}" alt="{name}"/>
</a>
</div>
</xsl:if>
Меняем адрес ссылки, если есть Дополнительное свойство - Ссылка на материал
<xsl:variable name="link">
<xsl:choose>
<xsl:when test="property_value[tag_name='link']/value !=''">
<xsl:value-of disable-output-escaping="yes" select="property_value[tag_name='link']/value" />
</xsl:when>
<xsl:otherwise>
<xsl:value-of disable-output-escaping="yes" select="url" />
</xsl:otherwise>
</xsl:choose>
</xsl:variable>
<xsl:choose>
<xsl:when test="property_value[tag_name='link']/value !=''">
<a href="{property_value[tag_name='link']/value}" >
<img src="{dir}{image_small}" class="news_img" alt="" />
</a>
</xsl:when>
<xsl:otherwise>
<img src="{dir}{image_small}" class="news_img" alt="" />
</xsl:otherwise>
</xsl:choose>
Определяем позицию
Добавляем атрибут
<xsl:attribute name="class">
<xsl:choose>
<xsl:when test="position() mod 2 = 0">right</xsl:when>
<xsl:otherwise>left</xsl:otherwise>
</xsl:choose>
</xsl:attribute>
Последний элемент строки
<xsl:if test="position() = last()">
<xsl:attribute name="style">background-image: none</xsl:attribute>
</xsl:if>
<xsl:if test="position() = last()">
<xsl:attribute name="class">last</xsl:attribute>
</xsl:if>
Для меню
<xsl:variable name="position">
<xsl:choose>
<xsl:when test="$count div position() <= 1">4</xsl:when>
<xsl:otherwise>3</xsl:otherwise>
</xsl:choose>
</xsl:variable>
<xsl:if test="position() mod $floor = 0 and position() != last()">
<xsl:text disable-output-escaping="yes">
</ul>
<ul>
</xsl:text>
</xsl:if>
Перевод строки после n-элемента
<xsl:if test="position() mod 4 = 0 and position() != last()">
<xsl:text disable-output-escaping="yes">
</ul>
<ul class="shop_table">
</xsl:text>
</xsl:if>
<xsl:if test="position() mod 3 = 0 and position() != last()">
<span class="table_row"></span>
</xsl:if>
<xsl:if test="position() mod 3 = 0 and position() != last()">
<xsl:attribute name="style">background-image: none</xsl:attribute>
</xsl:if>
В списках
<!-- Перевод строки после каждого 2-го элемента -->
<xsl:if test="((position() - 2) mod 2 = 0) and position() != last()">
<xsl:text disable-output-escaping="yes">
</div>
<div class="wrapper">
</xsl:text>
</xsl:if>
В таблице
<xsl:template match="shop_item">
<td>
.............
</td>
<xsl:if test="position() mod 3 = 0">
<xsl:text disable-output-escaping="yes"></tr><tr></xsl:text>
</xsl:if>
</xsl:template>
<div id="gallery" class="board" style="max-width: {$image_width + 50}px">
Вывод сообщение "В данном разделе магазина товаров нет", если раздел пустой
<xsl:if test="count(shop_item) = 0 and .//shop_group[@id=$group]/items_total_count = 0" >В данном разделе
товаров нет</xsl:if>
Вставляем значение дополнительного свойства в ссылку для изображения
<!-- Изображение для информационного элемента (если есть) -->
<xsl:choose>
<xsl:when test="property_value[tag_name='url']/value != ''">
<a href="{property_value[tag_name = 'url']/value}" target="_parent">
<img src="{dir}{image_small}" align="left"/>
</a>
</xsl:when>
<xsl:otherwise>
<img src="{dir}{image_small}" align="left"/>
</xsl:otherwise>
</xsl:choose>
Выводим массив дополнительных свойств - изображения (file)
<xsl:if test="property_value[tag_name='img']/file != ''">
<ul>
<xsl:for-each select="property_value[tag_name='img']">
<li><a href="{../dir}{file}" ><img src="{../dir}{file_small}" alt="{name}" /></a></li>
</xsl:for-each>
</ul>
</xsl:if>
<xsl:for-each select="property_value[tag_name='dopfoto']">
<a href="{../dir}{file}" target="_blank"><img src="{../dir}{file_small}" /></a>
</xsl:for-each>
Вставляем дату и время в XSL шаблон
<dt>
<xsl:value-of select="substring-before(date, '.')"/>
<xsl:variable name="month_year" select="substring-after(date, '.')"/>
<xsl:variable name="month" select="substring-before($month_year, '.')"/>
<xsl:choose>
<xsl:when test="$month = 1"> января </xsl:when>
<xsl:when test="$month = 2"> февраля </xsl:when>
<xsl:when test="$month = 3"> марта </xsl:when>
<xsl:when test="$month = 4"> апреля </xsl:when>
<xsl:when test="$month = 5"> мая </xsl:when>
<xsl:when test="$month = 6"> июня </xsl:when>
<xsl:when test="$month = 7"> июля </xsl:when>
<xsl:when test="$month = 8"> августа </xsl:when>
<xsl:when test="$month = 9"> сентября </xsl:when>
<xsl:when test="$month = 10"> октября </xsl:when>
<xsl:when test="$month = 11"> ноября </xsl:when>
<xsl:otherwise> декабря </xsl:otherwise>
</xsl:choose>
<xsl:value-of select="substring-after($month_year, '.')"/><xsl:text> г.</xsl:text>
</dt>
Заменяем запятую на точку в цене (каталог товаров)
В самом начале шаблона вывода товаров определяем формат вывода
имеется
<xsl:decimal-format name="my" decimal-separator="," grouping-separator=" "/>
добавляем
<xsl:decimal-format name="my1" decimal-separator="." grouping-separator=" "/>
в выводе цены вставляем код
<xsl:value-of select="format-number(price, '### ##0.00', 'my1')"/>
Откладываем в корзину минимальное количество товара по умолчанию
1. Создаем Допсвойство "Минимальное количество" min_quantity, тип строка.
В карточке товара в Допсвойстве "Минимальное количество" указываем минимальное количество для заказа, например, 10шт.
2. В XSL-шаблоне "ИнтернетМагазинКаталогТоваров" или "ИнтернетМагазинТовар" создаем переменную quantum, которая из Допсвойства min_quantity выделяет только числа
3. Вставляем значение переменной $quantum в скрипт кнопки "В корзину"
ПРИМЕР
<div class="actions">
<xsl:variable name="string" select="property_value[tag_name='min_quantity']/value"/>
<!-- Выделяем из строки числа -->
<xsl:variable name="quantum" select="translate($string, translate($string,'0123456789,',''),'')" />
<a data-animation="fadeAndPop" data-reveal-id="modalCart" id="add_to_cart_{@id}" href="#">
<button class="button btn-cart" onclick="return $.bootstrapAddIntoCart('{/shop/url}cart/', {@id}, {$quantum}); yaCounter31644173.reachGoal('addtocart'); return true;" title="В корзину" type="button">
<i class="fa fa-shopping-cart bg-color5">
<b></b>
</i>
<span class="bg-color3"><span>В корзину</span></span>
</button>
</a>
</div>
Обработка даты - приведение к числу для последующего сравнения с другой датой
<xsl:variable name="datetime" select="datetime" />
<xsl:value-of select="concat(substring($datetime, 7, 4), substring($datetime, 4, 2), substring($datetime, 1, 2), substring($datetime, 12, 2), substring($datetime, 15, 2), substring($datetime, 18, 2) )" disable-output-escaping="yes" />
Пересобираем URL (удаление первых трех символов)
<xsl:variable name="url">
<xsl:for-each select="url">
<xsl:variable name="link">
<xsl:value-of select="."/>
</xsl:variable>
<xsl:value-of select='substring($link, 4, string-length($link) - 1)'/>
</xsl:for-each>
</xsl:variable>
<a href="/en{$url}">... </a>
Меняем формат вывода даты
<div class="date">
<xsl:variable name="month_year" select="substring-after(date, '.')"/>
<xsl:variable name="month" select="substring-before($month_year, '.')"/>
<xsl:variable name="time1" select="substring-after(datetime, ' ')"/>
<xsl:variable name="time2" select="substring-after($time1, ':')"/>
<xsl:variable name="hour" select="substring-before($time1, ':')"/>
<xsl:variable name="minutes" select="substring-before($time2, ':')"/>
<span><xsl:value-of select="substring-before(date, '.')"/>.<xsl:value-of select="$month"/> / <xsl:value-of select="$hour"/>:<xsl:value-of select="$minutes"/></span>
</div>
СОРТИРОВКА ТОВАРОВ ОТ МИНИМАЛЬНОЙ ЦЕНЫ ПО УМОЛЧАНИЮ
В XSL-шаблоне МагазинКаталогТоваров заменяем код
<!--===== Выводим товары магазина =====-->
<div class="row products-grid">
<xsl:apply-templates select="shop_item"/>
</div>
на этот
<!--===== Выводим товары магазина =====-->
<div class="row products-grid">
<xsl:apply-templates select="shop_item">
<xsl:sort select="price" order="ascending" data-type="number"/>
</xsl:apply-templates>
</div>
Для сортировки товаров по умолчанию от максимальной цены заменить ascending на descending
Сортировка Допсвойств по id
<xsl:apply-templates select="property_value[not(file/node())]">
<xsl:sort select="property_id" order="ascending" data-type="number"/>
</xsl:apply-templates>
Случайный вывод элементов
<xsl:template match="/">
<xsl:for-each select="shop_item">
<xsl:value-of select="generate-id()"/> <br/>
</xsl:for-each>
</xsl:template>
Выводим надпись "НОВИНКА" для товаров, загруженных за последние 30 дней
<xsl:variable name="сurrent_date" select="/shop/сurrent_date"/>
<xsl:variable name="date" select="translate(date, translate(date, '0123456789', ''), '')"/>
<xsl:variable name="difference_date" select="$сurrent_date - $date" />
<xsl:if test="number($difference_date) < 30">
<div class="ribbon-wrapper-new">НОВИНКА</div>
</xsl:if>
Предварительно добавляем в ТДС Интернет-магазина вывод текущей даты
Текущая дата в Каталоге товаров
Меняем высоту блока, в зависимости от размера файла изображения из Допсвойства
<div id="sub-menu" class="dropdown-menu">
<xsl:if test="property_value[tag_name='img']/file !=''">
<xsl:attribute name="style">height:<xsl:value-of disable-output-escaping="yes" select="20+(property_value[tag_name='img']/file/@height)" />px</xsl:attribute>
// добавляем к высоте картинки 20px, если нужно, изменить параметр
</xsl:if>
.........
</div>
Быстрый фильтр товаров. Производители
XSL
Выбираем несколько случайных элементов из информационной системы
samenews
$oInformationsystem_Item = Core_Entity::factory('Informationsystem_Item', $Informationsystem_Controller_Show->item);
$oTag_Informationsystem_Items = $oInformationsystem_Item->Tag_Informationsystem_Items->findAll();
// Минимальное количество тегов для совпадения.
$iSameTags = 1;
$aTagIds = array();
foreach($oTag_Informationsystem_Items as $oTag_Informationsystem_Item)
{
$aTagIds[] = $oTag_Informationsystem_Item->tag_id;
}
$oInformationsystem = Core_Entity::factory('Informationsystem', Core_Array::get(Core_Page::instance()->libParams, 'informationsystemId'));
$Informationsystem_id = $oInformationsystem -> id; // Отбираем элементы только из текущей Инфосистемы
if (count($aTagIds))
{
$oSameTag_Informationsystem_Items = Core_Entity::factory('Tag_Informationsystem_Item');
$oSameTag_Informationsystem_Items->queryBuilder()
->select('tag_informationsystem_items.*')
->where('tag_id', 'IN', $aTagIds)
->where('tag_informationsystem_items.informationsystem_item_id', '!=', $oInformationsystem_Item->id)
->where('informationsystems.id', '=', $Informationsystem_id)
->join('informationsystem_items', 'tag_informationsystem_items.informationsystem_item_id', '=', 'informationsystem_items.id')
->join('informationsystems', 'informationsystem_items.informationsystem_id', '=', 'informationsystems.id')
->where('informationsystems.site_id', '=', CURRENT_SITE)
->groupBy('informationsystem_items.id')
->having('COUNT(tag_id)', '>=', $iSameTags)
->clearOrderBy()
->orderBy('RAND()')
->limit(5); // Указываем количество выводимых элементов
$aSameTag_Informationsystem_Items = $oSameTag_Informationsystem_Items->findAll();
$oXmlSamenews = Core::factory('Core_Xml_Entity')->name('samenews');
$Informationsystem_Controller_Show->addEntity($oXmlSamenews);
foreach($aSameTag_Informationsystem_Items as $oSameTag_Informationsystem_Item)
{
$oXmlSamenews->addEntity(
$oSameTag_Informationsystem_Item
->Informationsystem_Item
->clearEntities()
->showXmlProperties(TRUE) // Добавляем дополнительные свойства
);
}
}
XSL . В XSL-шаблон вывода единицы Инфосистемы добавляем следующий код:
Вывод брендов с разбивкой по алфавиту
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE xsl:stylesheet>
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:hostcms="http://www.hostcms.ru/"
exclude-result-prefixes="hostcms">
<xsl:output xmlns="http://www.w3.org/TR/xhtml1/strict" doctype-public="-//W3C//DTD XHTML 1.0 Strict//EN" encoding="utf-8" indent="yes" method="html" omit-xml-declaration="no" version="1.0" media-type="text/xml"/>
<xsl:key name="a" match="shop_producer" use="substring(name, 1, 1)" />
<!-- МагазинСписокПроизводителей -->
<xsl:template match="/">
<section id="produsers">
<xsl:apply-templates select="shop"/>
</section>
</xsl:template>
<xsl:template match="shop">
<div class="top">
<h1>Бренды</h1>
</div>
<xsl:if test="count(shop_producer) = 0">
<div id="error">Производители не найдены!</div>
</xsl:if>
<div class="block3" style="padding: 5px 0 12px 5px;">
<div class="row">
<ul>
<xsl:apply-templates select="shop_producer" mode="alphabet">
<xsl:sort select="name" order="ascending"/>
</xsl:apply-templates>
</ul>
</div>
<!--xsl:apply-templates select="shop_producer">
<xsl:sort select="name" order="ascending"/>
</xsl:apply-templates-->
</div>
</xsl:template>
<xsl:template match="shop_producer" mode="alphabet">
<xsl:variable name="a" select="substring(name,1,1)"/>
<xsl:if test="not(preceding-sibling::shop_producer[starts-with(name, $a)][1])">
<li class="col-xs-12">
<h4><xsl:value-of select="$a"/></h4>
<div class="row">
<ul>
<xsl:for-each select="/shop/shop_producer">
<xsl:variable name="name" select="substring(name,1,1)"/>
<xsl:if test="$a = $name">
<li class="col-xs-6 col-sm-4 col-md-3 match-height"><a class="producer" href="{/shop/url}producer-{@id}/"><xsl:value-of disable-output-escaping="no" select="name"/></a></li>
</xsl:if>
</xsl:for-each>
</ul>
</div>
</li>
</xsl:if>
</xsl:template>
<xsl:template match="shop_producer">
<a class="producer" href="{/shop/url}producers/{path}/"><xsl:value-of disable-output-escaping="no" select="name"/></a>
</xsl:template>
</xsl:stylesheet>
Делаем магазин каталог на Главной странице сайта
INDEX_PAGE_IS_DEFAULT = true-
Идем в структуру сайта, открываем редактирование узла "Главная", переключаем тип с документа на ТДС, выбираем ТДС Интернет-магазин, указываем id магазина и нужные xsl-шаблоны.
-
Идем в раздел "Интернет-магазины", заходим в редактор нужного магазина и меняем в списке узел структуры, к которому он привязан.
Добавляем инфосистему в показ каталога товаров на Главной
<?php
if (Core::moduleIsActive('shop'))
{
$Shop_Controller_Show = new Shop_Controller_Show(
Core_Entity::factory('Shop', 2)
);
$Shop_Controller_Show
->xsl(
Core_Entity::factory('Xsl')->getByName('МагазинКаталогТоваровНаГлавнойСайт2')
)
->groupsMode('none')
->addForbiddenTags('/shop/shop_item', array('description','image_small','image_small_width','image_small_height','guid'))
->group(FALSE)
->itemsPropertiesList(FALSE)
->itemsProperties(TRUE)
->limit(5);
// ADD ВИДЕО
ob_start();
$Informationsystem_Controller_Show = new Informationsystem_Controller_Show(
Core_Entity::factory('Informationsystem', 11)
);
$Informationsystem_Controller_Show
->informationsystemItems()
->queryBuilder()
->clearOrderBy()
->orderBy('RAND()');
$Informationsystem_Controller_Show
->xsl(Core_Entity::factory('Xsl')->getByName('СписокВидеоСайт2'))
->groupsMode('none')
->itemsForbiddenTags([
'text',
'description',
'seo_description',
'seo_keywords',
'seo_title',
])
->group(false)
->itemsPropertiesList(false)
->itemsProperties(true)
->limit(1)
// ->votes(TRUE)
->cache(false)
->show();
$Shop_Controller_Show->addEntity(
Core::factory('Core_Xml_Entity')
->name('video_file')
->value(ob_get_clean())
);
// END ADD
// Объединение с нужной таблицей свойств
$Shop_Controller_Show
->ShopItems()
->queryBuilder()
->where('shop_items.active', '=', 1)
->clearOrderBy()
->orderBy('RAND()')
->leftJoin('shop_item_properties', 'shop_items.shop_id', '=', 'shop_item_properties.shop_id')
->leftJoin('property_value_ints', 'shop_items.id', '=', 'property_value_ints.entity_id',
array(
array('AND' => array('shop_item_properties.property_id', '=', Core_QueryBuilder::expression('`property_value_ints`.`property_id`')))
)
)
// Идентификатор дополнительного свойства
->where('shop_item_properties.property_id', '=', 39)
// Значение дополнительного свойства
->where('property_value_ints.value', '=', '1')
->groupBy('shop_items.id')
// Количество свойств
->having('COUNT(shop_item_properties.shop_id)', '=', 1);
$Shop_Controller_Show->show();
}
?>
А также проверяем, если инфоэлемент не подгружается, то выводить файл по умолчанию. У меня это видеофайл.
<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:hostcms="http://www.hostcms.ru/"
exclude-result-prefixes="hostcms">
<xsl:output xmlns="http://www.w3.org/TR/xhtml1/strict" doctype-public="-//W3C//DTD XHTML 1.0 Strict//EN" encoding="utf-8" indent="yes" method="html" omit-xml-declaration="no" version="1.0" media-type="text/xml"/>
<xsl:decimal-format name="my" decimal-separator="," grouping-separator=" "/>
<xsl:template match="/shop">
<div class="products-row">
<xsl:choose>
<xsl:when test="count(shop_item)">
<xsl:apply-templates select="shop_item[position() < 3]" />
<div class="product">
<xsl:choose>
<xsl:when test="video_file !=''">
<xsl:value-of disable-output-escaping="yes" select="video_file" />
</xsl:when>
<xsl:otherwise>
<div class="video-bg">
<video src="/video/bags003.mp4" type="video/mp4" autoplay="autoplay" muted="muted" loop="loop"></video>
<div class="effects"></div>
</div>
</xsl:otherwise>
</xsl:choose>
</div>
<xsl:apply-templates select="shop_item[position() > 2]" />
</xsl:when>
<xsl:otherwise>
<div class="alert-wrapper">
<div class="alert alert-warning" role="alert">Нет товаров для отображения</div>
</div>
</xsl:otherwise>
</xsl:choose>
</div>
</xsl:template>
<xsl:template match="shop_item">
<xsl:variable name="id" select="@id" />
<div class="product">
<div class="product-img">
<a title="{name}" href="{url}">
<xsl:choose>
<xsl:when test="image_large != ''">
<img alt="{name}" class="lozad" data-src="{dir}{image_large}" width="{image_large_width}" height="{image_large_height}" />
</xsl:when>
<!-- Картинка родительского товара -->
<xsl:when test="modification_id and shop_item/image_large != ''">
<img alt="{name}" title="{name}" data-src="{shop_item/dir}{shop_item/image_large}" class="lazyload"/>
</xsl:when>
<xsl:otherwise><img data-src="/hostcmsfiles/assets/images/no-image.svg" alt="{name}" class="lazyload"/></xsl:otherwise>
</xsl:choose>
</a>
</div>
<div class="product-description">
<div class="product-labels">
<xsl:if test="discount != 0">
<div class="label label-discount">
Скидка
<xsl:choose>
<xsl:when test="shop_discount/percent">
<xsl:value-of disable-output-escaping="yes" select="round(shop_discount/percent)"/>%
</xsl:when>
<xsl:otherwise>
<xsl:value-of disable-output-escaping="yes" select="shop_discount/value"/>
<xsl:apply-templates select="/shop/shop_currency/code">
<xsl:with-param name="value" select="price + discount" />
</xsl:apply-templates>
</xsl:otherwise>
</xsl:choose>
</div>
</xsl:if>
<xsl:choose>
<xsl:when test="property_value[tag_name='in_reserve']/value !=0">
<div class="label">В резерве</div>
</xsl:when>
<xsl:when test="property_value[tag_name='sold']/value !=0">
<div class="label beige">Продана</div>
</xsl:when>
<xsl:when test="round(rest) = 0">
<div class="label">Нет в наличии</div>
</xsl:when>
<xsl:otherwise>
<div class="label beige">В наличии!</div>
</xsl:otherwise>
</xsl:choose>
<xsl:if test="property_value[tag_name='best_price']/value =1">
<div class="label label-best-price fw-bold yellow">Лучшая цена!</div>
</xsl:if>
</div>
<div class="product-icons">
<button type="button" class="icon icon-favorite" onclick="return $.addFavorite('{/shop/url}favorite/', {@id}, this)">
<xsl:if test="/shop/favorite/shop_item[@id = $id]/node() or /shop/shop_favorite/shop_item[@id = $id]/node()">
<xsl:attribute name="class">icon icon-favorite active</xsl:attribute>
</xsl:if>
<i class="svg_icon"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512" width="17px" height="17px"><path class="beige" d="M462.3 62.7c-54.5-46.4-136-38.7-186.6 13.5L256 96.6l-19.7-20.3C195.5 34.1 113.2 8.7 49.7 62.7c-62.8 53.6-66.1 149.8-9.9 207.8l193.5 199.8c6.2 6.4 14.4 9.7 22.6 9.7 8.2 0 16.4-3.2 22.6-9.7L472 270.5c56.4-58 53.1-154.2-9.7-207.8zm-13.1 185.6L256.4 448.1 62.8 248.3c-38.4-39.6-46.4-115.1 7.7-161.2 54.8-46.8 119.2-12.9 142.8 11.5l42.7 44.1 42.7-44.1c23.2-24 88.2-58 142.8-11.5 54 46 46.1 121.5 7.7 161.2z"/></svg></i>
</button>
</div>
<div class="product-description-wrapper">
<xsl:if test="comments_average_grade/node()">
<div class="five-stars-container">
<span class="five-stars" style="width: {comments_average_grade * 20}%"></span>
</div>
</xsl:if>
<a href="{url}" class="h4 product-name d-block"><xsl:value-of select="name"/></a>
<xsl:if test="text != ''">
<div class="description pt-3 pb-3"><xsl:value-of disable-output-escaping="yes" select="text"/></div>
</xsl:if>
<span class="h4 product-price">
<xsl:apply-templates select="/shop/shop_currency/code">
<xsl:with-param name="value" select="price" />
</xsl:apply-templates>
<xsl:if test="discount != 0">
<span class="old-price">
<xsl:apply-templates select="/shop/shop_currency/code">
<xsl:with-param name="value" select="price + discount" />
</xsl:apply-templates>
</span>
</xsl:if>
</span>
<div class="product-cart pt-3">
<button class="btn btn-transparent btn-sm mb-2 white" data-item-id="{@id}" onclick="return $.oneStepCheckout('{/shop/url}cart/', $(this).data('item-id'), 1)" data-toggle="modal" data-target="#oneStepCheckout{@id}"> Заказать</button>
<button type="button" class="btn btn-transparent btn-sm yellow mb-2" onclick="location.href = '{url}'">Подробнее</button>
<!--xsl:choose>
<xsl:when test="modifications_count > 0">
<a class="btn" href="{url}">Выбрать</a>
</xsl:when>
<xsl:otherwise>
<a class="btn" onclick="return $.bootstrapAddIntoCart('{/shop/url}cart/', {@id}, 1)">
<span><i class="fa fa-shopping-basket"></i></span>
<span>В корзину</span>
</a>
</xsl:otherwise>
</xsl:choose-->
</div>
</div>
</div>
</div>
</xsl:template>
<xsl:template match="shop_currency/code">
<xsl:param name="value" />
<xsl:variable name="spaced" select="format-number($value, '# ###', 'my')" />
<xsl:choose>
<xsl:when test=". = 'USD'">$<xsl:value-of select="$spaced"/></xsl:when>
<xsl:when test=". = 'EUR'">€<xsl:value-of select="$spaced"/></xsl:when>
<xsl:when test=". = 'GBP'">£<xsl:value-of select="$spaced"/></xsl:when>
<xsl:when test=". = 'RUB'"><xsl:value-of select="$spaced"/> <span class="rub ps-1"> ₽</span></xsl:when>
<xsl:when test=". = 'AUD'">AU$<xsl:value-of select="$spaced"/></xsl:when>
<xsl:when test=". = 'CNY'"><xsl:value-of select="$spaced"/>元</xsl:when>
<xsl:when test=". = 'JPY'"><xsl:value-of select="$spaced"/>¥</xsl:when>
<xsl:when test=". = 'KRW'"><xsl:value-of select="$spaced"/>₩</xsl:when>
<xsl:when test=". = 'PHP'"><xsl:value-of select="$spaced"/>₱</xsl:when>
<xsl:when test=". = 'THB'"><xsl:value-of select="$spaced"/>฿</xsl:when>
<xsl:when test=". = 'BRL'">R$<xsl:value-of select="$spaced"/></xsl:when>
<xsl:when test=". = 'INR'"><xsl:value-of select="$spaced"/><i class="fa fa-inr"></i></xsl:when>
<xsl:when test=". = 'TRY'"><xsl:value-of select="$spaced"/><i class="fa fa-try"></i></xsl:when>
<xsl:when test=". = 'ILS'"><xsl:value-of select="$spaced"/><i class="fa fa-ils"></i></xsl:when>
<xsl:otherwise><xsl:value-of select="$spaced"/> <xsl:value-of select="." /></xsl:otherwise>
</xsl:choose>
</xsl:template>
</xsl:stylesheet>
<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:hostcms="http://www.hostcms.ru/"
exclude-result-prefixes="hostcms">
<xsl:output xmlns="http://www.w3.org/TR/xhtml1/strict" doctype-public="-//W3C//DTD XHTML 1.0 Strict//EN" encoding="utf-8" indent="yes" method="html" omit-xml-declaration="no" version="1.0" media-type="text/xml"/>
<xsl:template match="/informationsystem">
<xsl:apply-templates select="informationsystem_item[active=1]"/>
</xsl:template>
<xsl:template match="informationsystem_item">
<div class="video-bg">
<video src="{property_value[tag_name='video_link']/value}" autoplay="autoplay" muted="muted" loop="loop"></video>
<div class="effects"></div>
</div>
</xsl:template>
</xsl:stylesheet>
Интернационализация в XSL-шаблонах
<!DOCTYPE xsl:stylesheet><!DOCTYPE xsl:stylesheet SYSTEM "lang://21"><!DOCTYPE xsl:stylesheet SYSTEM "lang://Search">
<!ENTITY labelSearch "Поиск"><h1>&labelSearch;</h1><img src="/images/my-image.png" alt="&labelSearch;" title="&labelSearch;" />Core::setLng('en');
<?php
return array (
'lngs' => array('en', 'de', 'ru'),
);
Информационный блок в карточке товара
Добавляем в карточку товара блок с призывом задать вопрос

1. В XSL шаблон вывода карточки товара в нужном месте размещаем данный код:
<div class="ask-question">
<div class="d-flex justify-content-center">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512" width="40px" height="40px">
<path style="fill:#ccc" d="M448 0H64C28.7 0 0 28.7 0 64v288c0 35.3 28.7 64 64 64h96v84c0 7.1 5.8 12 12 12 2.4 0 4.9-.7 7.1-2.4L304 416h144c35.3 0 64-28.7 64-64V64c0-35.3-28.7-64-64-64zm32 352c0 17.6-14.4 32-32 32H293.3l-8.5 6.4L192 460v-76H64c-17.6 0-32-14.4-32-32V64c0-17.6 14.4-32 32-32h384c17.6 0 32 14.4 32 32v288zm-224-88c-13.3 0-24 10.7-24 24s10.7 24 24 24 24-10.7 24-24-10.7-24-24-24zm-8.5-24h17c4.2 0 7.7-3.3 8-7.5l7-112c.3-4.6-3.4-8.5-8-8.5h-31c-4.6 0-8.3 3.9-8 8.5l7 112c.3 4.2 3.8 7.5 8 7.5z"></path>
</svg>
<span class="ps-3 fs-4 fw-bold title">Есть вопросы?</span>
</div>
<div class="text">
Если у вас есть вопросы по товару, то задавайте их и мы вам с радостью ответим.
</div>
<div class="last">
<button type="button" id="questionModalOpen" data-bs-toggle="modal" data-bs-target="#questionModal" class="btn btn-transparent">Задать вопрос о товаре</button>
</div>
</div>
2. В макет добавляем код загрузки формы (в примере код формы с отправкой уведомления Пользователю). Форма будет в модальном окне. Нажатие на кнопку "Задать вопрос" вызовет открытие формы.
<?php
// ФОРМА ЗАЯВКИ
$oForm = Core_Entity::factory('Form', 1);
$Form_Controller_Show = new Form_Controller_Show($oForm);
if (!is_null(Core_Array::getPost($oForm->button_name)))
{
$Form_Controller_Show
->values($_POST + $_FILES)
// 0 - html, 1- plain text
->mailType(0)
->mailXsl(
Core_Entity::factory('Xsl')->getByName('ПисьмоКураторуФормыВФорматеHTML')
)
->mailFromFieldName('euronasos19@gmail.com')
->process();
// Отправляем письмо-подтверждение пользователю
$Form_Controller_Show1 = clone $Form_Controller_Show;
$sEmail = Core_Array::get($Form_Controller_Show1->values, 'email'); // здесь указать название поля input для email в форме
if (Core_Valid::email($sEmail)){
ob_start();
$Form_Controller_Show1
->xsl(
Core_Entity::factory('Xsl')->getByName('ПисьмоПодтверждениеПользователюФормыВФорматеHTML')
)
->show();
$sMailText = ob_get_clean();
if (mb_strpos($sMailText, 'ERROR TRUE') === FALSE){
$subject = 'На сайте site.ru Вами была заполнена форма Заявки';// Тему письма отредактировать
$oCore_Mail = Core_Mail::instance()
->to($sEmail)
->from('info@site.ru')
->subject($subject)
->message(trim($sMailText))
->contentType('text/html')
->header('X-HostCMS-Reason', 'Form');
$oCore_Mail->send();
}
}
}
$Form_Controller_Show
->xsl(
Core_Entity::factory('Xsl')->getByName('ОтобразитьФормуЗаявкиВМодальномОкне')
)
->show();
?>
XSL . ФормаЗаявкиВМодальномОкне
<!ENTITY labelModalTitle1 "Благодарим вас за заявку!">
<!ENTITY labelModalTitle2 "Заявка получена.">
<!ENTITY labelSuccessText "Мы свяжемся с вами в ближайшее время">
<!ENTITY labelSuccessText2 "Наш менеджер ответит на все ваши вопросы">
<!ENTITY labelERROR "ОШИБКА!">
<!ENTITY labelTextErrorId0 "Вы неправильно ввели код подтверждения отправки формы!">
<!ENTITY labelTextErrorId1 "Заполните все обязательные поля!">
<!ENTITY labelTextErrorId2 "С момента отправки последней формы прошло слишком мало времени!">
<!ENTITY labelTextError1 "Это поле пустое">
<!ENTITY labelTextError2 "E-mail должен иметь вид name@domain.com">
<!ENTITY labelText1 "Обязательное поле">
<!ENTITY labelCheckNumber1 "Проверочный код">
<!ENTITY labelCheckNumber2 "показать другой код">
Стили CSS
/******************************/
.ask-question {
padding:20px;
background-color: #f0f0f0;
max-width:450px;
text-align: center;
}
.ask-question > div:not(.last) {
margin-bottom:15px;
}
background:
border:
color: #212529;
/******************************/
Использование jQuery Validate для проверки форм
<script>
$(function() {
$(".validate").validate({
focusInvalid: true,
errorClass: "input_error",
onkeyup: false,
onfocusout: false,
rules: {
captcha: {
required: true,
remote: '/forms/'
},
author: "required",
text: "required",
email: {
required: true,
email: true
}
},
messages: {
author: "Пожалуйста, укажите своё Имя!",
text: "Пожалуйста, напишите свой комментарий!",
captcha: "Вы не вписали контрольное число!",
email: {
required: "Введите свой email",
email: "E-mail должен быть в формате name@domain.com"
}
}});
});
</script>
Core_Page::instance()
// jQuery
->js('/hostcmsfiles/jquery/jquery.min.js')
...
// Validate
->js('/hostcmsfiles/jquery/jquery.validate.min.js')
...
->showJs();
Указание валидации формы
<script>
$(".validate").validate();
</script>
Валидация всех форм:
<script>
$("form").validate();
</script>
Способы валидации форм
Использование имена классов как правила
<form action="." method="post" class="validate">
<input type="text" name="name" value="" class="required" />
<input type="submit" value="Submit" />
</form>
<form action="." method="post" class="validate">
<input type="text" name="name" value="" class="name" />
<input type="text" name="zip" value="" class="zip" />
<input type="submit" value="Submit" />
</form>
<script >
$.validator.addClassRules("name", {
required: true,
minlength: 2
});
</script >
<script >
$.validator.addClassRules({
name: {
required: true,
minlength: 2
},
zip: {
required: true,
digits: true,
minlength: 5,
maxlength: 5
}});
</script >
Передача опций при инициализации validate()
<script >
$(".validate").validate({
rules: {
name: "required",
email: {
required: true,
email: true
}
},
messages: {
name: "Please specify your name",
email: {
required: "Введите свой email",
email: "E-mail должен быть в формате name@domain.com"
}
}});
</script >
-
required — поле обязательное для заполнения (true или false);
-
remote — указывается файл для проверки поля (например: "check.php");
-
email — проверяет корректность e-mail адреса (true или false);
-
url — проверяет корректность url адреса (true или false);
-
date — проверка корректности даты (true или false);
-
dateISO — проверка корректности даты ISO (true или false);
-
number — проверка на число (true или false);
-
digits — только цифры (true или false);
-
creditcard — корректность номера кредитной карты (true или false);
-
equalTo — равное чему-то (например другому полю equalTo: "#pswd");
-
accept — проверка на правильное расширение (accept: "xls|csv");
-
maxlength — максимальное кол-во символов;
-
minlength — минимальное кол-во символов;
-
rangelength — кол-во символов от скольких и до скольких (rangelength: [2, 5]);
-
range — число должно быть в диапазоне от и до (range: [2, 12]);
-
max — максимальное значение числа;
-
min — минимальное значение числа.
Пример использования в XSL-шаблоне
<script >
$(".validate").validate({
rules: {
surname: "required",
name: "required",
email: {
required: true,
email: true
}
},
messages: {
surname: "Введите фамилию!",
name: "Введите имя!",
email: {
required: "Введите e-mail!",
email: "Адрес должен быть вида name@domain.com"
}
},
focusInvalid: true,
errorClass: "input_error"
});
</script>
Проверка валидации и заблокированного E-mail нежелательного Пользователя<SCRIPT>
$(document).ready(function() {
$('.select2').addClass('required');
$("#form<xsl:value-of select="@id" />").submit(function (event) {
event.preventDefault();
var eml = $('input[name=email]').val();
if(eml =='svinya.svintus@yandex.ru') {
alert ('Вы не можете отправлять нам письма');
$(location).attr('href', '/');
}else{
$(this).validate({
focusInvalid: true,
errorClass: "input_error"
});
}
});
});
</SCRIPT>
Карточка услуги с вертикальным слайдером на основе Swiper

XSL
<?xml version="1.0" encoding="utf-8"?>
JavaScript / jQuery
* Swiper 9.0.2
* Most modern mobile touch slider and framework with hardware accelerated transitions
* https://swiperjs.com
*
* Copyright 2014-2023 Vladimir Kharlampidi
*
* Released under the MIT License
*
* Released on: February 3, 2023
*/
//# sourceMappingURL=swiper-bundle.min.js.map
Стили CSS
* Swiper 8.4.4
* Most modern mobile touch slider and framework with hardware accelerated transitions
* https://swiperjs.com
*
* Copyright 2014-2022 Vladimir Kharlampidi
*
* Released under the MIT License
*
* Released on: October 12, 2022
*/
Модальное окно с формой подписки и сохранением куки на jQuery

Добавляем в макет код показа формы:
<?php
// add ФОРМА ПОДПИСКА ЗА СКИДКУ
$oForm = Core_Entity::factory('Form', 49); // заменить ID формы
$Form_Controller_Show = new Form_Controller_Show($oForm);
if (!is_null(Core_Array::getPost($oForm->button_name)))
{
$Form_Controller_Show
->values($_POST + $_FILES)
// 0 - html, 1- plain text
->mailType(0)
->mailXsl(
Core_Entity::factory('Xsl')->getByName('ПисьмоКураторуФормыВФорматеHTML')
)
->mailFromFieldName('email')
->process();
}
$Form_Controller_Show
->xsl(
Core_Entity::factory('Xsl')->getByName('ОтобразитьФормуВМодальномОкне')
)
->show();
?>
Подключаем в макете скрипт jquery.cookie.min.js:
<script src="/js/jquery.cookie.min.js"></script>
Проверяем куки:
<script>
$(document).ready(function($) {
if ($.cookie('was') == null) {
// Покажем всплывающее окно
setTimeout(function(){$('#popupModal').modal('show');}, 36000);
}
// Запомним в куках, что посетитель к нам уже заходил
$.cookie('was', 'value', { expires: 2, path: '/' });
});
</script>JavaScript / jQuery . jquery.cookie.min.js
Наиболее часто используемые XSLT и XPath функции
Функции XSLT
-
node-set current() — возвращает текущий узел преобразования;
-
node-set document(object, node-set) — позволяет обращаться к внешним документам по заданным URI. Первый узел необязательного параметра node-set принимается за точку отсчета для относительных URI;
-
boolean element-available(string) — проверяет доступность элемента или множества, указанного в параметре. В качестве параметра принимает строку - имя искомого элемента;
-
string format-number(number, format, name?) — возвращает число number в виде строки, отформатированной в соответствии с параметром format. Необязательный параметр name - это имя QName, задающее формат в соответствии правилами элемента <xsl:decimal-format>;
-
boolean function-available(string) — проверяет доступность функции указанной в параметре. В качестве параметра принимает строку - имя функции;
-
string generate-id(node-set) — присваивает уникальный строковый идентификатор первому узлу переданного множества node-set или контекстного узла, если аргумент опущен;
-
node-set key(name, value) — по данному имени name и значению ключа value возвращает множество узлов, которые им обладают. Ключи создаются при помощи элемента <xsl:key>;
-
string system-property(string)— возвращает значения системных свойств, имя которых передается как аргумент;
-
xsl:version — возвращает версию XSLT процессора;
-
xsl:vendor — возвращает производителя XSLT процессора;
-
xsl:vendor-url — возвращает URL, идентифицирующий производителя.
-
string unparsed-entity-uri(string) — предоставляет доступ к не разбираемым сущностям, возвращая URI сущности по ее имени.
Функции XPath
Логические функции
-
boolean boolean(object)— функция возвращает логическое значение переданного ей объекта;
-
number — если число равно нулю возвращает ложь, иначе — истину. NaN всегда возвращает ложь;
-
string — если строка не пуста возвращает истину, иначе — ложь;
-
boolean — значение не изменяется;
-
node-set — пустой набор узлов дает ложь, иначе — истину.
-
boolean false() — функция возвращает ложь;
-
boolean lang(string) — функция проверяет соответствие языка контекстного узла(определенного параметром xml:lang) переданному ей языку в виде строки string;
-
boolean not(boolean) — выполняет логическое отрицание;
-
boolean true() — функция возвращает истину.
Числовые функции
-
number ceiling(number) — округляет аргумент до ближайшего целого, не меньшего переданного функции числа;
-
number floor(number) — округляет аргумент до ближайшего целого, не большего переданного функции числа;
-
number number(object?) — явным образом приводит переданный функции объект в числовой тип. Если аргумент опущен, то применяется к множеству контекстного узла;
-
number round(number) — округляет аргумент до ближайшего целого значения;
-
number sum(node-set) — суммирует значения узлов переданного ей множества.
Строковые функции
-
string concat(string, string, …) — возвращает конкатенацию аргументов;
-
boolean contains(string, string) — принимает на вход два строковых аргумента и возвращает true, если первая строка содержит вторую и false в противном случае;
-
string normalize-space(string?) — удаляет начальные и завершающие разделительные символы, нормализует все внутренние идущие подряд разделители в один пробел. Если аргумент опущен, выполняется со строковым значением контекстного узла;
-
boolean starts-with(string, string) — принимает на вход два строковых аргумента и проверяет начинается ли первая строка со второй;
-
string string(object?) — приводит объект к строковому типу явным образом. Если аргумент опущен, то применяется к множеству контекстного узла;
-
number string-length(string?) — возвращает длину переданного ей строкового аргумента. Если аргумент опущен, то применяется к контекстному узлу;
-
string substring(string, number, number?) — возвращает подстроку переданного ей строкового аргумента, начинающуюся с позиции определенной вторым аргументом и длиной, указанной третьим аргументом. Если третий аргумент не передан, то подстрока продолжается до конца строки;
-
string substring-after(string, string) — принимает на вход два строковых аргумента, находит в первой строке вторую и возвращает подстроку, которая за ней следует;
-
string substring-before(string, string) — принимает на вход два строковых аргумента, находит в первой строке вторую и возвращает подстроку, которая ей предшествует;
-
string translate(string, string, string) — производит замену символов первого своего строкового аргумента, которые присутствуют во втором аргументе на соответствующие символы третьего аргумента.
Функции для работы с наборами узлов
-
number count(node-set) — возвращает число узлов в наборе node-set, переданного ей в качестве аргумента;
-
node-set id(id-value) — возвращает множество узлов по уникальным идентификаторам;
-
number last() — возвращает позицию последнего узла в наборе узлов;
-
string local-name(node-set?) — возвращает локальное (неполное) имя узла, или имя первого узла множества. Если node-set не передан, функция вернет имя контекстного узла;
-
string name(node-set?) — возвращает полное имя узла, или имя первого узла множества. Если node-set не передан, функция вернет локальную часть имени контекстного узла;
-
string namespace-uri(node-set?) — возвращает URI пространства имен а расширенном имени узла;
-
number position() — возвращает позицию контекстного узла в наборе узлов.xsl
Плавающий блок с призывом добавить товар в Избранное (на Bootstrap)
В XSL шаблон карточки товара над иконкой Избранного добавляем код:
<div class="alert alert-primary d-flex align-items-center alert-dismissible fade show alert-info-modal" role="alert">
<small>Понравился товар? Добавьте его в избранное</small>
<button type="button" class="btn-close" data-bs-dismiss="alert" aria-label="Закрыть"></button>
</div>
Блок будет показываться с небольшой задержкой. Для этого используем возможности CSS3
@keyframes showDiv {
0%,
94% {
opacity: 0;
}
95% {
opacity: 0.3;
}
100% {
opacity: 1;
}
}
Для кода использованы стили alert фреймворка Bootstrap 5
Закрывается блок нажатием на крестик.

Стили CSS
.alert-wrapper {
display: flex;
justify-content: center;
width: 100%;
}
.alert-info-modal {
background-color: #ff8100;
border: 0;
color: #fff;
position: absolute;
bottom: 95%;
left: 50%;
min-width: 280px;
padding: 10px 15px;
animation: showDiv 3s forwards;
-webkit-transition: all 0.2s linear;
-moz-transition: all 0.2s linear;
-o-transition: all 0.2s linear;
transition: all 0.2s linear;
}
.alert-info-modal:before {
border-width: 0.4rem 0.4rem 0;
position: absolute;
content: "";
border-color: transparent;
border-style: solid;
border-top-color: #ff8100;
top: 100%;
left: 0px;
transform: translate(50px,0px);
}
.alert-info-modal:after {
margin-top: -1px;
transform: rotate(45deg);
}
@keyframes showDiv {
0%,
94% {
opacity: 0;
}
95% {
opacity: 0.3;
}
100% {
opacity: 1;
}
}
Сортировка значений дополнительных свойств
Значения дополнительных свойств выбираются из нескольких таблиц и не имеют порядка сортировки, в отличии от самих дополнительных свойств. Если Вам необходимо выводить значения дополнительных свойств в порядке сортировки свойств, то в XSL-шаблоне необходимо вместо прямого применения шаблона к property_value применять шаблон к property, а из шаблона property применять шаблон к property_value с ограничением по property_id.
Вариант 1
<xsl:template match="shop_item">
...
<xsl:apply-templates select="/shop/shop_item_properties//property">
<xsl:sort
select = "sorting"
data-type = "number"
order = "ascending"
/>
</xsl:apply-templates>
...
</xsl:template>
<xsl:template match="property">
<xsl:variable name="property_id" select="@id" />
<xsl:if test="/shop/shop_item/property_value[property_id = $property_id]/value/node() and /shop/shop_item/property_value[property_id = $property_id]/value != '' or /shop/shop_item/property_value[property_id = $property_id]/type != 2">
<tr>
<td><xsl:value-of disable-output-escaping="yes" select="name"/></td>
<xsl:apply-templates select="/shop/shop_item/property_value[property_id = $property_id]" />
</tr>
</xsl:if>
</xsl:template>
<xsl:template match="/shop/shop_item/property_value">
<xsl:variable name="property_id" select="property_id" />
<xsl:variable name="property" select="/shop/shop_item_properties//property[@id=$property_id]" />
<td style="padding: 5px" bgcolor="#F5F5F5">
<xsl:choose>
<xsl:when test="$property/type = 7">
<input type="checkbox" disabled="disabled">
<xsl:if test="value = 1">
<xsl:attribute name="checked">checked</xsl:attribute>
</xsl:if>
</input>
</xsl:when>
<xsl:otherwise>
<xsl:value-of disable-output-escaping="yes" select="value"/>
</xsl:otherwise>
</xsl:choose>
</td>
</xsl:template>
Рабочий вариант с сайта (вывод свойств разбит по директориям)
<xsl:if test="count(property_value[property_dir_id=14])">
<div class="property_list_title">Габариты и вес</div>
<div class="propertys-property_list">
<xsl:apply-templates select="/shop/shop_item_properties//property[property_dir_id=14]">
<xsl:sort
select = "sorting"
data-type = "number"
order = "ascending"
/>
</xsl:apply-templates>
</div>
</xsl:if>
<xsl:template match="property">
<xsl:variable name="property_id" select="@id" />
<xsl:if test="/shop/shop_item/property_value[property_id = $property_id]/value/node() and /shop/shop_item/property_value[property_id = $property_id]/value != '' or /shop/shop_item/property_value[property_id = $property_id]/type != 2">
<xsl:apply-templates select="/shop/shop_item/property_value[property_id = $property_id]" mode="property_list"/>
</xsl:if>
</xsl:template>
<!-- Вывод строки со значением свойства -->
<xsl:template match="property_value" mode="property_list">
<xsl:f test="value/node() and value != '' or file/node() and file != ''">
<div class="shop_property">
<xsl:variable name="property_id" select="property_id" />
<xsl:variable name="property" select="/shop/shop_item_properties//property[@id=$property_id]" />
<span class="property-name">
<xsl:value-of select="$property/name"/>
</span>
<span class="property-value"><xsl:choose>
<xsl:when test="$property/type = 2">
<a href="{../dir}{file}" target="_blank"><xsl:value-of select="file_name"/></a>
</xsl:when>
<xsl:when test="$property/type = 5">
<a href="{informationsystem_item/url}"><xsl:value-of select="informationsystem_item/name"/></a>
</xsl:when>
<xsl:when test="$property/type = 7">
<input type="checkbox" disabled="disabled">
<xsl:if test="value = 1">
<xsl:attribute name="checked">checked</xsl:attribute>
</xsl:if>
</input>
</xsl:when>
<xsl:when test="$property/type = 12">
<a href="{shop_item/url}"><xsl:value-of select="shop_item/name"/></a>
</xsl:when>
<xsl:otherwise>
<xsl:value-of disable-output-escaping="yes" select="value"/>
<!-- Единица измерения свойства -->
<xsl:if test="$property/shop_measure/node()">
<xsl:text> </xsl:text><xsl:value-of select="$property/shop_measure/name"/>
</xsl:if>
</xsl:otherwise>
</xsl:choose></span>
</div>
</xsl:if>
</xsl:template>
Вариант 2
<!-- Шаблон для товара -->
<xsl:template match="shop_item">
...
<xsl:variable name="myItem" select="." />
<xsl:for-each select="/shop/shop_item_properties//property">
<xsl:variable name="propertyId" select="@id" />
<xsl:choose>
<xsl:when test="count($myItem/property_value[property_id = $propertyId])">
<xsl:apply-templates select="$myItem/property_value[property_id = $propertyId]"/>
</xsl:when>
<xsl:otherwise><td></td></xsl:otherwise>
</xsl:choose>
</xsl:for-each>
...
</xsl:template>
Вариант 3
Используется при сортировке значений дополнительных свойств при выводе списка товаров. Хук вносится в код типовых динамических страниц и добавляет тег sort для значений доп. свойств (в примере для значений свойств целого и строчного типа).
if (!$Shop_Controller_Show->item)
{
class Property_Value_Observer
{
static public function onBeforeGetXml($object, $args)
{
$object->addXmlTag('sort', $object->Property->sorting);
}
}
Core_Event::attach('property_value_string.onBeforeGetXml', array('Property_Value_Observer', 'onBeforeGetXml'));
Core_Event::attach('property_value_int.onBeforeGetXml', array('Property_Value_Observer', 'onBeforeGetXml'));
}
Вариант 4
Сортировка значений одного свойства в порядке добавления достигается указанием <xsl:sort select="@id" />, например:
<xsl:for-each select="property_value[tag_name='img'][file !='']">
<xsl:sort select="@id" />
<div class="item">
<a href="{../dir}{file}" class="elevatezoom-gallery" data-image="{../dir}{file}" data-zoom-image="{../dir}{file}">
<img class="img-responsive" height="150" width="100" src="{../dir}{file}"/>
</a>
</div>
</xsl:for-each>
Ссылка на предыдущую и следующую новость в Инфосистеме
// добавляем окружающие элементы
// Если мы находимся на странице новости
if ($Informationsystem_Controller_Show->item) {
$oInformationsystem_Item = Core_Entity::factory('Informationsystem_Item', $Informationsystem_Controller_Show->item);
// Текущий элемент
$cur_elem = $Informationsystem_Controller_Show->item;
// Текущая группа
$cur_group = $oInformationsystem_Item->informationsystem_group_id;
// SELECT * FROM informationsystem_Items WHERE informationsystem_Items.id < $cur_elem ORDER BY informationsystem_Items.id DESC LIMIT 1
$oCore_QueryBuilder_Select = Core_QueryBuilder::select()
->select('informationsystem_items.path','informationsystem_items.name')
->from('informationsystem_items')
->open()
->where('informationsystem_items.id', '<', $cur_elem)
->setAnd()
->where('informationsystem_items.informationsystem_group_id', '=', $cur_group)
->setAnd()
->where('informationsystem_items.deleted', '=', '0')
->close()
->clearOrderBy()
->orderBy('id', 'DESC')
->limit(1);
$prev = $oCore_QueryBuilder_Select->execute()->asAssoc()->current();
$prev = $prev['path'];
$prev_name = $oCore_QueryBuilder_Select->execute()->asAssoc()->current();
$prev_name = $prev_name['name'];
// SELECT * FROM informationsystem_Items WHERE informationsystem_Items.id > $cur_elem ORDER BY informationsystem_Items.id LIMIT 1
$oCore_QueryBuilder_Select = Core_QueryBuilder::select()
->select('informationsystem_items.path','informationsystem_items.name')
->from('informationsystem_items')
->open()
->where('informationsystem_items.id', '>', $cur_elem)
->setAnd()
->where('informationsystem_items.informationsystem_group_id', '=', $cur_group)
->setAnd()
->where('informationsystem_items.deleted', '=', '0')
->close()
->clearOrderBy()
->orderBy('id')
->limit(1);
$next = $oCore_QueryBuilder_Select->execute()->asAssoc()->current();
$next = $next ['path'];
$next_name = $oCore_QueryBuilder_Select->execute()->asAssoc()->current();
$next_name = $next_name['name'];
$Informationsystem_Controller_Show
->addEntity(Core::factory('Core_Xml_Entity')
->name('neighboring_items')
->addEntity(Core::factory('Core_Xml_Entity')->name('prev_item')->value($prev))
->addEntity(Core::factory('Core_Xml_Entity')->name('prev_item_name')->value($prev_name))
->addEntity(Core::factory('Core_Xml_Entity')->name('next_item')->value($next))
->addEntity(Core::factory('Core_Xml_Entity')->name('next_item_name')->value($next_name))
);
}
// добавляем окружающие элементы
<!-- Получаем ID родительской группы и записываем в переменную $group -->
<xsl:variable name="group" select="/informationsystem/group"/>
<!-- окружающие элементы -->
<xsl:variable name="link_path" select="/informationsystem//informationsystem_group[@id=$group]/url"/>
<xsl:variable name="prev_item" select="/informationsystem/neighboring_items/prev_item"/>
<xsl:variable name="next_item" select="/informationsystem/neighboring_items/next_item"/>
<xsl:variable name="prev_item_name" select="/informationsystem/neighboring_items/prev_item_name"/>
<xsl:variable name="next_item_name" select="/informationsystem/neighboring_items/next_item_name"/>
<div class="navigator">
<xsl:choose>
<xsl:when test="$prev_item != ''">
<a href="{$link_path}{$prev_item}/">< Предыдущий элемент (<xsl:value-of select="$prev_item_name" />)</a>
</xsl:when>
<xsl:otherwise>
<span class="previous">< Предыдущий элемент</span>
</xsl:otherwise>
</xsl:choose>
<xsl:choose>
<xsl:when test="$next_item != ''">
<a href="{$link_path}{$next_item}/">(<xsl:value-of select="$next_item_name" />) Следующий элемент ></a>
</xsl:when>
<xsl:otherwise>
<span class="next">Следующий элемент ></span>
</xsl:otherwise>
</xsl:choose>
</div>
<!-- /окружающие элементы -->
Текущая дата в Каталоге товаров
В XSL шаблон к xsl:stylesheet добавляем новые атрибуты xmlns:date="http://exslt.org/dates-and-times" и extension-element-prefixes="date", должно получится:
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:hostcms="http://www.hostcms.ru/"
exclude-result-prefixes="hostcms"
xmlns:date="http://exslt.org/dates-and-times" extension-element-prefixes="date">
Далее например можно записать в переменную текущую дату и вычислить разницу с другой датой с помощью date:difference(string, string).
Чтобы код работал, в настройках магазина меняем формат даты на %Y-%m-%d
в ТДС записываем текущую дату
$oCurrent_date = date('dmY'); // именно в этом формате
$Shop_Controller_Show
->addEntity(Core::factory('Core_Xml_Entity')->name('сurrent_date')->value($oCurrent_date)); // теперь в XML есть сurrent_date
Теперь, если дата создания товара меньше 30 дней, выводим слово НОВИНКА
<xsl:variable name="current_date" select="/shop/current_date"/>
<xsl:variable name="difference_date" select="date:difference($current_date,datetime)" />
<xsl:variable name="difference_date_cut" select="substring-before(substring-after($difference_date, 'P'), 'D')" />
<xsl:if test="number($difference_date_cut) < 30"> <!-- 30 количество дней -->
<div class="ribbon-wrapper-new">
<div class="ribbon-round-new bg-color3">НОВИНКА</div>
</div>
</xsl:if>
Удаление всех товаров из корзины
Для того, чтобы дать возможность пользователю удалить из корзины сразу все товары необходимо:
1. Добавить в настройки ТДС корзины перед строкой
Core_Page::instance()->object = $Shop_Cart_Controller_Show
вот этот код:
// Удаление всех товаров из корзины
if (Core_Array::getGet('delete_all'))
{
$oShop_Cart_Controller = Shop_Cart_Controller::instance();
$oItemsInCart = $oShop_Cart_Controller->getAll($oShop);
foreach( $oItemsInCart as $oItemInCart)
{
$oShop_Cart_Controller
->shop_item_id($oItemInCart->shop_item_id)
->delete();
}
}
2. Для удаления всех товаров в XSL шаблоне Корзины разместить ссылку
<a title="Удалить все товары из заказа" onclick="return confirm('Вы уверены, что хотите удалить все товары из заказа?')" href="/shop/cart/?delete_all=1">Удалить все</a>УДАЛЕНИЕ И ДОБАВЛЕНИЕ ТОВАРОВ В КРАТКОЙ КОРЗИНЕ
// Добавление товара в корзину
if (Core_Array::getRequest('add')) ...
// Ajax Обновление товара в корзине
if (Core_Array::getRequest('updateCart')) {
$shop_item_id = intval(Core_Array::getRequest('updateCart'));
$count = intval(Core_Array::getRequest('count'));
if (($shop_item_id) && ($count)) {
$oShop_Cart_Controller = Shop_Cart_Controller::instance();
$oShop_Cart_Controller
->checkStock($bCheckStock)
->shop_item_id($shop_item_id)
->quantity($count)
->update();
}
}
// Ajax Удаляение товара из корзины
if (Core_Array::getRequest('deleteCart')) {
$shop_item_id = intval(Core_Array::getRequest('deleteCart'));
if ($shop_item_id) {
$oShop_Cart_Controller = Shop_Cart_Controller::instance();
$oShop_Cart_Controller
->shop_item_id($shop_item_id)
->delete();
}
}
// Ajax
if (Core_Array::getRequest('_', FALSE) && (Core_Array::getRequest('add') || Core_Array::getRequest('loadCart')))
// Ajax
if (Core_Array::getRequest('_', FALSE) && (Core_Array::getRequest('add') || Core_Array::getRequest('loadCart') || Core_Array::getRequest('updateCart') || Core_Array::getRequest('deleteCart')))
// Функции без создания коллекции
$.extend({
...
updateCart: function(path, shop_item_id, count){
$.clientRequest({
path: path + '?updateCart=' + shop_item_id + '&count=' + count,
callBack: $.updelCallback,
context: $('.little-cart')
});
return false;
},
deleteCart: function(path, shop_item_id){
$.clientRequest({
path: path + '?deleteCart=' + shop_item_id,
callBack: $.updelCallback,
context: $('.little-cart')
});
return false;
},
updelCallback: function(data, status, jqXHR){
$.loadingScreen('hide');
$(this).html(data);
}
<xsl:variable name="kol" select="../quantity" />
<xsl:variable name="cena" select="format-number(price, '#####0,##', 'my')" />
Стоимость: <xsl:value-of select="$cena * $kol"/>
<br />
Кол-во: <xsl:value-of select="$kol"/>
<br />
<a href="#" onclick="return $.updateCart('{/shop/url}cart/', {@id}, {$kol}+1)">Добавить</a>
<br />
<a href="#" onclick="return $.updateCart('{/shop/url}cart/', {@id}, {$kol}-1)">Убавить</a>
<br />
<a href="#" onclick="return $.deleteCart('{/shop/url}cart/', {@id})">Удалить</a>
<p>Сумма: <xsl:value-of select="total_amount"/><xsl:text> </xsl:text><xsl:value-of select="shop_currency/name"/></p>
Добавить, Убавить и Удалить лучше всего доработать и заменить на иконкиШАБЛОН "МагазинСамыеПопулярныеТовары"
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE xsl:stylesheet>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:hostcms="http://www.hostcms.ru/" exclude-result-prefixes="hostcms">
<xsl:output xmlns="http://www.w3.org/TR/xhtml1/strict" doctype-public="-//W3C//DTD XHTML 1.0 Strict//EN" encoding="UTF-8" indent="yes" method="html" omit-xml-declaration="no" version="1.0" media-type="text/xml"/>
<!-- Шаблон показа популярных товаров.
Основан на шаблоне "МагазинКаталогТоваровНаГлавнойСпецПред" -->
<!-- Кол-во товаров в строку
Если указано 0 то не разбивать, выводить все в одну строку -->
<xsl:param name="items_per_line" select="'3'"/>
<!--Формат вывода чисел-->
<xsl:decimal-format name="my" decimal-separator="," grouping-separator=" "/>
<!--Создадим ключ по идентификатору товара, чтобы оптимизировать выборку товаров при показе в предопределенном порядке -->
<xsl:key name="items_id" match="/shop/shop_item" use="@id"/>
<!--Признак того, что нужно показывать товары в порядке убывания популярности-->
<xsl:variable name="is_ordered_show" select="/shop/popular/method = 'orders' and /shop/popular/item"/>
<xsl:template match="/shop">
<!-- Есть товары -->
<xsl:if test="shop_item">
<h1>Популярные товары</h1>
<!-- Выводим товары магазина -->
<xsl:choose>
<!--Если в XML существуют узлы, описывающие порядок показа товаров-->
<xsl:when test="$is_ordered_show">
<!--то запустим цикл по этим узлам-->
<xsl:for-each select="popular/item">
<xsl:sort select="@order" data-type="number" order="ascending"/>
<!--и для каждого id товара будем вызывать темплейт item, передавая в него узел соответствующего товара, выбранный с помощью ключа-->
<xsl:apply-templates select="key('items_id', .)">
<xsl:with-param name="ordered_count" select="current()/@count"/>
</xsl:apply-templates>
<!--Если показываем товары в порядке убывания популярности,
то добавляем разбивку по N товаров в строке
ЗДЕСЬ.-->
<xsl:if test="$items_per_line > 3 and position() mod $items_per_line = 3 and position() != last()">
<div style="margin-top:20px;" class="clear"/>
</xsl:if>
</xsl:for-each>
</xsl:when>
<!--а в случае рандомного показа просто вызовем темплейт item для всех товаров описанных в XML-->
<xsl:otherwise>
<xsl:apply-templates select="shop_item"/>
</xsl:otherwise>
</xsl:choose>
<div class="clear"></div>
</xsl:if>
</xsl:template>
<!-- Шаблон для товара -->
<xsl:template match="shop_item">
<div class="shop-item">
<div class="inner">
<a href="{url}" title="Подробная информация // {name} // {shop_producer/name}" class="item-images-inner">
<!-- Изображение для товара, если есть -->
<xsl:choose>
<xsl:when test="image_small!=''" >
<img src="{dir}{image_small}" alt="{name}" class="item-image" />
</xsl:when>
<xsl:otherwise>
<img src="/images/no_img.jpg" alt="{name}" />
</xsl:otherwise>
</xsl:choose>
<img src="/images/bg-item.png" alt="{name}" class="item-image-back" />
</a>
<xsl:if test="property_value[tag_name = 'hit'] != ''">
<span class="hit"></span>
</xsl:if>
<!-- Название товара -->
<span class="price">
<xsl:value-of select="shop_producer/name" />
<!--<xsl:value-of disable-output-escaping="yes" select="name"/>--><xsl:text> / </xsl:text>
<xsl:if test="marking != ''">
<span><xsl:value-of disable-output-escaping="yes" select="marking"/></span><xsl:text> / </xsl:text>
</xsl:if>
<!-- Цена товара -->
<xsl:choose>
<xsl:when test="price != 0">
<span>
<xsl:variable name="price" select="price"/>
<xsl:value-of select="format-number($price, '### ##0', 'my')"/> 
<!-- Валюта товара -->
<xsl:value-of disable-output-escaping="yes" select="currency"/>
</span>
</xsl:when>
<xsl:otherwise>
<span class="shop_price">под заказ</span>
</xsl:otherwise>
</xsl:choose>
<!-- Если цена со скидкой - выводим ее -->
<xsl:if test="price_tax != price">
<span style="color: gray; text-decoration: line-through;">
<xsl:variable name="price_tax" select="price_tax"/>
<span style="font-size: 11pt">
<xsl:value-of select="format-number($price_tax, '### ##0', 'my')"/> <xsl:value-of disable-output-escaping="yes" select="currency"/>
</span>
</span>
</xsl:if>
</span>
</div>
<div class="clear"></div>
</div>
<!-- Перевод строки после каждого 3-го элемента -->
<xsl:if test="((position() - 3) mod 3 = 0) and position() != last()">
<xsl:text disable-output-escaping="yes">
</div>
<div class="wrapper">
</xsl:text>
</xsl:if>
</xsl:template>
<!-- Склонение после числительных -->
<xsl:template name="declension">
<xsl:param name="number" select="number"/>
<!-- Именительный падеж -->
<xsl:param name="nominative" select="nominative"/>
<!-- Родительный падеж, единственное число -->
<xsl:param name="genitive_singular" select="genitive_singular"/>
<!-- Родительный падеж, множественное число -->
<xsl:param name="genitive_plural" select="genitive_plural"/>
<xsl:variable name="last_digit">
<xsl:value-of select="$number mod 10"/>
</xsl:variable>
<xsl:variable name="last_two_digits">
<xsl:value-of select="$number mod 100"/>
</xsl:variable>
<xsl:choose>
<xsl:when test="$last_digit = 1 and $last_two_digits != 11">
<xsl:value-of select="$nominative"/>
</xsl:when>
<xsl:when test="$last_digit = 2 and $last_two_digits != 12 or $last_digit = 3 and $last_two_digits != 13 or $last_digit = 4 and $last_two_digits != 14">
<xsl:value-of select="$genitive_singular"/>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="$genitive_plural"/>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
</xsl:stylesheet>
Шаблон XSL "Поиск" с показом карточек товаров
XSL
Экспорт прайс-листа в Excel
Для автоматической генерации прайс-листа в формате Excel необходимо загрузить PHPExcel и распаковать его в корневую директорию.
Обновите код настроек ТДС "Прайс" на следующий:
<?php
$oShop = Core_Entity::factory('Shop', Core_Array::get(Core_Page::instance()->libParams, 'shopId'));
$Shop_Controller_Show = new Shop_Controller_Show($oShop);
$path = Core_Page::instance()->structure->getPath();
$Shop_Controller_Show
//->pattern(rawurldecode($path) . '({path})(page-{page}/)')
->pattern(rawurldecode($path) . '({path})({xls})(page-{page}/)')
->patternExpressions(array(
'xls' => 'xls\/'
))
->addEntity(
Core::factory('Core_Xml_Entity')
->name('path')
->value($path)
)
->limit(500)
->parseUrl();
// Генерация Excel прайса
class HostCMS_Excel extends Core_Servant_Properties
{
/**
* Allowed object properties
* @var array
*/
protected $_allowedProperties = array(
'title',
'filename',
);
/**
* excelObject
* @var object
*/
protected $_excelObject = NULL;
/**
* excelSheetObject
* @var object
*/
protected $_excelSheetObject = NULL;
/**
* excelWriterObject
* @var object
*/
protected $_excelWriterObject = NULL;
/**
* Shop_Model
* @var object
*/
protected $_shop = NULL;
protected $_cell = 2;
/**
* Constructor.
*/
public function __construct($objPHPExcel, Shop_Model $oShop)
{
parent::__construct();
$this->_excelObject = $objPHPExcel;
$this->_shop = $oShop;
$this->title = 'price';
$this->filename = 'file';
// set default font
$this->_excelObject->getDefaultStyle()->getFont()->setName('Calibri');
// set default font size
$this->_excelObject->getDefaultStyle()->getFont()->setSize(10);
// writer already created the first sheet for us, let's get it
$this->_excelSheetObject = $this->_excelObject->getActiveSheet();
// create the writer
$this->_excelWriterObject = PHPExcel_IOFactory::createWriter($this->_excelObject, "Excel5");
// autosize the columns
$this->_excelSheetObject->getColumnDimension('A')->setAutoSize(TRUE);
$this->_excelSheetObject->getColumnDimension('B')->setAutoSize(TRUE);
$this->_excelSheetObject->getColumnDimension('C')->setAutoSize(TRUE);
}
/**
* File output.
*/
public function output()
{
// rename the sheet
$this->_excelSheetObject->setTitle($this->title);
// write header
$this->header($this->_excelSheetObject);
$aShop_Groups = $this->fillShopGroup($this->_shop->id, 0);
foreach ($aShop_Groups as $iShopGroupId => $sShopGroupName)
{
$this->_excelSheetObject->getStyle('A' . $this->_cell)->getFont()->setBold(TRUE);
$this->_excelSheetObject->getCell('A' . $this->_cell)->setValue($sShopGroupName);
$this->_cell++;
$this->items(intval($iShopGroupId));
}
// Setting the header type
header('Content-Type: application/vnd.openxmlformats-officedocument.spreadsheetml.sheet');
header('Content-Disposition: attachment;filename="' . $this->filename . '.xls"');
header('Cache-Control: max-age=0');
$this->_excelWriterObject->save('php://output');
}
/**
* Create header row.
*/
public function header($oSheet)
{
// let's bold and size the header font and write the header
// as you can see, we can specify a range of cells, like here: cells from A1 to A4
$oSheet->getStyle('A1:C1')->getFont()->setBold(TRUE)->setSize(12);
$oSheet->getCell('A1')->setValue('Наименование');
$oSheet->getCell('B1')->setValue('Артикул');
$oSheet->getCell('C1')->setValue('Цена');
return $oSheet;
}
/**
* Create items row.
*/
public function items($iShopGroupId)
{
$offset = 0;
$limit = 100;
$sCurrency = $this->_shop->Shop_Currency->name;
$oShop_Group = $this->_shop->Shop_Groups->getById($iShopGroupId);
$Shop_Item_Controller = new Shop_Item_Controller();
if (Core::moduleIsActive('siteuser'))
{
$oSiteuser = Core_Entity::factory('Siteuser')->getCurrent();
if ($oSiteuser)
{
$Shop_Item_Controller->siteuser($oSiteuser);
}
}
if (!is_null($oShop_Group->id))
{
do {
$oShop_Items = $oShop_Group->Shop_Items;
$oShop_Items->queryBuilder()
->where('shop_items.active', '=', 1)
->offset($offset)
->limit($limit);
$aShop_Items = $oShop_Items->findAll(FALSE);
foreach ($aShop_Items as $oShop_Item)
{
// Shortcut
$iShortcut = $oShop_Item->shortcut_id;
if ($iShortcut)
{
$oShop_Item = $oShop_Item->Shop_Item;
}
$aPrice = $Shop_Item_Controller->getPrices($oShop_Item);
$price = Shop_Controller::instance()->getCurrencyCoefficientInShopCurrency(
$oShop_Item->Shop_Currency,
$oShop_Item->Shop->Shop_Currency) * $aPrice['price_discount'];
$sPrice = $price . ' ' . $sCurrency;
$this->_excelSheetObject->getCell('A' . $this->_cell)->setValue($oShop_Item->name);
$this->_excelSheetObject->getCell('B' . $this->_cell)->setValue($oShop_Item->marking);
$this->_excelSheetObject->getCell('C' . $this->_cell)->setValue($sPrice);
$this->_cell++;
}
$offset += $limit;
}
while (count($aShop_Items));
}
return $this;
}
/**
* Shop groups tree
* @var array
*/
protected $_aGroupTree = array();
/**
* Build visual representation of group tree
* @param int $iShopId shop ID
* @param int $iShopGroupParentId parent ID
* @param int $aExclude exclude group ID
* @param int $iLevel current nesting level
* @return array
*/
public function fillShopGroup($iShopId, $iShopGroupParentId = 0, $aExclude = array(), $iLevel = 0)
{
$iShopId = intval($iShopId);
$iShopGroupParentId = intval($iShopGroupParentId);
$iLevel = intval($iLevel);
if ($iLevel == 0)
{
$aTmp = Core_QueryBuilder::select('id', 'parent_id', 'name')
->from('shop_groups')
->where('shop_id', '=', $iShopId)
->where('deleted', '=', 0)
->where('active', '=', 1)
->orderBy('sorting')
->orderBy('name')
->execute()->asAssoc()->result();
foreach ($aTmp as $aGroup)
{
$this->_aGroupTree[$aGroup['parent_id']][] = $aGroup;
}
}
$aReturn = array();
if (isset($this->_aGroupTree[$iShopGroupParentId]))
{
$countExclude = count($aExclude);
foreach ($this->_aGroupTree[$iShopGroupParentId] as $childrenGroup)
{
if ($countExclude == 0 || !in_array($childrenGroup['id'], $aExclude))
{
$aReturn[$childrenGroup['id']] = $childrenGroup['name'];
$aReturn += $this->fillShopGroup($iShopId, $childrenGroup['id'], $aExclude, $iLevel + 1);
}
}
}
$iLevel == 0 && $this->_aGroupTree = array();
return $aReturn;
}
}
if (!empty($Shop_Controller_Show->patternParams['xls']))
{
require_once(CMS_FOLDER . 'PHPExcel/PHPExcel.php');
// create new PHPExcel object
$objPHPExcel = new PHPExcel();
$HostCMS_Excel = new HostCMS_Excel($objPHPExcel, $oShop);
$HostCMS_Excel
->title('Прайс ' . $oShop->name)
->filename('price')
->output();
exit();
}
// /Excel
Core_Page::instance()->object = $Shop_Controller_Show;
Обновите код ТДС "Прайс" на следующий:
<?php
$Shop_Controller_Show = Core_Page::instance()->object;
$Shop_Controller_Show
->shopItems()
->queryBuilder()
->clearOrderBy()
->leftJoin('shop_groups', 'shop_groups.id', '=', 'shop_items.shop_group_id')
->where('shop_items.active', '=', 1)
->open()
->where('shop_groups.active', '=', 1)
->setOr()
->where('shop_groups.active', 'IS', NULL)
->where('shop_items.modification_id', '=', 0)
->close()
->clearOrderBy()
->orderBy('shop_items.shop_group_id')
->orderBy('shop_items.name');
$Shop_Controller_Show
->shopGroups()
->queryBuilder()
->where('shop_groups.active', '=', 1)
->clearOrderBy()
->orderBy('shop_groups.id');
$xslName = Core_Array::get(Core_Page::instance()->libParams, 'xsl');
$Shop_Controller_Show
->xsl(
Core_Entity::factory('Xsl')->getByName($xslName)
)
->groupsMode('all')
->itemsProperties(TRUE)
->group(FALSE)
->show();
Прайс-лист будет доступен по адресу http://ваш_сайт/shop/price/xls/

Элемент <xsl:sort> - сортировка
Синтаксис
XSLT 1.0
<xsl:sort
select = "string-expression"
lang = "nmtoken"
data-type = "text | number | qname-but-not-ncname"
order = "ascending | descending"
case-order = "upper-first | lower-first" />
<xsl:apply-templates select="informationsystem_item">
<xsl:sort
select = "sorting"
data-type = "number"
order = "ascending"
/>
</xsl:apply-templates>
Атрибуты
-
select — обязательный атрибут, значением которого является выражение, называемое также ключевым выражением. Это выражение вычисляется для каждого узла обрабатываемого множества, преобразуется в строку и затем используется как значение ключа при сортировке. По умолчанию значением этого атрибута является ".", что означает, что в качестве значения ключа для каждого узла используется его строковое значение.
-
order — необязательный атрибут, определяет порядок, в котором узлы должны сортироваться по своим ключам. Этот атрибут может принимать только два значения — "ascending", указывающее на восходящий порядок сортировки, и "descending", указывающее на нисходящий порядок. Значением по умолчанию является "ascending", то есть восходящий порядок.
-
lang — необязательный атрибут, определяет язык ключей сортировки. Дело в том, что в разных языках символы алфавита могут иметь различный порядок, что, соответственно, должно учитываться при сортировке. Атрибут lang в XSLT может иметь те же самые значения, что и атрибут xml:lang (например: "en", "en-us", "ru" и т. д.). Если значение этого атрибута не определено, процессор может либо определять язык исходя из параметров системы, либо сортировать строки исходя из порядка кодов символов Unicode.
-
data-type — необязательный атрибут, определяет тип данных, который несут строковые значения ключей.
-
"text" — ключи должны быть отсортированы в лексикографическом порядке исходя из языка, определенного атрибутом lang или параметрами системы. Это значение используется по умолчанию;
-
"number" — ключи должны сравниваться в численном виде. Если строковое значение ключа не является числом, оно будет преобразовано к не-числу (NaN), и, поскольку нечисловые значения неупорядочены, соответствующий узел может появиться в отсортированном множестве где угодно;
-
"имя" — в целях расширяемости XSLT также позволяет указывать в качестве типа данных произвольное имя. В этом случае реализация сортировки полностью зависит от процессора.
-
case-order — необязательный атрибут, указывает на порядок сортировки символов разных регистров. Значениями этого атрибута могут быть "upper-first", что означает, что заглавные символы должны идти первыми, или "lower-first", что означает, что первыми должны быть строчные символы. К примеру, строки "ночь", "Улица", "фонарь", "Аптека", "НОЧЬ", "Фонарь" при использовании case-order="upper-first" будут иметь порядок "Аптека", "НОЧЬ", "ночь", "Фонарь", "фонарь", "улица". При использовании case-order="lower-first" те же строки будут идти в порядке "Аптека", "ночь", "НОЧЬ", "фонарь", "Фонарь", "улица". Значение case-order по умолчанию зависит от процессора и языка сортировки. В большинстве случаев заглавные буквы идут первыми.
XSLT 2.0 и XSLT 3.0
<xsl:sort
select? = expression
lang? = { nmtoken }
order? = { "ascending" | "descending" }
collation? = { uri }
stable? = { "yes" | "no" }
case-order? = { "upper-first" | "lower-first" }
data-type? = { "text" | "number" | qname-but-not-ncname }>
<!-- Content: sequence-constructor -->
</xsl:sort>
Описание и примеры
Пример
<list>
<person>
<name>William</name>
<surname>Gibson</surname>
</person>
<person>
<name>William</name>
<surname>Blake</surname>
</person>
<person>
<name>John</name>
<surname>Fowles</surname>
</person>
</list>
<xsl:template match="list">
<xsl:copy>
<xsl:for-each select="person">
<xsl:sort select="name" order="descending"/>
<xsl:sort select="surname"/>
<xsl:copy-of select="."/>
</xsl:for-each>
</xsl:copy>
</xsl:template>
<list>
<person>
<name>William</name>
<surname>Blake</surname>
</person>
<person>
<name>William</name>
<surname>Gibson</surname>
</person>
<person>
<name>John</name>
<surname>Fowles</surname>
</person>
</list>
