Skip to content

Product Shipping Prices

Use product_shipping_prices module to insert a module displaying the lowest shipping cost of the currently viewed product on a page with a possibility to view all available shipping costs for a given product. This module is available only within a product card.

Configuration parameters

none

Module source code

{% from "@macros/icon.twig" import icon %}
{% from "@macros/product_shipping_prices_modal.twig" import product_shipping_prices_modal %}

{% set product = ObjectApi.getProduct(product_id) %}
{% set shipping = product.shipping %}

{% set modalName = 'product-shipping-prices-modal-' ~ moduleInstance %}

{% set defaultVariant = product.variant %}

{% if defaultVariant.countryShippingCosts|length > 0 or product.variants|length > 1 %}
    {% set shopLanguageCountryShippingCosts = defaultVariant.countryShippingCosts|filter((countryShippingCosts) => countryShippingCosts.country.id == 179) %}

    {% if shopLanguageCountryShippingCosts|length == 0 %}
        {% set defaultCountryShippingCosts = defaultVariant.countryShippingCosts[0] %}
        {% set isDefaultCountryDifferentThanShopLanguage = true %}
    {% else %}
        {% set defaultCountryShippingCosts = shopLanguageCountryShippingCosts|first %}
    {% endif %}

    {% set defaultShippingCosts = defaultCountryShippingCosts.shippingCosts[0] %}

    {% set doesShipToMultipleCountries = defaultVariant.countryShippingCosts|length > 1 %}
    {% set hasMultipleShippingMethods = doesShipToMultipleCountries or defaultCountryShippingCosts.shippingCosts|length > 1 %}
    {% set isPersonalCollect = defaultShippingCosts.shipping.isPersonalCollect %}

    {% set shippingMethodsBasicInfo %}
        <strong class="product-shipping-prices__shipping-info-price">
            {% if hasMultipleShippingMethods %}
                {{ translate('from') }}
                {{ defaultShippingCosts.price.formatGross }}
            {% elseif defaultShippingCosts.price.isZero and isPersonalCollect %}
                {{ translate('free <<shipping_prices personal collect>>') }}
            {% elseif defaultShippingCosts.price.isZero %}
                {{ translate('free <<shipping_prices delivery>>') }}
            {% else %}
                {{ translate('from') }}
                {{ defaultShippingCosts.price.formatGross }}
            {% endif %}
        </strong>

        {% if not isPersonalCollect %}
            -
            {{ defaultShippingCosts.shipping.name }}
        {% endif %}

        {% if doesShipToMultipleCountries or isDefaultCountryDifferentThanShopLanguage %}
            ({{ translate(defaultCountryShippingCosts.country.name) }})
        {% endif %}
    {% endset %}

    {% set shippingMethodsSimple %}
        {{ icon('icon-package', {
            classNames: ['icon_xs', 'product-shipping-prices__icon']
        }) }}

        <div class="product-shipping-prices__shipping-method-wrapper">
            <span class="product-shipping-prices__shipping-method">
                {% if isPersonalCollect %}
                    {{ translate('Pick up in person') }}
                {% else %}
                    {{ translate('Shipping') }}
                {% endif %}
            </span>

            <h-modal-opener
                class="
                    product-shipping-prices__shipping-info
                    product-shipping-prices__shipping-info_multiple-shippings
                    link
                    link_secondary
                "
                name="{{ modalName }}"
                {{ hasMultipleShippingMethods ? '' : 'hidden' }}
            >
                {{ shippingMethodsBasicInfo }}
            </h-modal-opener>

            <span
                class="product-shipping-prices__shipping-info product-shipping-prices__shipping-info_single-shipping"
                {{ hasMultipleShippingMethods ? 'hidden' : '' }}
            >
                {{ shippingMethodsBasicInfo }}
            </span>

            <p class="product-shipping-prices__description p_xs color_secondary">{{ defaultShippingCosts.shipping.description }}</p>
        </div>
    {% endset %}

    {% set hasMultipleVariants = product.variants|length > 1 %}

    {% if doesShipToMultipleCountries or hasMultipleVariants %}
        {% set defaultCountries = [] %}
        {% for countryShippingCost in defaultVariant.countryShippingCosts %}
            {% set countryId = countryShippingCost.country.id %}
            {% set countryName = countryShippingCost.country.name %}

            {% set defaultCountries = defaultCountries|merge([{ countryId, countryName }]) %}
        {% endfor %}

        {% set availableShippings = [] %}
        {% for countryShippingCost in defaultVariant.countryShippingCosts %}
            {% for shippingCost in countryShippingCost.shippingCosts %}
                {% set isShippingAlreadyAdded = availableShippings|filter(shipping => shipping.id == shippingCost.shipping.id)|length > 0 %}

                {% if not isShippingAlreadyAdded %}
                    {% set description = shippingCost.shipping.description %}
                    {% if shippingCost.shipping.isPersonalCollect %}
                        {% set shippingType = 'personal' %}
                    {% elseif shippingCost.shipping.isPickupPointDelivery %}
                        {% set shippingType = 'pickupPoint' %}
                    {% else %}
                        {% set shippingType = '' %}
                    {% endif %}
                    {% set name = shippingCost.shipping.name %}
                    {% set id = shippingCost.shipping.id %}

                    {% set availableShippings = availableShippings|merge([{ description, shippingType, name, id }]) %}
                {% endif %}
            {% endfor %}
        {% endfor %}

        {% set shippingsInCountries = [] %}
        {% for countryShippingCost in defaultVariant.countryShippingCosts %}
            {% set countryId = countryShippingCost.country.id %}

            {% set shippingCosts = [] %}
            {% for shippingCost in countryShippingCost.shippingCosts %}
                {% set lowestCost = shippingCost.price.formatGross %}
                {% set lowestCostFloat = shippingCost.price.grossValue %}
                {% set id = shippingCost.shipping.id %}

                {% set shippingCosts = shippingCosts|merge([{ lowestCost, lowestCostFloat, id }]) %}
            {% endfor %}

            {% set shippingsInCountries = shippingsInCountries|merge([{ countryId, shippingCosts }]) %}
        {% endfor %}

        <product-shipping-prices
            product-id="{{ product.id }}"
            variant-id="{{ product.variant.id }}"
            class="product-shipping-prices"
            default-countries="{{ defaultCountries|json_encode }}"
            default-available-shippings="{{ availableShippings|json_encode }}"
            default-shippings-in-countries="{{ shippingsInCountries|json_encode }}"
        >
            <div class="product-shipping-prices">
                {{ shippingMethodsSimple }}
            </div>

            {{ product_shipping_prices_modal({
                countryShippingCosts: defaultVariant.countryShippingCosts,
                modalName,
                moduleInstanceId: moduleInstance,
                hasMultipleVariants,
                doesShipToMultipleCountries
            }) }}
        </product-shipping-prices>
    {% else %}
        <div class="product-shipping-prices">
            {{ shippingMethodsSimple }}
        </div>

        {% if hasMultipleShippingMethods %}
            {{ product_shipping_prices_modal({
                countryShippingCosts: defaultVariant.countryShippingCosts,
                modalName,
                moduleInstanceId: moduleInstance,
                hasMultipleVariants,
                doesShipToMultipleCountries
            }) }}
        {% endif %}
    {% endif %}
{% endif %}

Used webcomponents

Used macros

Used Object Api methods

Used styles

Module configuration schema

[
    {
        "state": "unfolded",
        "label": "General settings",
        "elements": [
            {
                "type": "infobox",
                "name": "infobox",
                "options": {
                    "type": "blank",
                    "message": "#### Related settings in the admin panel:%s- changing phrases in [translations](%s)%s- changing shipping methods and costs in [delivery settings](%s)",
                    "placeholderValues": [
                        "\n",
                        "\/admin\/configLanguages\/list",
                        "\n",
                        "\/admin\/configShippings\/list"
                    ]
                }
            }
        ]
    }
]