Skip to content

Product Prices

Use product_prices module to render price(s) of the currently visible product on a page. This module is available only within a product card.

Configuration parameters

showRegularPrice

int if set to 1 a regular price will be displayed

showSpecialOfferDuration

int if set to 1 an information about special offer duration will be displayed.

specialOfferDurationType

string if set to promotionsLastingMoreThan30Days the duration of the special offer will be displayed only after the promotion has lasted for more than 30 days. Otherwise it will be displayed for all promotions.

percentageDiscountValue

int if set to 1 an information about the special offer price in percentage value will be displayed.

Module source code

{% from "@macros/product_price.twig" import product_price %}

{% set globalPricesSettings = ObjectApi.getProductPricesSettings() %}
{% set shopUrls = ObjectApi.getShopUrls() %}
{% set product = ObjectApi.getProduct(product_id) %}

{% set productVariant = product %}

{% if product.variants.count == 1 %}
    {% set productVariant = product.variants[0] %}
{% endif %}

{% set price = productVariant.price %}

{% set priceInCurrency = productVariant.priceInProductCurrency %}

{% set showPercentageDiscountValue = productVariant.hasSpecialOffer and moduleConfig.percentageDiscountValue  %}

{% set specialOffer = productVariant.specialOffer %}

{% set showGrossNetTabs = globalPricesSettings.showGrossPrice and globalPricesSettings.showNetPrice %}

{% set showDifferentCurrency = productVariant.hasDifferentCurrency and productVariant.currency.id != currency_id  %}

{% if showDifferentCurrency %}
    {% if productVariant.lowestHistoricalPriceInLast30DaysInProductCurrency %}
        {% set lowestHistoricalPriceInLast30DaysInProductCurrencyPrice = productVariant.lowestHistoricalPriceInLast30DaysInProductCurrency.getPrice() %}
    {% endif %}

    {% if productVariant.hasUnitPriceCalculation and globalPricesSettings.showUnitPrice %}
        {% set unitPriceInCurrency = productVariant.hasSpecialOffer ? productVariant.specialOfferUnitPriceInProductCurrency : productVariant.unitPriceInProductCurrency %}
    {% endif %}
{% endif %}

{% if showPercentageDiscountValue %}
    {% set percentageDiscountValue = specialOffer.formatDiscount %}
{% endif %}

{% if productVariant.hasUnitPriceCalculation and globalPricesSettings.showUnitPrice %}
    {% set unitPrice = productVariant.hasSpecialOffer ? productVariant.specialOfferUnitPrice : productVariant.unitPrice %}
{% endif %}

{% if productVariant.lowestHistoricalPriceInLast30Days %}
    {% set lowestHistoricalPriceInLast30Days = productVariant.lowestHistoricalPriceInLast30Days.getPrice() %}
{% endif %}

{% if lowestHistoricalPriceInLast30Days %}
    {% set lowestHistoricalPricePercentage = (100 - price.grossValue * 100 / lowestHistoricalPriceInLast30Days.grossValue)|round() %}
    {% set isLowestHistoricalPriceHigherThanCurrent = lowestHistoricalPriceInLast30Days.grossValue > price.grossValue %}
{% endif %}

{% set daysFromPromotionStart = specialOffer.getDetails().startDate.timeDifference(ObjectApi.getNow()).days %}

{% set showSpecialOfferDurationForAllPromotions = moduleConfig.specialOfferDurationType == 'allPromotions' %}
{% set showSpecialOfferDurationForPromotionsLongerThan30Days = moduleConfig.specialOfferDurationType == 'promotionsLastingMoreThan30Days' and daysFromPromotionStart >= 30 %}

{% set showSpecialOfferDuration = moduleConfig.showSpecialOfferDuration and (showSpecialOfferDurationForAllPromotions or showSpecialOfferDurationForPromotionsLongerThan30Days) %}

