Het duidelijk tonen van prijzen exclusief BTW is essentieel voor B2B webshops. In deze handleiding leg ik stap voor stap uit hoe je eenvoudig een Shopify block toevoegt.
Ken je dat gevoel? Je hebt een mooie Shopify-winkel, verkoopt aan zowel particulieren als bedrijven, en dan krijg je steeds weer die ene vraag: "Ja, maar hoeveel is het zonder BTW?"
Het wordt nog vervelender als je bedenkt dat zakelijke klanten vaak hun beslissingen baseren op netto prijzen. Ze moeten budgetten verantwoorden, offertes maken, en willen gewoon direct zien wat ze kwijt zijn exclusief BTW. En laten we eerlijk zijn - het handmatig uitrekenen en mailen kost gewoon te veel tijd.
Daarom heb ik deze handige oplossing gebouwd. Het is een block dat automatisch de prijs zonder BTW toont, direct onder je normale prijs. Het werkt met alle moderne Shopify-thema's en het mooiste is: als iemand een andere variant kiest (andere kleur, maat, whatever), past de BTW-prijs zich meteen aan. Geen gedoe, gewoon werkend.
Voordat we gaan klooien met code, even snel wat je ermee kunt. Het rekent natuurlijk automatisch je BTW uit (je stelt zelf het percentage in). Maar het kan meer. Je kunt er een mooi "Zakelijk" labeltje bij zetten, de kleuren aanpassen zodat het perfect bij je huisstijl past, en zelfs kiezen hoe je prijsbereiken wilt tonen.
Oh, en het werkt gewoon goed op telefoons. Dat is tegenwoordig geen luxe meer, maar noodzaak.
Oké, eerst even inloggen in je Shopify-admin. Ga naar Online Store > Themes. Bij je actieve thema zie je een knopje Actions, klik daarop en kies Edit code.
Nu zie je een hoop mappen aan de linkerkant. Zoek de map Snippets op en klik op Add a new snippet. Geef het de naam price-ex-btw (zonder aanhalingstekens) en klik op Create snippet.
Goed, nu komt het echte werk. Delete alles wat er staat en plak deze code:
liquid
{% comment %}
⚡️ Prijs Exclusief BTW Snippet by Diek Thunnissen
- Werkt met echte product variants (variant-selects component)
- Werkt met product variations (verschillende producten)
- Detecteert beide systemen automatisch{% endcomment %}
{%- liquid
# Bereken prijzen excl. BTW
assign btw_percentage = block.settings.btw_percentage | times: 1.0 | divided_by: 100.0
assign btw_multiplier = 1.0 | plus: btw_percentage
# Bereken de afrondfactor
assign decimal_places = block.settings.decimal_places | default: 2
assign rounding_factor = decimal_places | prepend: '1' | append: '0' | times: 1
# Voor product variations gebruiken we altijd het huidige product
assign target_product = product
# Verwerk prijzen voor het huidige product
if product.price_varies
assign regular_price_min = product.price_min | divided_by: btw_multiplier | times: rounding_factor | round | divided_by: rounding_factor
assign regular_price_max = product.price_max | divided_by: btw_multiplier | times: rounding_factor | round | divided_by: rounding_factor
else
assign regular_price = product.price | divided_by: btw_multiplier | times: rounding_factor | round | divided_by: rounding_factor
endif
# Als er een selected variant is, gebruik die prijs
if product.selected_or_first_available_variant
assign variant_price = product.selected_or_first_available_variant.price | divided_by: btw_multiplier | times: rounding_factor | round | divided_by: rounding_factor
endif
-%}
<style>
.zakelijk-btw-container {
display: flex;
align-items: center;
gap: 8px;
margin-top: {{ block.settings.spacing | default: 8 }}px;
margin-bottom: 12px;
}
.zakelijk-tag {
display: inline-block;
background-color: {{ block.settings.badge_bg_color | default: '#a18367' }};
color: {{ block.settings.badge_text_color | default: '#ffffff' }};
font-size: 12px;
padding: 3px 10px;
border-radius: {{ block.settings.badge_radius | default: 3 }}px;
}
.ex-btw-price {
font-size: {{ block.settings.font_size | default: 14 }}px;
color: {{ block.settings.price_color | default: '#000000' }};
font-weight: {{ block.settings.price_weight | default: 'bold' }};
}
.ex-btw-label {
color: {{ block.settings.label_color | default: '#707070' }};
font-weight: {{ block.settings.label_weight | default: 'normal' }};
font-size: {{ block.settings.font_size | default: 14 }}px;
{% if block.settings.label_style == 'italic' %}font-style: italic;{% endif %}
}
{% if block.settings.custom_css != blank %}
{{ block.settings.custom_css }}
{% endif %}
</style>
<div class="zakelijk-btw-container {{ block.settings.custom_class }}" id="btw-price-container">
{% if block.settings.show_badge %}
<span class="zakelijk-tag">{{ block.settings.badge_text | default: 'Zakelijk' }}</span>
{% endif %}
<span class="ex-btw-label">{{ block.settings.label_text | default: 'Excl. BTW:' }}</span>
{%- if product.price_varies -%}
<span class="ex-btw-price" id="btw-price-display">
{%- if block.settings.price_format == 'from' -%}
{{ block.settings.from_text | default: 'Vanaf' }} {{ regular_price_min | money }}
{%- else -%}
{{ regular_price_min | money }}{{ block.settings.range_separator | default: ' - ' }}{{ regular_price_max | money }}
{%- endif -%}
</span>
{%- else -%}
<span class="ex-btw-price" id="btw-price-display">
{%- if variant_price -%}
{{ variant_price | money }}
{%- else -%}
{{ regular_price | money }}
{%- endif -%}
</span>
{%- endif -%}
{% if block.settings.show_inc_btw %}
{% if block.settings.inc_btw_placement == 'inline' %}
<span class="ex-btw-label" style="margin-left: 8px;">{{ block.settings.inc_btw_label | default: 'Incl. BTW:' }}</span>
<span class="ex-btw-price" id="inc-btw-price-display">
{%- if product.price_varies -%}
{%- if block.settings.price_format == 'from' -%}
{{ block.settings.from_text | default: 'Vanaf' }} {{ product.price_min | money }}
{%- else -%}
{{ product.price_min | money }}{{ block.settings.range_separator | default: ' - ' }}{{ product.price_max | money }}
{%- endif -%}
{%- else -%}
{%- if product.selected_or_first_available_variant -%}
{{ product.selected_or_first_available_variant.price | money }}
{%- else -%}
{{ product.price | money }}
{%- endif -%}
{%- endif -%}
</span>
{% endif %}
{% endif %}
</div>
{% if block.settings.show_inc_btw and block.settings.inc_btw_placement == 'under' %}
<div class="zakelijk-btw-container {{ block.settings.custom_class }}" style="margin-top: 4px;">
<span class="ex-btw-label">{{ block.settings.inc_btw_label | default: 'Incl. BTW:' }}</span>
<span class="ex-btw-price" id="inc-btw-price-display-under">
{%- if product.price_varies -%}
{%- if block.settings.price_format == 'from' -%}
{{ block.settings.from_text | default: 'Vanaf' }} {{ product.price_min | money }}
{%- else -%}
{{ product.price_min | money }}{{ block.settings.range_separator | default: ' - ' }}{{ product.price_max | money }}
{%- endif -%}
{%- else -%}
{%- if product.selected_or_first_available_variant -%}
{{ product.selected_or_first_available_variant.price | money }}
{%- else -%}
{{ product.price | money }}
{%- endif -%}
{%- endif -%}
</span>
</div>
{% endif %}
{% comment %} JavaScript voor variant price updates
{% endcomment %}
{% if template == 'product' %}
<script>
document.addEventListener('DOMContentLoaded', function() {
const BTW_MULTIPLIER = {{ btw_multiplier }};
const btwPriceDisplay = document.getElementById('btw-price-display');
const incBtwPriceDisplay = document.getElementById('inc-btw-price-display');
const incBtwPriceDisplayUnder = document.getElementById('inc-btw-price-display-under');
if (!btwPriceDisplay) return;
// Functie om BTW prijzen te updaten
function updateBTWPrices(variantId) {
if (!variantId) return;
// Zoek variant data uit het JSON script in variant-selects
const variantScript = document.querySelector('variant-selects script[data-selected-variant]');
let variantData = null;
if (variantScript) {
try {
const selectedVariant = JSON.parse(variantScript.textContent);
if (selectedVariant && selectedVariant.id.toString() === variantId.toString()) {
variantData = selectedVariant;
}
} catch (e) {
console.log('Error parsing selected variant:', e);
}
}
// Als geen data van script, zoek alle variants
if (!variantData) {
// Zoek in window object
if (window.productData && window.productData.variants) {
variantData = window.productData.variants.find(v => v.id.toString() === variantId.toString());
}
// Zoek in andere mogelijke locaties
if (!variantData && window.product && window.product.variants) {
variantData = window.product.variants.find(v => v.id.toString() === variantId.toString());
}
}
if (variantData && variantData.price) {
const variantPrice = parseInt(variantData.price);
const exBtwPrice = Math.round(variantPrice / BTW_MULTIPLIER);
// Update BTW prijs
if (typeof Shopify !== 'undefined' && Shopify.formatMoney) {
btwPriceDisplay.textContent = Shopify.formatMoney(exBtwPrice, "{{ shop.money_format }}");
if (incBtwPriceDisplay) {
incBtwPriceDisplay.textContent = Shopify.formatMoney(variantPrice, "{{ shop.money_format }}");
}
if (incBtwPriceDisplayUnder) {
incBtwPriceDisplayUnder.textContent = Shopify.formatMoney(variantPrice, "{{ shop.money_format }}");
}
} else {
// Fallback zonder Shopify.formatMoney
const formattedExBtw = '€' + (exBtwPrice / 100).toFixed(2).replace('.', ',');
const formattedInc = '€' + (variantPrice / 100).toFixed(2).replace('.', ',');
btwPriceDisplay.textContent = formattedExBtw;
if (incBtwPriceDisplay) incBtwPriceDisplay.textContent = formattedInc;
if (incBtwPriceDisplayUnder) incBtwPriceDisplayUnder.textContent = formattedInc;
}
}
}
// Luister naar variant-selects component
const variantSelects = document.querySelector('variant-selects');
if (variantSelects) {
// Luister naar radio button changes (swatch picker)
const radioInputs = variantSelects.querySelectorAll('input[type="radio"]');
radioInputs.forEach(input => {
input.addEventListener('change', function() {
setTimeout(() => {
// Check of er een hidden input is met variant ID
const hiddenInput = document.querySelector('input[name="id"][type="hidden"], select[name="id"]');
if (hiddenInput && hiddenInput.value) {
updateBTWPrices(hiddenInput.value);
}
}, 100);
});
});
// Luister naar select changes (dropdown picker)
const selectInputs = variantSelects.querySelectorAll('select');
selectInputs.forEach(select => {
select.addEventListener('change', function() {
setTimeout(() => {
const hiddenInput = document.querySelector('input[name="id"][type="hidden"], select[name="id"]');
if (hiddenInput && hiddenInput.value) {
updateBTWPrices(hiddenInput.value);
}
}, 100);
});
});
// Observeer DOM changes voor dynamische updates
const observer = new MutationObserver((mutations) => {
mutations.forEach((mutation) => {
if (mutation.type === 'childList' || mutation.type === 'attributes') {
const hiddenInput = document.querySelector('input[name="id"][type="hidden"], select[name="id"]');
if (hiddenInput && hiddenInput.value) {
updateBTWPrices(hiddenInput.value);
}
}
});
});
observer.observe(variantSelects, {
childList: true,
subtree: true,
attributes: true,
attributeFilter: ['data-selected-variant']
});
}
// Luister naar custom events
document.addEventListener('variant:change', function(event) {
if (event.detail && event.detail.variant && event.detail.variant.id) {
updateBTWPrices(event.detail.variant.id);
}
});
// Fallback: observeer prijs wijzigingen
const priceElement = document.querySelector('.price, .product__price, [data-price]');
if (priceElement) {
const priceObserver = new MutationObserver(() => {
setTimeout(() => {
const hiddenInput = document.querySelector('input[name="id"][type="hidden"], select[name="id"]');
if (hiddenInput && hiddenInput.value) {
updateBTWPrices(hiddenInput.value);
}
}, 50);
});
priceObserver.observe(priceElement, { childList: true, subtree: true });
}
});
</script>
{% endif %}
Wat doet deze code nou eigenlijk? Het eerste stuk (dat liquid gedeelte) rekent de BTW uit. Het is slim genoeg om te kijken of je product verschillende prijzen heeft (bijvoorbeeld verschillende maten met verschillende prijzen) en past zich daarop aan.
Het CSS stukje in het midden zorgt dat alles er netjes uitziet. En dat JavaScript onderaan? Dat is de toversaus die ervoor zorgt dat als iemand een andere variant kiest, de prijs meteen mee verandert. Geen pagina refresh nodig.
Nu moeten we Shopify vertellen waar dit block moet komen. Zoek in je code editor het bestand main-product.liquid
. Dit is het hoofdbestand van je productpagina's.
Open het bestand en zoek (met Ctrl+F of Cmd+F) naar {%- case block.type -%}
. Dit staat meestal ergens tussen regel 200 en 400. Direct onder deze regel plak je:
liquid
{%- when 'price_ex_btw' -%}
<div class="product-info__block product-info__block--sm product-price-ex-btw" {{ block.shopify_attributes }}>
{% render 'price-ex-btw', product: product, block: block, use_variant: true, current_variant: current_variant %}
</div>
Dit zegt eigenlijk tegen Shopify: "Hé, als iemand een price_ex_btw block toevoegt, gebruik dan onze snippet."
Laatste technische stap. In hetzelfde main-product.liquid
bestand scroll je helemaal naar beneden tot je {% schema %}
ziet. Zoek daar naar "blocks": [
en plak direct daarna:
json
{
"type": "price_ex_btw",
"name": "⚡️ Prijs Excl. BTW",
"limit": 1,
"settings": [
{
"type": "header",
"content": "⚡️ Prijs Exclusief BTW by Diek Thunnissen",
"info": "Voeg prijzen exclusief BTW toe aan je product pagina."
},
{
"type": "range",
"id": "btw_percentage",
"min": 1,
"max": 30,
"step": 1,
"unit": "%",
"label": "BTW percentage",
"default": 21
},
{
"type": "text",
"id": "label_text",
"label": "Label tekst",
"default": "Excl. BTW:"
},
{
"type": "checkbox",
"id": "show_inc_btw",
"label": "Toon ook prijs incl. BTW",
"default": true
},
{
"type": "text",
"id": "inc_btw_label",
"label": "Incl. BTW label",
"default": "Incl. BTW:"
},
{
"type": "select",
"id": "inc_btw_placement",
"label": "Incl. BTW weergave",
"options": [
{
"value": "under",
"label": "Onder excl. BTW"
},
{
"value": "inline",
"label": "Naast excl. BTW"
}
],
"default": "under"
},
{
"type": "select",
"id": "price_format",
"label": "Prijsweergave bij prijsbereik",
"options": [
{
"value": "from",
"label": "Vanaf"
},
{
"value": "range",
"label": "Bereik (min-max)"
}
],
"default": "from"
},
{
"type": "text",
"id": "from_text",
"label": "Vanaf tekst",
"default": "Vanaf"
},
{
"type": "text",
"id": "range_separator",
"label": "Bereik separator",
"default": " - "
},
{
"type": "header",
"content": "Badge"
},
{
"type": "checkbox",
"id": "show_badge",
"label": "Toon badge",
"default": false
},
{
"type": "text",
"id": "badge_text",
"label": "Badge tekst",
"default": "Zakelijk"
},
{
"type": "color",
"id": "badge_bg_color",
"label": "Badge achtergrondkleur",
"default": "#f2f2f2"
},
{
"type": "color",
"id": "badge_text_color",
"label": "Badge tekstkleur",
"default": "#555555"
},
{
"type": "range",
"id": "badge_radius",
"min": 0,
"max": 20,
"step": 1,
"unit": "px",
"label": "Badge hoekradius",
"default": 4
},
{
"type": "header",
"content": "Styling"
},
{
"type": "range",
"id": "spacing",
"min": 0,
"max": 40,
"step": 2,
"unit": "px",
"label": "Verticale ruimte",
"default": 8
},
{
"type": "range",
"id": "font_size",
"min": 10,
"max": 24,
"step": 1,
"unit": "px",
"label": "Lettergrootte",
"default": 14
},
{
"type": "color",
"id": "label_color",
"label": "Label kleur",
"default": "#707070"
},
{
"type": "color",
"id": "price_color",
"label": "Prijs kleur",
"default": "#000000"
},
{
"type": "select",
"id": "label_weight",
"label": "Label gewicht",
"options": [
{
"value": "normal",
"label": "Normaal"
},
{
"value": "bold",
"label": "Vet"
},
{
"value": "500",
"label": "Medium"
}
],
"default": "normal"
},
{
"type": "select",
"id": "label_style",
"label": "Label stijl",
"options": [
{
"value": "normal",
"label": "Normaal"
},
{
"value": "italic",
"label": "Cursief"
}
],
"default": "normal"
},
{
"type": "select",
"id": "price_weight",
"label": "Prijs gewicht",
"options": [
{
"value": "normal",
"label": "Normaal"
},
{
"value": "bold",
"label": "Vet"
},
{
"value": "500",
"label": "Medium"
}
],
"default": "bold"
},
{
"type": "header",
"content": "Geavanceerd"
},
{
"type": "text",
"id": "custom_class",
"label": "Custom CSS class"
},
{
"type": "liquid",
"id": "custom_css",
"label": "Custom CSS",
"info": "Gebruik de .zakelijk-btw-container class als selector"
}
]
},
Klaar! De code staat er nu in.
Nu het leuke deel. Ga naar Online Store > Themes en klik op Customize. Open een productpagina en onder Product information zie je een Add block knop. Klik daarop en tadaa - daar staat je nieuwe ⚡️ Prijs Excl. BTW block.
Sleep het naar waar je het wilt hebben. Direct onder de prijs is vaak een goede plek, maar je kunt het ook bij de product details zetten. Zodra je het toevoegt, zie je rechts alle instellingen.
Voor de meeste B2B winkels werkt dit goed: zet het BTW percentage op 21%, vink "Toon ook prijs incl. BTW" aan, en kies voor weergave "Onder excl. BTW". Zo zie je beide prijzen netjes onder elkaar.
Wil je het wat minder opvallend? Maak de lettergrootte 12px, zet de labelkleur op lichtgrijs (#999999
) en de prijskleur op donkergrijs (#666666
). Dan staat de info er wel, maar valt het niet te veel op.
Voor een echt professionele uitstraling zet je de "Zakelijk" badge aan. Kies een mooie achtergrondkleur die bij je merk past. Wil je het helemaal af maken? Voeg wat custom CSS toe:
css
.zakelijk-btw-container {
box-shadow: 0 2px 4px rgba(0,0,0,0.1);
padding: 12px;
background: #f8f9fa;
border-radius: 8px;
}
Heb je producten met verschillende BTW percentages? Geen probleem. Maak verschillende product templates aan in Shopify. Bijvoorbeeld eentje voor normale producten (21%), eentje voor voeding (9%) en eentje voor boeken (9%). In elk template stel je het juiste BTW percentage in.
Meestal komt het door een typfoutje. Check vooral of alle komma's en accolades kloppen in de JSON. Eén missende komma en Shopify snapt er niks meer van.
Werken de variant prijzen niet? Kan gebeuren bij sommige thema's. Het block probeert verschillende manieren om de juiste prijs te vinden, maar soms moet je het JavaScript een beetje aanpassen voor jouw specifieke thema.
Het mooie is dat snippets bewaard blijven als je je thema update. Maar je moet wel de block settings opnieuw toevoegen aan main-product.liquid
. Daarom is het slim om een backup te maken van je aangepaste code.
Het is niet alleen handig voor jou (geen gezeik meer met BTW vragen), maar je zakelijke klanten voelen zich ook serieus genomen. Ze zien meteen wat ze moeten betalen, kunnen makkelijk vergelijken en offertes maken.
En eerlijk is eerlijk - het ziet er ook gewoon professioneel uit. Het laat zien dat je nadenkt over verschillende soorten klanten en hun behoeften.
Je hebt nu een krachtige toevoeging aan je Shopify winkel. Test het vooral goed uit, vraag feedback aan je zakelijke klanten, en pas het aan waar nodig.
Loopt het ergens spaak of wil je iets speciaals? Stuur me gerust een mailtje. Ik help graag om het perfect te maken voor jouw situatie.
Diek Thunnissen
Shopify Developer & E-commerce Specialist
Ik help webwinkels om beter te worden. Van kleine aanpassingen tot complete custom oplossingen - altijd met het doel om het leven van winkeliers én hun klanten makkelijker te maken.
🌐 diekthunnissen.nl
📧 info@diekthunnissen.nl
Succes met je nieuwe BTW functie!
Al sinds mijn vijftiende bouw ik websites. Nu, 10+ jaar en 50+ projecten verder, combineer ik design, Shopify‑development en data‑gedreven marketing tot één 360° e‑commerce‑aanpak.
Check me op socials voor updates, tips en een kijkje achter de schermen.