Shopify show how close to free shipping - ajax

I am trying to show how close someone is to free shipping using the standard timber draw cart system. The code should be checking if the customer has $30 or less and then display how much more they need to spend to achieve free shipping, and if they are over $30 state that they have achieve the free shipping threshold.
Here is my current cart code
<!-- /snippets/ajax-cart-template.liquid -->
{% comment %}
This snippet provides the default handlebars.js templates for
the ajax cart plugin. Use the raw liquid tags to keep the
handlebar.js template tags as available hooks.
{% endcomment %}
<script id="CartTemplate" type="text/template">
{% raw %}
<form action="/cart" method="post" novalidate class="cart ajaxcart">
<div class="ajaxcart__inner">
{{#items}}
<div class="ajaxcart__product">
<div class="ajaxcart row" data-line="{{line}}">
<div class="grid__item desktop-4 tablet-2 mobile-1">
<img src="{{img}}" alt="">
</div>
<div class="desktop-8 tablet-4 mobile-2">
<p>
{{name}}
{{#if variation}}
<span class="ajaxcart__product-meta">{{variation}}</span>
{{/if}}
{{#properties}}
{{#each this}}
{{#if this}}
<span class="ajaxcart__product-meta">{{#key}}: {{this}}</span>
{{/if}}
{{/each}}
{{/properties}}
{% endraw %}{% if settings.cart_vendor_enable %}{% raw %}
<span class="ajaxcart__product-meta">{{ vendor }}</span>
{% endraw %}{% endif %}{% raw %}
</p>
<p><strong>{{{price}}}</strong></p>
<div class="display-table">
<div class="display-table-cell">
<div class="ajaxcart__qty">
<button type="button" class="ajaxcart__qty-adjust ajaxcart__qty--minus quantity-increment" data-id="{{id}}" data-qty="{{itemMinus}}" data-line="{{line}}">
<span>−</span>
</button>
<input type="text" name="updates[]" class="ajaxcart__qty-num" value="{{itemQty}}" min="0" data-id="{{id}}" data-line="{{line}}" aria-label="quantity" pattern="[0-9]*">
<button type="button" class="ajaxcart__qty-adjust ajaxcart__qty--plus quantity-increment" data-id="{{id}}" data-line="{{line}}" data-qty="{{itemAdd}}">
<span>+</span>
</button>
</div>
</div>
</div>
</div>
</div>
</div>
{{/items}}
{% endraw %}{% if settings.cart_notes_enable %}{% raw %}
<div>
<label for="CartSpecialInstructions">{% endraw %}{{ 'cart.general.note' | t }}{% raw %}</label>
<textarea name="note" class="input-full" id="CartSpecialInstructions">{{ note }}</textarea>
</div>
{% endraw %}{% endif %}{% raw %}
</div>
<div class="ajaxcart__footer row">
<div class="desktop-half tablet-half mobile-half">
<p><strong>{% endraw %}{{ 'cart.general.subtotal' | t }}{% raw %}</strong></p>
</div>
<div class="desktop-half tablet-half mobile-half">
<p class="text-right"><strong>{{{totalPrice}}}</strong></p>
</div>
<p class="text-center">{% endraw %}{{ 'cart.general.currency_disclaimer' | t }}{% raw %}</p>
<p class="text-center">{% endraw %}{{ section.settings.hello }}{% raw %}</p>
<p class="text-center">{% endraw %}{{ 'cart.general.shipping_at_checkout' | t }}{% raw %}</p>
<p class="text-center">
{% endraw %}
{% if totalPrice <= 30 %}
You’re just {{{30 | minus: totalPrice}}} away from FREE shipping.
{% else %}
You've qualified for Free Shipping.
{% endif %}
{% raw %}
</p>
<button type="submit" class="cart__checkout" name="checkout">
{% endraw %}{{ 'cart.general.checkout' | t }}{% raw %} →
</button>
{% endraw %}{% if additional_checkout_buttons %}
<div class="additional_checkout_buttons">{{ content_for_additional_checkout_buttons }}</div>
{% endif %}{% raw %}
</div>
</form>
{% endraw %}
</script>
<script id="AjaxQty" type="text/template">
{% raw %}
<div class="ajaxcart__qty">
<button type="button" class="ajaxcart__qty-adjust ajaxcart__qty--minus icon-fallback-text" data-id="{{id}}" data-qty="{{itemMinus}}">
<span class="icon icon-minus" aria-hidden="true"></span>
<span class="fallback-text">−</span>
</button>
<input type="text" class="ajaxcart__qty-num" value="{{itemQty}}" min="0" data-id="{{id}}" aria-label="quantity" pattern="[0-9]*">
<button type="button" class="ajaxcart__qty-adjust ajaxcart__qty--plus icon-fallback-text" data-id="{{id}}" data-qty="{{itemAdd}}">
<span class="icon icon-plus" aria-hidden="true"></span>
<span class="fallback-text">+</span>
</button>
</div>
{% endraw %}
</script>
<script id="JsQty" type="text/template">
{% raw %}
<div class="js-qty">
<button type="button" class="js-qty__adjust js-qty__adjust--minus quantity-increment" data-id="{{id}}" data-qty="{{itemMinus}}">
<span>−</span>
</button>
<input type="text" class="js-qty__num" value="{{itemQty}}" min="1" data-id="{{id}}" aria-label="quantity" pattern="[0-9]*" name="{{inputName}}" id="{{inputId}}">
<button type="button" class="js-qty__adjust js-qty__adjust--plus quantity-increment" data-id="{{id}}" data-qty="{{itemAdd}}">
<span>+</span>
</button>
</div>
{% endraw %}
</script>

You wrote:
{% endraw %}
{% if totalPrice <= 30 %}
You’re just {{{30 | minus: totalPrice}}} away from FREE shipping.
{% else %}
You've qualified for Free Shipping.
{% endif %}
{% raw %}
Which is correct... if you were offering free shipping at $0.30
Shopify stores prices as integers, not floating-point-numbers - so the values in the price variables represent cents, not dollars. If you want to compare to $30.00, you'll need to compare to 3000, not 30
Also, you've put your Liquid code into a Handlebars template - Liquid is rendered server-side, so the evaluation of the cart total happens before the page is served to your client. If the shopper changes their cart total, the template does not get re-evaluated at the server level, so the message won't be dynamic.
What you should do instead is add a new variable to your template, like {{{ shippingMessageHTML }}}, then edit the script file that populates the template to have a variable with the same name.
Example:
(Note: It looks like you're using Brooklyn or one of its related themes. This theme family names the function that populates that template buildCart, which is usually found in an asset file named ajax-cart, app or theme. The extension will either be .js or .js.liquid)
Find the section of code near the bottom of the function, which should look something like this:
// Gather all cart data and add to DOM
data = {
items: items,
note: cart.note,
totalPrice: Shopify.formatMoney(cart.total_price, settings.moneyFormat),
totalCartDiscount: cart.total_discount === 0 ? 0 : {{ 'cart.general.savings_html' | t: savings: '[savings]' | json }}.replace('[savings]', Shopify.formatMoney(cart.total_discount, settings.moneyFormat))
};
At the end of that data object, add your message HTML. Example:
// Gather all cart data and add to DOM
data = {
items: items,
note: cart.note,
totalPrice: Shopify.formatMoney(cart.total_price, settings.moneyFormat),
totalCartDiscount: cart.total_discount === 0 ? 0 : {{ 'cart.general.savings_html' | t: savings: '[savings]' | json }}.replace('[savings]', Shopify.formatMoney(cart.total_discount, settings.moneyFormat)),
//Note: we added a comma after the previous line before adding this new one
shippingMessageHTML: cart.total_price < 3000 ? 'Want free shipping? It\'s only ' + Shopify.formatMoney(3000 - cart.total_price, settings.moneyFormat) + ' away!' : 'Yahoo! No pay-for-shipping for you!'
};
With that, when the data gets merged with your cart template, the most current cart total will be used in the calculation. As long as the variable you use inside the data object matches the name of the variable you set in the CartTemplate, you'll be good to go!
(If you're wondering what the difference between {{ variable }} and {{{ variable }}} is, the Handlebars template language interprets double-curly-braces as text and triple-curly-braces as HTML. So if you want to put a span or anything into your message, use triple braces. If your message will only ever be flat text, you can use either double or triple)

Related

Display Only the Most Recent Post by Category in Jekyll

I have posts within my blog that have 2 categories: project, and then whatever the name of the project is (i.e. project1 and project2). I've built out a page to display all my projects, with a loop that looks like this:
<div class="container">
{% for post in site.categories.project %}
{% assign remainder = forloop.index | modulo: 3 %}
{% if remainder == 1 or forloop.first %}
<div class="row">
{% endif %}
<div class="col-sm-4 d-flex align-items-stretch">
<div class="card" href="{{ site.baseurl }}{{ post.url }}">
<div class="m-2">
<h3>{{post.title}} {{post.categories[1]}}</h3>
{% if post.image %}
<img src="{{ post.image }}" />
{% endif %}
<p>{{post.projectInfo}}</p>
</div>
<div class="m-2 mt-auto">
{% if post.projectLink %}
Project Link |
{% endif %}
Blog Post
</div>
</div>
</div>
{% if remainder == 0 or forloop.last %}
</div>
{% endif %}
{% endfor %}
</div>
However, when I make an update to the project, I'd like to ONLY display the most recent post, and skip over all the others. I've tried assigning a variable thisProject, and then doing a limit: 1, but because I've grabbed each post already in the outermost for loop, it'll actually show multiple iterations of lastest post for the project that has multiple posts.
Any way I can better limit this?

Loop through liquid advanced custom field to return multiple metafield values

I've built the following liquid for loop to retrieve & output data from a repeating advanced custom field in Shopify. The ACF namespace is faq, and contains heading and content data. My current loop is as follows:
<div class="feed-faqs">
{% if page.metafields.faq != blank %}
{% assign faqs = page.metafields.faq %}
{% for item in faqs %}
{% assign i = forloop.index %}
<div class="item item--{{ i }}">
{{ heading[i] }}
{{ content[i] }}
</div>
{% endfor %}
{% endif %}
</div>
However, on the frontend, this loop returns the following:
<div class="feed-faqs">
<div class="item item--1">
</div>
<div class="item item--2">
</div>
</div>
Is what I'm trying to achieve (to output multiple values from a repeating ACF field) possible with this approach, and if so, where have I gone wrong in fetching the header & content data?
Worked it out, so leaving this answer for anyone else in the future:
<div class="feed--faqs">
{% if page.metafields.faq != blank %}
{% assign faqs = page.metafields.faq.heading %}
{% for value in faqs %}
{% assign i = forloop.index0 %}
<div class="item item--{{ i }}">
<h4>{{ page.metafields.faq.heading[i] }}</h4>
<p>{{ page.metafields.faq.content[i] }}</p>
</div>
{% endfor %}
{% endif %}
</div>
Metafield value type is set to 'Json String'.
For reference, I'm using the ArenaCommerce Advanceds Custom Fields app: https://apps.shopify.com/advanced-custom-field.

Product Image in mega menu

I am build a megamenu in Shopify that will show a mix of collection image, product images and a generic image for any other link that might be in there.
Currently the collection image displays fine and the generic image, but having some trouble getting the product image to display. My code for the mega menu is show below:
<ul class="megaMenu">
<div class="megaMenuWrapper">
{% for child_link in link.links %}
<li {% if child_link.active %}class="active {% if child_link.child_active %}child-active{% endif %}"{% endif %}>
<a href= "{{ child_link.url }}">
{% if child_link.type == "collection_link" and child_link.object.image %}
<div class="menuImage" style="background-image: url('{{ child_link.object.image | img_url: '500x' }}')"></div>
{% elsif child_link.type == "product_link" and child_link.object.image %}
<div class="menuImage" style="background-image: url('{{ child_link.object.image | img_url: '500x' }}')"></div>
{% else%}
<div class="menuImage" style="background-image: url('https://cdn.shopify.com/s/files/1/0924/5464/files/map_macarons_paris.jpg?1158498038497005180')"></div>
{% endif %}
<span>{{ child_link.title }}</span>
</a>
</li>
{% endfor %}
</div>
</ul>
Any ideas on what might be wrong are welcome.
Products doesn't have an image object, it has a featured_image or images.
So you should call {{ child_link.object.featured_image | img_url: '500x' }} instead.
The same applies for your if check where you check if the image is present.

Liquid nesting For-Loop Syntax issue in Jekyll

First time posting, so thanks in advance for your time c:
I'm using Jekyll to serve a portfolio. I'm using a portfolio plugin as well as a JS library called Lightbox. I have the portfolio plugin working. The ideal action is that every time the user clicks a portfolio item, it executes the lightbox (that's working). In order to for more images to be stored in the lightbox, I must give them the same data-title name.
My understanding is that I need to nest a for-loop within my current loop, to check for all items within the array to return any additional lightbox items.
My .yml file reads like so:
title: Portfolio Title
description: A crazy portfolio item
bg-image: Test-01.png
lb-images:
- Test-01.png
- Test-02.png
- Test-03.png`
My .md file reads like so:
<div class="flex-container">
<!-- portfolio-item -->
{% assign projects = site.data.projects | get_projects_from_files | sort:'date' %}
{% for project in projects reversed %}
<div class="flex-item" style="background-image: url(/img/projects/{{ project.bg-image }}); background-repeat: no-repeat">
<a href="../images/projects/{{ project.lb-images[0] }}" data-lightbox="{{ project.title }}" data-title="{{ project.bg-image }}">
<div id="overlay">
<span id="reveal-text">
<h3>{{ project.title }}</h3>
<p>{{ project.description }}</p>
<p>{{ project.category }}</p>
</span>
</div>
</a>
</div>
{% for project in projects %}
{% endfor %}
{% endfor %}
</div>
I assumed that the forloop.index would begin at [1] and then continue through that array until there are no more lb-images. But something's up. My guess is syntax or how I'm calling the data from the .yml file, or both.
Again thanks for your time.
Daniel
(edit: took out space in nested endfor loop, runs now but returns: href="../images/projects/] }}" and data-title and data-lightbox returns are for each data.project file instead of for each item in data.project.lb-images)
Correct loop to expose images for a project is:
{% assign projects = site.data.projects | get_projects_from_files | sort:'date' %}
<div class="flex-container">
{% for project in projects reversed %}
<!-- portfolio-item -->
<div class="flex-item" style="background-image: url(/img/projects/{{ project.bg-image }}); background-repeat: no-repeat">
<a href="../images/projects/{{ project.lb-images[0] }}" data-lightbox="{{ project.title }}" data-title="{{ project.bg-image }}">
<div id="overlay">
<span id="reveal-text">
<h3>{{ project.title }}</h3>
<p>{{ project.description }}</p>
<p>{{ project.category }}</p>
</span>
</div>
</a>
</div>
{% for img in project.lb-images %}
{% if forloop.first != true %}
{% endif %}
{% endfor %}
{% endfor %}
</div>
Liquid forloop documentation

How to hide unavailable product variants in Shopify?

I'm trying to make only the available product variants visible in drop downs for products like this one. For example, say you choose 2012 in the first drop down, it would only show the available choices in the second. If you then chose Wed 25th July in the second, it would only show the available variants in the third. At the minute it shows all choices and states 'We don't offer the product in this combination' for an unavailable choice.
So far, my product.liquid page has this code:
<div class="col-7 product-description clearfix">
<h1>{{ product.title }}</h1>
{{ product.description }}
{% include 'addthis' %}
<br/><br/>
{% if product.available %}
{% if product.variants.size > 1 %}
<!-- If the product only has MULTIPLE OPTIONS -->
<form action="/cart/add" method="post" class="product-variants">
<div id="options">
<select id="product-select" name='id'>
{% for variant in product.variants %}
<option value="{{ variant.id }}">{{ variant.title }}</option>
{% endfor %}
</select>
<div class="select-wrapper">
<label for="region">DVD Region</label>
<select id="color" required>
<option value="NTSC">NTSC</option>
<option value="PAL/SECAM" selected="selected">PAL/SECAM</option>
</select>
</div>
<p>Click Here find out more about your region.</p>
</div> <!-- options -->
<div class="price-field"></div>
<input type="submit" name="add" value="Add to cart" id="purchase" />
</form>
{% else %}
<!-- If the product only has ONE variant -->
<form action="/cart/add" method="post" class="product-variants">
<div class="price-field"> {{ product.price | money }}</div>
<input type="submit" name="add" value="Add to cart" id="purchase" />
<input type="hidden" id="{{ variant.id }}" name="id" value="{{ product.variants[0].id }}" /> <!-- passes variant id -->
</form>
{% endif %}
{% else %}
<p>This product is not available</p>
{% endif %}
</div><!-- .col-7 -->
<div class="col-5 last product-thumbs">
<ul>
{% for image in product.images %}
{% if forloop.first %}
<li class="featured-image" >
<a class="zoom " href="{{ image | product_img_url: 'large' }}" title="{{ product.featured_image.alt | escape }}">
<img src="{{ image | product_img_url: 'large' }}" alt="{{ product.featured_image.alt | escape }}" />
</a>
</li>
{% else %}
<li>
<a class="zoom" href="{{ image | product_img_url: 'large' }}" title="{{ image.alt | esacpe }}">
<img class="" src="{{ image | product_img_url: 'small' }}" alt="{{ image.alt | escape }}" />
</a>
</li>
{% endif %}
{% endfor %}
</ul>
</div><!-- .col-5 -->
<script type="text/javascript">
// <![CDATA[
var selectCallback = function(variant, selector) {
if (variant && variant.available == true) {
// selected a valid variant
jQuery('#purchase').removeClass('disabled').removeAttr('disabled'); // remove unavailable class from add-to-cart button, and re-enable button
jQuery('#purchase').fadeIn();
jQuery('.price-field').html(Shopify.formatMoney(variant.price, "{{shop.money_with_currency_format}}")); // update price field
} else {
// variant doesn't exist
jQuery('#purchase').addClass('disabled').attr('disabled', 'disabled'); // set add-to-cart button to unavailable class and disable button
jQuery('#purchase').fadeOut();
var message = variant ? "Sold Out" : "We don't offer the product in this combination";
jQuery('.price-field').text(message); // update price-field message
}
};
// initialize multi selector for product
jQuery(document).ready(function() {
new Shopify.OptionSelectors("product-select", { product: {{ product | json }}, onVariantSelected: selectCallback });
{% assign found_one_in_stock = false %}
{% for variant in product.variants %}
{% if variant.available and found_one_in_stock == false %}
{% assign found_one_in_stock = true %}
{% for option in product.options %}
jQuery('.single-option-selector:eq(' + {{ forloop.index0 }} + ')').val({{ variant.options[forloop.index0] | json }}).trigger('change');
{% endfor %}
{% endif %}
{% endfor %}
$('#options div').addClass("selector-wrapper");
{% if product.options.size == 1 %}
$(".selector-wrapper").append("<label>{{ product.options.first }}</label>");
{% endif %}
});
// ]]>
</script>
Any help?

Resources