{% set prices %}
    <product-price
            class="product-prices"
            product-id="{{ product.id }}"
            slot="logged-in">
        <div class="product-prices__header">
            {% if showDifferentCurrency %}
                <h-tabs class="tabs">
                    <h-tab
                            selected
                            class="tabs__tab"
                            panel-name="shop-current-currency-{{ product.id }}">
                        {{ price.currency }}
                    </h-tab>

                    <h-tab
                            class="tabs__tab"
                            panel-name="product-currency-{{ product.id }}">
                        {{ productVariant.currency.code }}
                    </h-tab>
                </h-tabs>
            {% endif %}

            {% if showGrossNetTabs %}
                <h-tabs class="tabs">
                    <h-tab
                            selected
                            class="tabs__tab"
                            panel-name="price-gross-{{ product.id }}">
                        {{ translate('with VAT', price.formatTax) }}
                    </h-tab>

                    <h-tab
                            class="tabs__tab"
                            panel-name="price-net-{{ product.id }}">
                        {{ translate('without VAT') }}
                    </h-tab>
                </h-tabs>
            {% endif %}
        </div>

        <h-tab-panel
                {% if globalPricesSettings.showNetPrice == false or showGrossNetTabs %}hidden{% endif %}
                name="price-net-{{ product.id }}"
                class="js__product-price-net"
        >
            {% if showDifferentCurrency %}
                <h-tab-panel
                        hidden
                        class="js__product-currency-price"
                        name="product-currency-{{ product.id }}">
                    {{ product_price({
                        priceValue: priceInCurrency.formatNet,
                        basePriceValue: productVariant.basePriceInProductCurrency.formatNet,
                        otherPriceValue: productVariant.otherPrice.isZero ? null : productVariant.otherPrice.formatNet,
                        percentageDiscountValue: percentageDiscountValue,
                        unitPrice: unitPriceInCurrency.formatNet,
                        unitName: productVariant.unitPriceCalculationUnit.name,
                        hasSpecialOffer: productVariant.hasSpecialOffer,
                        specialOffer: specialOffer,
                        lowestHistoricalPriceInLast30Days: lowestHistoricalPriceInLast30DaysInProductCurrencyPrice ? lowestHistoricalPriceInLast30DaysInProductCurrencyPrice.formatNet : null,
                        lowestHistoricalPricePercentage: lowestHistoricalPricePercentage ?: null,
                        isLowestHistoricalPriceHigherThanCurrent: isLowestHistoricalPriceHigherThanCurrent,
                        priceOutsideTheBundle: productVariant.bundle.originalItemsPrice.formatNet
                    }, {
                        showAdditionalTaxInfo: globalPricesSettings.showAdditionalTaxInfo,
                        showSpecialOfferDuration,
                        showLowestPriceIn30Days: globalPricesSettings.showLowestPriceIn30Days,
                        showPriceWithoutShippingCostInfo: globalPricesSettings.showAdditionalTaxInfo,
                        showRegularPrice: moduleConfig.showRegularPrice,
                        showPercentageDiscountValue: moduleConfig.percentageDiscountValue
                    }) }}
                </h-tab-panel>
            {% endif %}

            <h-tab-panel
                    class="js__product-price"
                    name="shop-current-currency-{{ product.id }}">
                {{ product_price({
                    priceValue: price.formatNet,
                    basePriceValue: productVariant.basePrice.formatNet,
                    otherPriceValue: productVariant.otherPrice.isZero ? null : productVariant.otherPrice.formatNet,
                    percentageDiscountValue: percentageDiscountValue,
                    unitPrice: unitPrice.formatNet,
                    unitName: productVariant.unitPriceCalculationUnit.name,
                    hasSpecialOffer: productVariant.hasSpecialOffer,
                    specialOffer: specialOffer,
                    lowestHistoricalPriceInLast30Days: lowestHistoricalPriceInLast30Days ? lowestHistoricalPriceInLast30Days.formatNet : null,
                    lowestHistoricalPricePercentage: lowestHistoricalPricePercentage ?: null,
                    isLowestHistoricalPriceHigherThanCurrent: isLowestHistoricalPriceHigherThanCurrent,
                    priceOutsideTheBundle: productVariant.bundle.originalItemsPrice.formatNet
                }, {
                    showAdditionalTaxInfo: globalPricesSettings.showAdditionalTaxInfo,
                    showSpecialOfferDuration,
                    showLowestPriceIn30Days: globalPricesSettings.showLowestPriceIn30Days,
                    showPriceWithoutShippingCostInfo: globalPricesSettings.showAdditionalTaxInfo,
                    showRegularPrice: moduleConfig.showRegularPrice,
                    showPercentageDiscountValue: moduleConfig.percentageDiscountValue
                }) }}
            </h-tab-panel>
        </h-tab-panel>

        <h-tab-panel
                {% if globalPricesSettings.showGrossPrice == false %}hidden{% endif %}
                name="price-gross-{{ product.id }}"
                class="js__product-price-gross"
        >
            {% if showDifferentCurrency %}
                <h-tab-panel
                        hidden
                        class="js__product-currency-price"
                        name="product-currency-{{ product.id }}">
                    {{ product_price({
                        priceValue: priceInCurrency.formatGross,
                        basePriceValue: productVariant.basePriceInProductCurrency.formatGross,
                        otherPriceValue: productVariant.otherPrice.isZero ? null : productVariant.otherPrice.formatGross,
                        percentageDiscountValue: percentageDiscountValue,
                        unitPrice: unitPriceInCurrency.formatGross,
                        unitName: productVariant.unitPriceCalculationUnit.name,
                        hasSpecialOffer: productVariant.hasSpecialOffer,
                        specialOffer: specialOffer,
                        priceFormatTax: price.formatTax,
                        lowestHistoricalPriceInLast30Days: lowestHistoricalPriceInLast30DaysInProductCurrencyPrice ? lowestHistoricalPriceInLast30DaysInProductCurrencyPrice.formatGross : null,
                        lowestHistoricalPricePercentage: lowestHistoricalPricePercentage ?: null,
                        isLowestHistoricalPriceHigherThanCurrent: isLowestHistoricalPriceHigherThanCurrent,
                        priceOutsideTheBundle: productVariant.bundle.originalItemsPrice.formatGross
                    }, {
                        showAdditionalTaxInfo: globalPricesSettings.showAdditionalTaxInfo,
                        showSpecialOfferDuration,
                        showLowestPriceIn30Days: globalPricesSettings.showLowestPriceIn30Days,
                        showPriceWithoutShippingCostInfo: globalPricesSettings.showAdditionalTaxInfo,
                        showRegularPrice: moduleConfig.showRegularPrice,
                        showPercentageDiscountValue: moduleConfig.percentageDiscountValue
                    }) }}
                </h-tab-panel>
            {% endif %}

            <h-tab-panel
                    class="js__product-price"
                    name="shop-current-currency-{{ product.id }}">
                {{ product_price({
                    priceValue: price.formatGross,
                    basePriceValue: productVariant.basePrice.formatGross,
                    otherPriceValue: productVariant.otherPrice.isZero ? null : productVariant.otherPrice.formatGross,
                    percentageDiscountValue: percentageDiscountValue,
                    unitPrice: unitPrice.formatGross,
                    unitName: productVariant.unitPriceCalculationUnit.name,
                    hasSpecialOffer: productVariant.hasSpecialOffer,
                    specialOffer: specialOffer,
                    priceFormatTax: price.formatTax,
                    lowestHistoricalPriceInLast30Days: lowestHistoricalPriceInLast30Days ?: null,
                    lowestHistoricalPricePercentage: lowestHistoricalPricePercentage ?: null,
                    isLowestHistoricalPriceHigherThanCurrent: isLowestHistoricalPriceHigherThanCurrent,
                    priceOutsideTheBundle: productVariant.bundle.originalItemsPrice.formatGross
                }, {
                    showAdditionalTaxInfo: globalPricesSettings.showAdditionalTaxInfo,
                    showSpecialOfferDuration,
                    showLowestPriceIn30Days: globalPricesSettings.showLowestPriceIn30Days,
                    showPriceWithoutShippingCostInfo: globalPricesSettings.showAdditionalTaxInfo,
                    showRegularPrice: moduleConfig.showRegularPrice,
                    showPercentageDiscountValue: moduleConfig.percentageDiscountValue
                }) }}
            </h-tab-panel>
        </h-tab-panel>
    </product-price>

    {% if globalPricesSettings.showPricesToUnregistered %}
        {% set priceSpecifications = [] %}

        {% set specialOfferStartDate = productVariant.hasSpecialOffer ? specialOffer.getDetails().startDate.dateShort : null %}
        {% set specialOfferEndDate = productVariant.hasSpecialOffer ? specialOffer.getDetails().endDate.dateShort : null %}

        {% if globalPricesSettings.showGrossPrice %}
            {% set priceSpecifications = priceSpecifications|merge([
                {
                    "@type": "PriceSpecification",
                    "price": price.grossValue,
                    "priceCurrency": price.currency,
                    "valueAddedTaxIncluded": true,
                    "validFrom": specialOfferStartDate,
                    "validThrough": specialOfferEndDate
                }
            ]) %}

            {% if unitPrice %}
                {% set priceSpecifications = priceSpecifications|merge([
                    {
                        "@type": "UnitPriceSpecification",
                        "price": unitPrice.grossValue,
                        "priceCurrency": unitPrice.currency.code,
                        "unitText": productVariant.unitPriceCalculationUnit.name,
                        "valueAddedTaxIncluded": true,
                        "validFrom": specialOfferStartDate,
                        "validThrough": specialOfferEndDate
                    }
                ]) %}
            {% endif %}

            {% if showDifferentCurrency %}
                {% set priceSpecifications = priceSpecifications|merge([
                    {
                        "@type": "PriceSpecification",
                        "price": priceInCurrency.netValue,
                        "priceCurrency": productVariant.currency.code,
                        "valueAddedTaxIncluded": false,
                        "validFrom": specialOfferStartDate,
                        "validThrough": specialOfferEndDate
                    }
                ]) %}
            {% endif %}
        {% endif %}

        {% if globalPricesSettings.showNetPrice %}
            {% set priceSpecifications = priceSpecifications|merge([
                {
                    "@type": "PriceSpecification",
                    "price": price.netValue,
                    "priceCurrency": price.currency,
                    "valueAddedTaxIncluded": false,
                    "validFrom": specialOfferStartDate,
                    "validThrough": specialOfferEndDate
                }
            ]) %}

            {% if unitPrice %}
                {% set priceSpecifications = priceSpecifications|merge([
                    {
                        "@type": "UnitPriceSpecification",
                        "price": unitPrice.netValue,
                        "priceCurrency": unitPrice.currency.code,
                        "unitText": productVariant.unitPriceCalculationUnit.name,
                        "valueAddedTaxIncluded": false,
                        "validFrom": specialOfferStartDate,
                        "validThrough": specialOfferEndDate
                    }
                ]) %}
            {% endif %}

            {% if showDifferentCurrency %}
                {% set priceSpecifications = priceSpecifications|merge([
                    {
                        "@type": "PriceSpecification",
                        "price": priceInCurrency.netValue,
                        "priceCurrency": productVariant.currency.code,
                        "valueAddedTaxIncluded": false,
                        "validFrom": specialOfferStartDate,
                        "validThrough": specialOfferEndDate
                    }
                ]) %}
            {% endif %}
        {% endif %}

        {% set productPricesJsonLd = {
            "@context": [
                "http://schema.org/",
                {
                    "@base": "#{shopUrls.mainPageUrl.absolute}"
                }
            ],
            "@id": "#{productVariant.url.relative}",
            "offers": {
                "@id": "#{productVariant.url.relative}",
                "@type": "Offer",
                "priceValidUntil": specialOfferEndDate,
                "PriceSpecification": priceSpecifications
            }
        }%}

        <script type="application/ld+json">
        {{ productPricesJsonLd | json_encode | raw }}
    </script>
    {% endif %}
{% endset %}

