Информационный блок в карточке товара

Добавляем в карточку товара блок с призывом задать вопрос

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 . ФормаЗаявкиВМодальномОкне

<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE xsl:stylesheet SYSTEM "lang://351">
<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="/">
<xsl:apply-templates select="/form" />
</xsl:template>
<xsl:template match="/form">
<xsl:choose>
<xsl:when test="success/node() and success = 1">
<!--div id="fade" style="display: block;"></div-->
<div class="modal fade form-success-result" id="modalSuccess" tabindex="-1" role="dialog">
<div class="modal-dialog  modal-dialog-centered">
<div class="modal-content p-5">
<div class="modal-header text-center">
<!--div class="modal-title w-100 fs-4 fw-bold">&labelModalTitle1;</div-->
<button class="btn-close" type="button" data-bs-dismiss="modal"></button>
</div>
<div class="modal-body">
<xsl:value-of disable-output-escaping="yes" select="success_text" />
</div>
</div>
</div>
</div>
<script>
let modalSuccess = new bootstrap.Modal(document.getElementById('modalSuccess'));
modalSuccess.show();
</script>
</xsl:when>
<!-- Выводим ошибку (error), если она была передана через внешний параметр -->
<xsl:when test="error != ''">
<div class="modal fade form-success-result" id="modalError" tabindex="-1" role="dialog">
<div class="modal-dialog  modal-dialog-centered">
<div class="modal-content p-5">
<div class="modal-header text-center">
<div class="modal-title w-100 fs-3 fw-bold">ОШИБКА!</div>
<button class=" " type="button" data-bs-dismiss="modal"></button>
</div>
<div class="modal-body"><b><xsl:value-of disable-output-escaping="yes" select="error" /></b></div>
</div>
</div>
</div>
<script>
let modalError = new bootstrap.Modal(document.getElementById('modalError'));
modalError.show();
</script>
</xsl:when>
<xsl:when test="errorId/node()">
<div class="modal fade form-success-result" id="modalError" tabindex="-1" role="dialog">
<div class="modal-dialog  modal-dialog-centered">
<div class="modal-content p-5">
<div class="modal-header text-center">
<div class="modal-title w-100 fs-3 fw-bold">&labelERROR;</div>
<button class="btn-close" type="button" data-bs-dismiss="modal"></button>
</div>
<div class="modal-body">
<xsl:choose>
<xsl:when test="errorId = 0">
&labelTextErrorId0;
</xsl:when>
<xsl:when test="errorId = 1">
&labelTextErrorId1;
</xsl:when>
<xsl:when test="errorId = 2">
&labelTextErrorId2;
</xsl:when>
</xsl:choose>
</div>
</div>
</div>
</div>
<script>
let modalError = new bootstrap.Modal(document.getElementById('modalError'));
modalError.show();
</script>
</xsl:when>
<xsl:otherwise>
 <div class="modal fade" id="questionModal" tabindex="-1" aria-labelledby="questionModalLabel_{@id}" aria-hidden="true">
