All things Shopify and commerce
Hi,
I am looking for quotes on the following work:
We use the Local delivery option in Shopify that is setup with 3 x postcode zones and different costs per zone. Depending on the postcode the customer selects, is what we charge for freight.
We charge freight per order NOT per product.
I have two aims:
1. The customer can check and see the freight cost in the product page and the cart by entering their postcode.
OR
2. The customer can check and the freight cost in the Cart by entering their postcode.
If their postcode is not available, it needs to tell them that we do not deliver to the selected area.
Any work must be compatible with future theme updates etc.
The website is: www.bafurnitureclearance.au
Look forward to hearing back from someone with a good solution 🙂
Thanks
Dave
According to your store Dave @BAFC I see that you are using the Dawn theme, and you can add a Shipping calculator section in your card, so the desired results can be archivable, If It's not that you want, please provide further context. Best Regards 🙂
Hi Stefan,
Thanks for your reply.
Can you please explain/elaborate on this comment:
" I see that you are using the Dawn theme, and you can add a Shipping calculator section in your card"
Regards
Dave
1. Go to your online store theme click three dots and edit code
2. In the snippets folder create a file called "eg-shipping-calc" and paste the code below
{% liquid
assign title = 'Calculate Shipping Rates'
assign btn_label = 'Calculate'
assign btn_label_loading = 'Calculating...'
%}
<style>
.bs-alert {
position: relative;
padding: 8px 16px;
margin-bottom: 24px;
border-radius: 4px;
border-width: 1px;
border-style: solid;
}
.bs-alert-danger {
color: #842029;
background: #f8d7da;
border-color: #f5c2c7;
}
.bs-alert-warning {
color: #664d03;
background: #fff3cd;
border-color: #ffecb5;
}
.bs-alert-success {
color: #0f5132;
background: #d1e7dd;
border-color: #badbcc;
}
.bs-alert ul {
margin: 0;
padding: 0 0 0 12px;
line-height: normal;
}
.bs-alert ul li {
margin: 4px;
}
.bs-alert p {
margin: 0;
padding: 0;
}
/*
Shipping Calc
*/
#eg-shipping-calc {
position: relative;
overflow: hidden;
transition: all .2s ease-out;
margin-bottom: 32px;
}
#eg-shipping-calc-title {
font-size: 16px;
border-bottom: .1rem solid rgba(var(--color-foreground), .08);
padding-bottom: 6px;
margin-bottom: 14px;
}
.cart__footer #eg-shipping-calc-title {
margin-top: 0;
}
#eg-shipping-calc .select {
margin-bottom: 8px;
}
#eg-shipping-calc .select .select__select {
font-size: 1.5rem;
height: 3.5rem;
padding: 0 1.5rem;
}
#eg-shipping-calc .field {
margin-bottom: 8px;
}
#eg-shipping-calc .field .field__input {
height: 3.5rem;
padding: 0 1.5rem;
font-size: 1.5rem;
}
#eg-shipping-calc .field .field__input::placeholder {
opacity: 1;
}
#eg-shipping-calc .button {
height: 3.5rem;
min-height: auto;
}
</style>
<div id="eg-shipping-calc" style="display: none;">
<h4 id="eg-shipping-calc-title">
{{ title }}
</h4>
<div id="eg-shipping-calc-alert-danger" class="bs-alert bs-alert-danger" role="alert" hidden></div>
<div id="eg-shipping-calc-alert-warning" class="bs-alert bs-alert-warning" role="alert" hidden></div>
<div id="eg-shipping-calc-alert-success" class="bs-alert bs-alert-success" role="alert" hidden></div>
<div class="select">
<select
id="eg-shipping-calc-country"
class="select__select"
autocomplete="country"
aria-label="{{ 'customer.addresses.country' | t }}"
>
{{ all_country_option_tags }}
</select>
<svg aria-hidden="true" focusable="false" role="presentation" class="icon icon-caret" viewBox="0 0 10 6">
<path fill-rule="evenodd" clip-rule="evenodd" d="M9.354.646a.5.5 0 00-.708 0L5 4.293 1.354.646a.5.5 0 00-.708.708l4 4a.5.5 0 00.708 0l4-4a.5.5 0 000-.708z" fill="currentColor"></path>
</svg>
</div>
<div
id="eg-shipping-calc-province-wrapper"
class="select"
style="display: none;"
>
<select
id="eg-shipping-calc-province"
class="select__select"
autocomplete="address-level1"
aria-label="{{ 'customer.addresses.province' | t }}"
></select>
<svg aria-hidden="true" focusable="false" role="presentation" class="icon icon-caret" viewBox="0 0 10 6">
<path fill-rule="evenodd" clip-rule="evenodd" d="M9.354.646a.5.5 0 00-.708 0L5 4.293 1.354.646a.5.5 0 00-.708.708l4 4a.5.5 0 00.708 0l4-4a.5.5 0 000-.708z" fill="currentColor"></path>
</svg>
</div>
<div class="field">
<input
id="eg-shipping-calc-zip"
class="field__input"
type="text"
placeholder="{{ 'customer.addresses.zip' | t }}"
autocomplete="postal-code"
aria-label="{{ 'customer.addresses.zip' | t }}"
>
</div>
<button
id="eg-shipping-calc-btn"
class="button button--full-width button--secondary"
data-label="{{ btn_label }}"
data-label-loading="{{ btn_label_loading }}"
onclick="generateShippingRates(this)"
>
{{ btn_label }}
</button>
</div>
<script src="{{ 'shopify_common.js' | shopify_asset_url }}" defer></script>
<script>
window.addEventListener('DOMContentLoaded', (event) => {
// Init Shipping Calc feature
const initShippingCalc = async (preload = false) => {
const element = document.querySelector('#eg-shipping-calc')
const cartDrawerItems = document.querySelector('cart-drawer-items')
const cartFooter = document.querySelector('.cart__footer')
const countryProvinceSelector = new Shopify.CountryProvinceSelector('eg-shipping-calc-country', 'eg-shipping-calc-province', {
hideElement: 'eg-shipping-calc-province-wrapper'
});
// Check if the element has already been cloned once
if (cartDrawerItems && !cartDrawerItems.classList.contains('is-empty')) {
cartDrawerItems.insertAdjacentElement('beforeend', element.cloneNode(true));
document.querySelector('#CartDrawer #eg-shipping-calc').style.display = 'block';
}
if (cartFooter) {
cartFooter.insertAdjacentElement('afterbegin',element.cloneNode(true))
document.querySelector('#MainContent #eg-shipping-calc').style.display = 'block'
}
}
initShippingCalc();
const selectAllshippingCountry = document.querySelectorAll("#eg-shipping-calc-country");
let selectedValue;
selectAllshippingCountry.forEach(selectElement => {
selectElement.addEventListener("change", (event) => {
// Get the selected option
selectedValue = event.target.selectedOptions[0];
console.log("selectedValue: ", selectedValue);
// Set the selected option for all #eg-shipping-calc-country elements
selectAllshippingCountry.forEach(element => {
// Find the option with the selected value and set it as selected
const optionToSelect = Array.from(element.options).find(option => option.value === selectedValue.value);
if (optionToSelect) {
optionToSelect.selected = true;
// Check if selectedValue has data-provinces
const dataProvinces = selectedValue.getAttribute('data-provinces');
if (dataProvinces) {
const allProvinceWrappers = document.querySelectorAll("#eg-shipping-calc-province-wrapper");
const dataProvincesArr = dataProvinces.split(" ");
if(dataProvincesArr.length > 1) {
// Toggle the style display for allProvinceWrappers
allProvinceWrappers.forEach(wrapper => {
wrapper.style.display = 'block';
});
} else {
// Toggle the style display for allProvinceWrappers
allProvinceWrappers.forEach(wrapper => {
wrapper.style.display = 'none';
});
}
}
}
});
const countryProvinceSelector = new Shopify.CountryProvinceSelector('eg-shipping-calc-country', 'eg-shipping-calc-province', {
hideElement: 'eg-shipping-calc-province-wrapper'
});
});
});
// Generate Shipping rates
// https://shopify.dev/docs/api/ajax/reference/cart#generate-shipping-rates
window.generateShippingRates = async (btn) => {
btn.textContent = btn.dataset.labelLoading
const wrapper = btn.parentNode
wrapper.querySelector('#eg-shipping-calc-alert-danger').innerHTML = ''
wrapper.querySelector('#eg-shipping-calc-alert-danger').setAttribute('hidden', 'hidden')
wrapper.querySelector('#eg-shipping-calc-alert-warning').innerHTML = ''
wrapper.querySelector('#eg-shipping-calc-alert-warning').setAttribute('hidden', 'hidden')
wrapper.querySelector('#eg-shipping-calc-alert-success').innerHTML = ''
wrapper.querySelector('#eg-shipping-calc-alert-success').setAttribute('hidden', 'hidden')
const country = wrapper.querySelector('#eg-shipping-calc-country').value
const province = wrapper.querySelector('#eg-shipping-calc-province').value
const zip = wrapper.querySelector('#eg-shipping-calc-zip').value
const prepareResponse = await fetch(`/cart/prepare_shipping_rates.json?shipping_address[zip]=${zip}&shipping_address[country]=${country}&shipping_address[province]=${province}`, {
method: 'POST'
})
console.log(prepareResponse)
if (prepareResponse.ok) {
const asyncRespose = await fetch(`/cart/async_shipping_rates.json?shipping_address[zip]=${zip}&shipping_address[country]=${country}&shipping_address[province]=${province}`)
console.log(asyncRespose)
const data = await asyncRespose.json()
console.log(data)
let html = ''
if (data.shipping_rates.length) {
data.shipping_rates.forEach(elem => {
html += `
<li>
${elem.presentment_name}: <strong>${elem.price} ${elem.currency}</strong>
</li>
`
})
wrapper.querySelector('#eg-shipping-calc-alert-success').innerHTML = `
<ul class="">
${html}
</ul>
`
wrapper.querySelector('#eg-shipping-calc-alert-success').removeAttribute('hidden')
} else {
wrapper.querySelector('#eg-shipping-calc-alert-warning').innerHTML = `
<p class="">
${modal.dataset.textNoResults}
</p>
`
wrapper.querySelector('#eg-shipping-calc-alert-warning').removeAttribute('hidden')
}
} else {
const data = await prepareResponse.json()
console.log(data)
let html = ''
for (const [key, value] of Object.entries(data)) {
html += `
<li>
<strong>${key}</strong>: ${value.toString()}
</li>
`
}
wrapper.querySelector('#eg-shipping-calc-alert-danger').innerHTML = `
<ul class="">
${html}
</ul>
`
wrapper.querySelector('#eg-shipping-calc-alert-danger').removeAttribute('hidden')
}
btn.textContent = btn.dataset.label
}
})
</script>
3. Save it and now in the sections folder create a section named "shipping-calculator" and paste this code below
{% render 'eg-shipping-calc' %}
{% schema %}
{
"name": "Shipping Calculator",
"presets": [
{
"name": "Shipping Calculator"
}
]
}
{% endschema %}
4. Save it and exit the code editor, now go to your online store click customize go to your cart, and add a section named "Shipping Calculator" and save it.
5. Congrats now add your product to your cart go to your cart page and calculate the shipping!
Hi Stefan,
Thanks for this.
I will follow your instructions and see if I can get this to work.
I will report back afterwards.
Regards
Dave
Hi Alex,
Thanks for this.
I found out, that most app providers cannot integrate with the local shipping - manual postcode rates that I use in shopify.
They can work with the general rates, but this means that you have to select entire states, and cannot drill down to specific postcodes for the shipping.
I found a solution via adding meta objects in the admin, and a code snippet that connect to the local shipping section, and now have a cart calculator.
Thanks anyway.
Cheers,
BAFC
Discover how to increase the efficiency of commerce operations with Shopify Academy's l...
By Jacqui Mar 26, 2025Shopify and our financial partners regularly review and update verification requiremen...
By Jacqui Mar 14, 2025Unlock the potential of marketing on your business growth with Shopify Academy's late...
By Shopify Mar 12, 2025