{% if globalPricesSettings.showPricesToUnregistered  %}
    {{ prices }}
{% else %}
    <auth-controller>
        <div slot="logged-in" hidden>
            {{ prices }}
        </div>

        <div slot="logged-out">
            <div class="flash-message flash-message__warning">
                <h-icon
                        icon-name="icon-alert-triangle"
                        css-classes="flash-message__icon"
                        role="button"
                ></h-icon>

                <p>{{ translate('Please %slog in%s to view the product price', ['<login-modal-opener class="link link_regular link_underline" tabindex="0" role="button">', '</login-modal-opener>']) }}</p>
            </div>
        </div>
    </auth-controller>
{% endif %}

The module uses JSON-LD and Microdata from schema.org to optimize search results in browsers.

Macros reference

Webcomponents reference

Used Object Api methods

Used styles

Module configuration schema

[
    {
        "state": "unfolded",
        "label": "General settings",
        "elements": [
            {
                "type": "infobox",
                "name": "infobox",
                "options": {
                    "type": "blank",
                    "message": "%s Related settings in the admin panel%s- changing phrases in [translations](%s)%s- showing net\/gross prices in [tax rates settings](%s)%s- enabling different currency and unit price calculation in [product settings](%s)%s- enabling information about the lowest price on the product page in [product settings](%s)",
                    "placeholderValues": [
                        "####",
                        "\n",
                        "\/admin\/configLanguages\/list",
                        "\n",
                        "\/admin\/configTax\/list",
                        "\n",
                        "\/admin\/configProducts",
                        "\n",
                        "\/admin\/configProducts"
                    ]
                }
            }
        ]
    },
    {
        "state": "unfolded",
        "label": "Promotions",
        "elements": [
            {
                "type": "checkbox",
                "name": "showRegularPrice",
                "label": "Display regular price (for products on sale)",
                "defaultValue": 0
            },
            {
                "type": "checkbox",
                "name": "percentageDiscountValue",
                "label": "Display the percentage change in price",
                "defaultValue": 0,
                "hint": {
                    "message": "For products on sale, an additional information (e.g. - 20%s) will be displayed next to the crossed-out regular price and the lowest price.",
                    "placeholderValues": ["%"]
                }
            },
            {
                "type": "checkbox",
                "name": "showSpecialOfferDuration",
                "label": "Display promotion end date",
                "defaultValue": 1,
                "children": [
                    {
                        "type": "radio",
                        "name": "specialOfferDurationType",
                        "label": "Show for:",
                        "defaultValue": "allPromotions",
                        "options": {
                            "radioOptions": [
                                { "key": "allPromotions", "label": "all promotions" },
                                { "key": "promotionsLastingMoreThan30Days", "label": "promotions lasting more than 30 days" }
                            ]
                        },
                        "relations": [
                            {
                                "parentName": "showSpecialOfferDuration",
                                "parentValueToActionsMap": [
                                    {
                                        "value": 0,
                                        "actions": ["setHidden", "setDisabled", "setOptional"]
                                    },
                                    {
                                        "value": 1,
                                        "actions": ["setVisible", "setAvailable", "setRequired"]
                                    }
                                ]
                            }
                        ]
                    }
                ]
            }
        ]
    }
]