<div class="modal-dialog  modal-dialog-centered modal-dialog-scrollable">
<div class="modal-content">
<div class="modal-header justify-content-center">
<div class="h2 m-0 modal-title" id="questionModalLabel_{@id}"><xsl:value-of disable-output-escaping="yes" select="name" /></div>
<button class="btn-close" type="button" data-bs-dismiss="modal"></button>
</div>
<div class="modal-body">
<xsl:if test="description !=''">
<xsl:value-of disable-output-escaping="yes" select="description" />
</xsl:if>
<div id="add-text" class="text-center"> </div>
<!-- Параметр action формы должен быть "./", если обработчик на этой же странице, либо "./form/", если обработчик на другой странице, например ./form/ -->
<form name="form{@id}" id="form{@id}" class="validate" action="./" method="post" enctype="multipart/form-data" >
<!-- Вывод разделов формы 0-го уровня -->
<xsl:apply-templates select="form_field_dir" />
<!-- Вывод списка полей формы 0-го уровня -->
<xsl:apply-templates select="form_field" />
<!-- Код подтверждения -->
<xsl:if test="captcha_id != 0">
<div class="form-group mb-3">
<div class="row">
<div class="col-6 caption">
<input type="hidden" name="captcha_id" value="{/form/captcha_id}"/>
<input type="text" name="captcha" size="15" class="form-control required" minlength="4" title="Введите число, которое указано на картинке."/>
<div class="padding-5">&labelCheckNumber1;<sup><font color="red">*</font></sup></div>
</div>
<div class="col-6 field">
<img id="formCaptcha_{/form/@id}_{/form/captcha_id}" src="/captcha.php?id={captcha_id}&amp;height=30&amp;width=100" class="captcha" name="captcha" />
<div class="captcha">
<img src="/images/refresh.png" /> <span class="small" onclick="$('#formCaptcha_{/form/@id}_{/form/captcha_id}').updateCaptcha('{/form/captcha_id}', 30); return false" style="cursor:pointer">&labelCheckNumber2;</span>
</div>
</div>
</div>
</div>
</xsl:if>
<!--div class="margin-bottom-10">
<div class="g-recaptcha" data-sitekey="6LfemXMiAAAAAPtn9tHaYj5z-0yKJq4Tmi3Ph1Cw"></div>
</div-->
<xsl:if test="csrf_token/node() and csrf_token != ''">
<input type="hidden" name="{csrf_field}" value="{csrf_token}" />
</xsl:if>
<div class="form-group">
<input type="hidden" name="{button_name}" value="submit"/>
<button id="submit_{@id}" value="submit" name="{button_name}" type="submit" class="btn btn-black mt-4 w-100"><xsl:value-of select="button_value" /></button>
</div>
</form>
<div class="mt-4">
<div class="form-check">
<input id="checkbox{@id}" class="form-check-input" type="checkbox" name="checkbox" checked="checked" onchange="document.getElementById('submit_{@id}').disabled = !this.checked;"/>
<label for="checkbox{@id}" class="form-check-label small" style="text-align:justify">Я соглашаюсь на обработку своих персональных данных в соответствии с <a href="/private" class="link-border"> Политикой конфиденциальности</a></label>
</div>
</div>
</div>
</div>
</div>
</div>
<SCRIPT>
<xsl:comment>
<xsl:text disable-output-escaping="yes">
    <![CDATA[
    $(function() {
    $("#fileUpload").on('change', function () {
 
     //Get count of selected files
     var countFiles = $(this)[0].files.length;
     var imgPath = $(this)[0].value;
     var extn = imgPath.substring(imgPath.lastIndexOf('.') + 1).toLowerCase();
     var image_holder = $("#image-holder");
     image_holder.empty();
 
     if (extn == "png" || extn == "jpg" || extn == "jpeg" || extn == "webp") {
         if (typeof (FileReader) != "undefined") {
 
             //loop for each file selected for uploaded.
             for (var i = 0; i < countFiles; i++) {
 
                 var reader = new FileReader();
                 reader.onload = function (e) {
                     $("<img />", {
                         "src": e.target.result,
                             "class": "thumb-image"
                     }).appendTo(image_holder);
                 }
 
                 image_holder.show();
                 reader.readAsDataURL($(this)[0].files[i]);
             }
 
         } else {
             alert("Ваш брузер не поддерживает FileReader!");
         }
     } else {
         alert("Выберите файл в формате JPG, JPEG, PNG или WEBP!");
     }
    });
    });
]]>
</xsl:text>
</xsl:comment>
</SCRIPT>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
<xsl:template match="form_field_dir">
<!--fieldset class="maillist_fieldset"-->
<!--legend><xsl:value-of select="name" /></legend-->
<!-- Вывод списка полей формы -->
<xsl:apply-templates select="form_field" />
<!-- Вывод разделов формы -->
<xsl:apply-templates select="form_field_dir" />
<!--/fieldset-->
</xsl:template>
<xsl:template match="form_field">
<!-- Не скрытое поле и не надпись -->
<xsl:if test="type != 7 and type != 8">
<div class="form-group mb-3">
<xsl:if test="type = 2">
<xsl:attribute name="class">form-group mb-2 me-4</xsl:attribute>
</xsl:if>
<xsl:variable name="caption">
<xsl:choose>
<xsl:when test="obligatory = 1">
<xsl:value-of select="caption" />*
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="caption" />
</xsl:otherwise>
</xsl:choose>
</xsl:variable>
<xsl:choose>
<!-- Радиокнопки -->
<xsl:when test="type = 3 or type = 9">
<xsl:apply-templates select="list/list_item" />
</xsl:when>
<!-- Checkbox -->
<xsl:when test="type = 4">
<div class="pretty p-default p-pulse">
<input type="checkbox" name="{name}">
<xsl:if test="checked = 1 or value = 1">
<xsl:attribute name="checked">checked</xsl:attribute>
</xsl:if>
</input>
<div class="state p-danger-o">
<label><xsl:value-of select="value" /></label>
</div>
</div>
</xsl:when>
<!-- Textarea -->
<xsl:when test="type = 5">
<textarea class="form-control" name="{name}" cols="{cols}" rows="{rows}" placeholder="{$caption}">
<xsl:if test="obligatory = 1">
<xsl:attribute name="class">form-control required</xsl:attribute>
</xsl:if>
<xsl:value-of select="value" />
</textarea>
</xsl:when>
<!-- Список -->
<xsl:when test="type = 6">
<select name="{name}" class="wide">
<xsl:if test="obligatory = 1">
<xsl:attribute name="class">wide required</xsl:attribute>
<xsl:attribute name="title"><xsl:value-of select="caption" /></xsl:attribute>
</xsl:if>
<option value="">...</option>
<xsl:apply-templates select="list/list_item" />
</select>
</xsl:when>
<!-- Текстовые поля -->
<xsl:otherwise>
<xsl:if test="type = 2">
<label for="fileUpload" class="download-file">
<i class="svg_icon">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512" width="21px" height="21px" ><path style="fill:#797979" d="M464 64H48C21.49 64 0 85.49 0 112v288c0 26.51 21.49 48 48 48h416c26.51 0 48-21.49 48-48V112c0-26.51-21.49-48-48-48zm16 336c0 8.822-7.178 16-16 16H48c-8.822 0-16-7.178-16-16V112c0-8.822 7.178-16 16-16h416c8.822 0 16 7.178 16 16v288zM112 232c30.928 0 56-25.072 56-56s-25.072-56-56-56-56 25.072-56 56 25.072 56 56 56zm0-80c13.234 0 24 10.766 24 24s-10.766 24-24 24-24-10.766-24-24 10.766-24 24-24zm207.029 23.029L224 270.059l-31.029-31.029c-9.373-9.373-24.569-9.373-33.941 0l-88 88A23.998 23.998 0 0 0 64 344v28c0 6.627 5.373 12 12 12h360c6.627 0 12-5.373 12-12v-92c0-6.365-2.529-12.47-7.029-16.971l-88-88c-9.373-9.372-24.569-9.372-33.942 0zM416 352H96v-4.686l80-80 48 48 112-112 80 80V352z"/></svg>
</i>
<span class="download-file-text ps-2">Выберите сразу несколько фото</span>
</label>
</xsl:if>
<input class="form-control" type="text" name="{name}" value="{value}" size="{size}" placeholder="{$caption}">
<xsl:choose>
<!-- Поле для ввода пароля -->
<xsl:when test="type = 1">
<xsl:attribute name="type">password</xsl:attribute>
</xsl:when>
<!-- Поле загрузки файла -->
<xsl:when test="type = 2">
<xsl:attribute name="type">file</xsl:attribute>
<xsl:attribute name="multiple">true</xsl:attribute>
<xsl:attribute name="class">photo</xsl:attribute>
<xsl:attribute name="name">files[]</xsl:attribute>
<xsl:attribute name="id">fileUpload</xsl:attribute>
<xsl:attribute name="accept">image/jpg,image/jpeg,image/png,image/webp</xsl:attribute>
<div id="image-holder" class="d-flex flex-wrap"></div>
</xsl:when>
<!-- HTML5: Дата -->
<xsl:when test="type = 10">
<xsl:attribute name="type">date</xsl:attribute>
</xsl:when>
<!-- HTML5: Цвет -->
<xsl:when test="type = 11">
<xsl:attribute name="type">color</xsl:attribute>
</xsl:when>
<!-- HTML5: Месяц -->
<xsl:when test="type = 12">
<xsl:attribute name="type">month</xsl:attribute>
</xsl:when>
<!-- HTML5: Неделя -->
<xsl:when test="type = 13">
<xsl:attribute name="type">week</xsl:attribute>
</xsl:when>
<!-- HTML5: Время -->
<xsl:when test="type = 14">
<xsl:attribute name="type">time</xsl:attribute>
</xsl:when>
<!-- HTML5: Дата-Время -->
<xsl:when test="type = 15">
<xsl:attribute name="type">datetime</xsl:attribute>
</xsl:when>
<!-- HTML5: E-mail -->
<xsl:when test="type = 16">
<xsl:attribute name="type">email</xsl:attribute>
</xsl:when>
<!-- HTML5: Поиск -->
<xsl:when test="type = 17">
<xsl:attribute name="type">search</xsl:attribute>
</xsl:when>
<!-- HTML5: Телефон -->
<xsl:when test="type = 18">
<xsl:attribute name="type">tel</xsl:attribute>
</xsl:when>
<!-- HTML5: URL -->
<xsl:when test="type = 19">
<xsl:attribute name="type">url</xsl:attribute>
</xsl:when>
<!-- Текстовое поле -->
<xsl:otherwise>
<xsl:attribute name="type">text</xsl:attribute>
</xsl:otherwise>
</xsl:choose>
<xsl:if test="obligatory = 1">
<xsl:attribute name="class">form-control required</xsl:attribute>
</xsl:if>
<!--xsl:if test="@id = 15">
<xsl:attribute name="disabled">disabled</xsl:attribute>
</xsl:if-->
</input>
</xsl:otherwise>
</xsl:choose>
</div>
</xsl:if>
<!-- скрытое поле -->
<xsl:if test="type = 7">
<input type="hidden" name="{name}" value="{value}" />
</xsl:if>
</xsl:template>
</xsl:stylesheet>
//
//
//
Код DTD для языка "ru"

<!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;   
}

.btn.btn-transparent {

background: transparent;

border: 1px solid #212529;

color: #212529;

/******************************/

Калькулятор в карточке товара для делимых продуктов

Этот калькулятор подойдёт для сайтов, где продается товар мерный, цена которого зависит от выбранной площади и толщины материала.
Для начала создаём Информационную систему, которую назовем, к примеру "Материалы для калькулятора". Сразу же создадим Допсвойство "Кратность" (поясню ниже). Далее создадим инфоэлементы для разных толщин материала. Например, "Материал толщина 1.8 мм", "Материал, толщина 2.1мм" и т.д. В свойстве "Кратность" нужно указать на какую величину увеличивается стоимость товара за единицу площади. Т.е. к примеру, для "Материал, толщина 1мм" стоимость квадратного метра 100р., а для "Материал толщина 1.8 мм" - 200 р. Тогда кратность будет равна "2". Эту кратность будем использовать в калькуляторе в карточке товара. Чтобы передать данные из созданной нами Инфосистемы в карточку товара, добавим нижеприведённый код в ТДС Интернет-магазина:
// Материалы в карточке товара
ob_start();
if (Core::moduleIsActive('informationsystem'))
{
	$Informationsystem_Controller_Show = new Informationsystem_Controller_Show(Core_Entity::factory('Informationsystem', 32));

	$Informationsystem_Controller_Show->xsl(Core_Entity::factory('Xsl')->getByName('МатериалыВКарточкеТовараСайт2'))
		->groupsMode('none')
		->itemsForbiddenTags(array('text', 'description'))
		->cache(FALSE)
		->group(FALSE)
		->itemsPropertiesList(FALSE)
		//->itemsProperties(array(129))
		->itemsProperties(TRUE)
		->limit(20)
		//->votes(TRUE)
		->show();
}
$Shop_Controller_Show->addEntity(
	Core::factory('Core_Xml_Entity')
		->name('kratnost')->value(ob_get_clean())
);
//

В итоге, получим в XML данные о Материалах.

В XSL карточки товара добавляем код нашего калькулятора, а в макет код jquery, который будет у нас отслеживать изменения в полях и селекторе и производить расчёт. 

XSL

<div class="calculator mt-4">
<!-- калькулятор площади -->
<form id="form" >
<input type="hidden" name="item-price" value="{price}"/>
<div class="row">
<div class="col-12 col-sm-6 form-group">
<label>Высота сетки, см: </label>
<div class="calc-input-block">
<input id="height" type="number" value="100" step="1" name="height"/>
<span class="qty-wrapper">
<span class="qty-inner">
<span class="qty-up" data-src="#height" title="+">+</span>
<span class="qty-down" data-src="#height" title="-">-</span>
</span>
</span>
</div>
</div>
<div class="col-12 col-sm-6 form-group">
<label>Длина сетки, см: </label>
<div class="calc-input-block">
<input id="width" type="number" value="100" step="1" name="width" />
<span class="qty-wrapper">
<span class="qty-inner">
<span class="qty-up" data-src="#width" title="+">+</span>
<span class="qty-down" data-src="#width" title="-">-</span>
</span>
</span>
</div>
</div>
</div>
<xsl:if test="/shop/kratnost">
<div class="form-group">
<xsl:value-of disable-output-escaping="yes" select="/shop/kratnost "/>
</div>
</xsl:if>
<!--Цена-->
<div class="item-price">
<div> Цена: </div>
<span id="summ"><xsl:value-of select="format-number(price, '### ##0', 'my')"/></span><xsl:text> </xsl:text><span><xsl:value-of select="currency"/></span>
</div>
<input id="quantity" type="hidden" value="1" name="quantity" />
</form>
<!--div class="margin-top-10 margin-bottom-10">
<div class="small"><xsl:value-of disable-output-escaping="yes" select="/shop/sales "/></div>
</div-->
<div class="list-btn mt-3">
<button id="fast_order" class="btn btn-secondary btn-lg in-cart" data-item-id="{@id}" onclick="return $.oneStepCheckout('{/shop/url}cart/', $(this).data('item-id'), $('#quantity').val())" type="button" title="Заказать" data-height="100" data-width="100" data-materials="Фотосетка 1,8 мм" data-toggle="modal" data-target="#oneStepCheckout{@id}">
<svg viewBox="0 0 576 512" width="16px" height="16px"><path class="white" d="M564.907 196.35L388.91 12.366C364.216-13.45 320 3.746 320 40.016v88.154C154.548 130.155 0 160.103 0 331.19c0 94.98 55.84 150.231 89.13 174.571 24.233 17.722 58.021-4.992 49.68-34.51C100.937 336.887 165.575 321.972 320 320.16V408c0 36.239 44.19 53.494 68.91 27.65l175.998-184c14.79-15.47 14.79-39.83-.001-55.3zm-23.127 33.18l-176 184c-4.933 5.16-13.78 1.73-13.78-5.53V288c-171.396 0-295.313 9.707-243.98 191.7C72 453.36 32 405.59 32 331.19 32 171.18 194.886 160 352 160V40c0-7.262 8.851-10.69 13.78-5.53l176 184a7.978 7.978 0 0 1 0 11.06z"/></svg>
<span>Заказать</span></button>
</div>
</div>

JavaScript / jQuery

// Cart quantity
$(".qty-inner .qty-up").on("click", function() {
var jInput = $($(this).data('src')),
oldValue = jInput.val();
var jInputName = $(jInput).attr('name');
console.log(jInputName);
if (jInputName =='height' || jInputName =='width') {
    if (oldValue < 100) {
      jInput.val(100);  
    } 
    else if (jInputName =='height' && oldValue < 300 && oldValue > 99) {
         jInput.val(parseInt(oldValue) + 1);
    }
    else if (jInputName =='width' && oldValue > 99) {
         jInput.val(parseInt(oldValue) + 1);
    }
}
else if(jInputName =='height2' || jInputName =='width2') {
    if (jInputName =='height2' && oldValue < 158) {
        jInput.val(158);
     }
    else if (jInputName =='width2' && oldValue < 100) {
        jInput.val(100);
     }
    else if (jInputName =='width2' && oldValue > 99) {
         jInput.val(parseInt(oldValue) + 100);
    }
}
var price = $('input[name=item-price]').val() * 1;
var height = $('input[name=height]').val() * 1; 
var width = $('input[name=width]').val() * 1; 
var height2 = $('input[name=height2]').val() * 1; 
var width2 = $('input[name=width2]').val() * 1; 
var material = $('#materials').val(); 
var materialName = $('#materials option:selected').text(); 
var result = ((height * width * material)/10000).toFixed(2); 
var result2 = ((width2 * material)/100).toFixed(2);
var summ = (result * price).toFixed(0);
var summ2 = (result2 * price).toFixed(0);
$('#summ').html(summ); // записываем сумму
$('#summ2').html(summ2); // записываем сумму
        $('#quantity').val(result); // записываем количество
        $('#quantity2').val(result2); // записываем количество
        if (jInputName =='width2') {
                $('#fast_order').data('height', height2 ).data('width', width2 ).data('materials', materialName );
                $('#inCart').data('height', height2 ).data('width', width2 ).data('materials', materialName );
        }else{
                $('#fast_order').data('height', height ).data('width', width ).data('materials', materialName );
                $('#inCart').data('height', height ).data('width', width ).data('materials', materialName );
        }
});
$(".qty-inner .qty-down").on("click", function() {
var jInput = $($(this).data('src')),
oldValue = jInput.val();
var jInputName = $(jInput).attr('name');
if (jInputName =='width2') {
       if (oldValue > 199) {
       jInput.val(parseInt(oldValue) - 100);
  }
}
else if (oldValue < 299 && oldValue > 100) {
jInput.val(parseInt(oldValue) - 1);
}
var price = $('input[name=item-price]').val() * 1;
var height = $('input[name=height]').val() * 1; 
 var width = $('input[name=width]').val() * 1;
var material = $('#materials').val(); 
var materialName = $('#materials option:selected').text(); 
var result = ((height * width * material)/10000).toFixed(2); 
var summ = (result * price).toFixed(0);
$('#summ').html(summ); // записываем сумму
$('#quantity').val(result); // записываем количество
$('#fast_order').data('height', height ).data('width', width ).data('materials', materialName ); // Отправляем информацию о размерах в быстрый заказ
});
$('#height, #width').on("change keyup paste", function(){
var price = $('input[name=item-price]').val() * 1;
var height = $('input[name=height]').val() * 1; 
var width = $('input[name=width]').val() * 1; 
var material = $('#materials').val(); 
var materialName = $('#materials option:selected').text(); 
var result = ((height * width * material)/10000).toFixed(2); 
var summ = (result * price).toFixed(0);
$('#summ').html(summ); // записываем сумму
$('#quantity').val(result); // записываем количество
$('#fast_order').data('height', height ).data('width', width ).data('materials', materialName );
});
$("#form #materials").change(function(){
var price = $('input[name=item-price]').val() * 1;
var height = $('input[name=height]').val() * 1; 
var width = $('input[name=width]').val() * 1; 
var material = $(this).val(); 
var materialName = $('#materials option:selected').text(); 
var result = (((height * width) * material)/10000).toFixed(2); 
var summ = (result * price).toFixed(0);
$('#summ').html(summ); // записываем сумму
        $('#quantity').val(result); // записываем количество
        $('#fast_order').data('height', height ).data('width', width ).data('materials', materialName );
});

МИКРОРАЗМЕТКА В КАРТОЧКЕ ТОВАРА (для HostCMS)

Микроразметка в Хлебных крошках в XSL шаблоне "Карточка товара"
<!-- Путь к группе -->
     <div class="d-none d-sm-block breadcrumbs" xmlns:v="http://rdf.data-vocabulary.org/#">

            <xsl:if test="$group = 0">
                <span typeof="v:Breadcrumb">
                    <a title="{/shop/name}" href="{/shop/url}" hostcms:id="{/shop/@id}" hostcms:field="name" hostcms:entity="shop" property="v:title" rel="v:url">
                        <xsl:value-of disable-output-escaping="yes" select="/shop/name"/>
                    </a>
                </span>
            </xsl:if>

            <xsl:apply-templates select="/shop//shop_group[@id=$group]" mode="breadCrumbs"/>

            <!-- Если модификация, выводим в пути родительский товар -->
            <xsl:if test="shop_item/node()">
                <i class="fa fa-angle-right"></i>

                <span typeof="v:Breadcrumb">
                    <a title="{shop_item/name}" href="{shop_item/url}" property="v:title" rel="v:url">
                        <xsl:value-of disable-output-escaping="yes" select="shop_item/name"/>
                    </a>
                </span>
            </xsl:if>

            <i class="fa fa-angle-right"></i>

            <span typeof="v:Breadcrumb">
                <a href="{url}" hostcms:id="{@id}" hostcms:field="name" hostcms:entity="shop_item" property="v:title" rel="v:url"><xsl:value-of disable-output-escaping="yes" select="name"/></a>
            </span>
        </div>
<!-- Шаблон выводит рекурсивно ссылки на группы магазина -->
<xsl:template match="shop_group" mode="breadCrumbs">
    <xsl:param name="parent_id" select="parent_id"/>

    <!-- Получаем ID родительской группы и записываем в переменную $group -->
    <xsl:param name="group" select="/shop/shop_group"/>

    <xsl:apply-templates select="//shop_group[@id=$parent_id]" mode="breadCrumbs"/>

    <xsl:if test="parent_id=0">
        <span typeof="v:Breadcrumb">
            <a title="{/shop/name}" href="{/shop/url}" hostcms:id="{/shop/@id}" hostcms:field="name" hostcms:entity="shop" class="root" property="v:title" rel="v:url">
                <xsl:value-of select="/shop/name"/>
            </a>
        </span>
    </xsl:if>

    <i class="fa fa-angle-right"></i>

    <span typeof="v:Breadcrumb">
        <a title="{name}" href="{url}" hostcms:id="{@id}" hostcms:field="name" hostcms:entity="shop_group" property="v:title" rel="v:url">
            <xsl:value-of disable-output-escaping="yes" select="name"/>
        </a>
    </span>

</xsl:template>

Микроразметка карточки товара

<div itemscope="itemscope" itemtype="http://schema.org/Product">

                   <!-- Название товара -->
                   <h1><span itemprop="name"><xsl:value-of select="name"/></span></h1>


                    <!-- Изображение для товара, если есть -->
                    <xsl:if test="image_small != ''">
                        <div id="gallery" class="photo">
                            <a href="{dir}{image_large}" ><img src="{dir}{image_small}" alt="" itemprop="image"/></a>
                        </div>

                        <ul class="margin-top-10">
                        <li><a href="{dir}{image_large}"><img src="{dir}{image_small}" alt=""  height="100"/></a></li>
                            <xsl:for-each select="property_value[tag_name='xml_foto'][file !='']">
                            <li><a href="{../dir}{file}"><img src="{../dir}{file_small}" height="100" itemprop="image"/></a></li>
                            </xsl:for-each>
                        </ul>
                    </xsl:if>


                    <!-- Цена товара -->
                    <xsl:if test="price != 0">
                        <div class="price" itemprop="offers" itemscope="" itemtype="http://schema.org/Offer">
                        <span itemprop="price" content="{price}"><xsl:value-of select="format-number(price, '### ##0', 'my')"/></span><xsl:text> </xsl:text>
                            <span itemprop="priceCurrency" content="RUB"><xsl:value-of select="currency"/></span>

                            <!-- Если цена со скидкой - выводим ее -->
                            <xsl:if test="discount != 0">
                                <p class="item-old-price">
                                    <xsl:value-of select="format-number(price + discount, '### ##0', 'my')"/><xsl:text> </xsl:text><xsl:value-of select="currency" />
                                </p>
                            </xsl:if>
                        </div>
                    </xsl:if>


                    <!-- Описание товара -->
                    <xsl:if test="description != ''">
                        <div itemprop="description"><xsl:value-of disable-output-escaping="yes" select="description" /></div>
                    </xsl:if>

   </div>

<div itemscope itemtype="http://schema.org/Product">
            <img src="/img/img.jpg" itemprop="image">
            <div itemprop="name"><strong>товар</strong></div>
            <div itemprop="description">Какое-то описание</div>
            <div itemprop="offers" itemscope itemtype="http://schema.org/Offer"> 
            <span itemprop="price">25356</span> <span itemprop="priceCurrency">RUB</span>
            </div>
</div>

Плавающий блок с призывом добавить товар в Избранное (на 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;
  }
}