how to get url parameters using shopify liquid? - shopify

I have a landing page that contains the add to cart button with the product handle like this:
shopifystorename.com/some-product-handle
What I want is to redirect automatically or the product be added automatically to the shopify cart if the user lands on that url above. I've tried using JS:
let m = window.location.href;
var n = m.lastIndexOf('/');
var result = m.substring(n+1);
console.log(result);
var span = document.getElementById("handle");
span.textContent = result;
And capture it on shopify liquid like so:
{% capture my_variable %}<span id="handle">test</span>{% endcapture %}
{{ my_variable }}
{{ all_products[my_variable].title }}
But I'm not getting the value or it is not updated.

It won't work. Liquid is for server-side rendering engine and JS is for frontend. You'll need to purely use Javascript here to make use of AJAX API of Shopify and in a more refined and simple way.
var thisProduct = await fetch('/products/'+ location.pathname +'.js').then(p => { return p.json(); });
alert('The title of this product is ' + thisProduct.title);

Related

Hiding elements when cart is empty in Shopify

In order to hide a line of text on an empty cart I tried
{% if cart.item_count > 0 %} your html here {% endif %}
This seems to work because it does when the cart starts out empty. But I assume the page is not refreshing during add to cart (That seems to be the case if a theme using ajax add to cart functionality.)
I wonder what I need to do in order to make it work anyway?
Yes, liquid is a server-side rendered language. There is nothing you can do in liquid to update the page after an ajax call.
The only way is Javascript.
When you do the ajax call, your should be calling the cart.js or add.js or update.js endpoints, in these cases you receive an object with an array: items.
You need to check (in Javascript) if responseData.items.length>0 to see if there are items in the cart.
To make an example, this is your .liquid.
{% if cart.item_count > 0 %}
<div id="#mycart">...</div>
{% endif %}
Now in your javascript code, you might have something like
$.ajax({
type: 'POST',
url: '/add.js',
data: payload,
dataType: 'json',
success: function (data) {
if (data["item_count"] === 0) {
$("#mycart").hide();
}else{
$("#mycart").show();
}
},
error: function () {
handleError();
}
});
I'm using jQuery, but is just to give you the idea.

Disable checkout if all products do not share same tag Shopify

I have a custom checkout experience in my Shopify store that I only want to allow if all products in the cart contain the tag "test"
This is the function I currently have, which seems to only work with a single item in the cart.
function productTags() {
{%- assign tagEnabled = false -%}
return {
{%- for item in cart.items -%}
{%- if item.product.tags contains 'test' -%}
"{{ item.product.tags }}": {{ item.quantity | json }}
{%- assign tagEnabled = true -%}
{%- endif -%}
{%- endfor -%}
};
}
this line ( "{{ item.product.tags }}": {{ item.quantity | json }}) is only there for display in the console when testing this. I can remove that if necessary.
How can I expand this to look for all item tags in the cart, and only assign the tagEnabled variable to true if all of them have the same tag?
Thanks in advance!
It looks like you are trying to mix Liquid with Javascript, which can make coding confusing. I would recommend splitting your code into two parts: one where you collect your Liquid variables and assign them to Javascript variables (and I see you are using the json filter to do that already, which is awesome - that filter guarantees that your variable output will be in a Javascript-legal format), and the second part where you write your Javascript code without any Liquid brackets getting in the way. (This is especially helpful if you are using a code editor with any syntax or error highlighting)
Let me know if the following helps you get the information you need:
// The Liquid filter 'map' lets you drill into nested object properties. We can use this to get an array of tag arrays.
// The JSON Liquid filter will turn any Liquid variable into a legal Javascript variable.
const itemProductTags = {{ cart.items | map: 'product'| map: 'tags' | json }}
// Check on our variables
console.log('All product tag arrays', itemProductTags)
console.log('Results of tagCheck()', tagCheck(itemProductTags, 'test') )
function tagCheck(tagsList, targetTag){
// Checks to see if the targetTag appears in all, some or none of the tag arrays.
// tagsList will be an array of arrays
var targetInAny = false;
var targetInAll = true;
for(var i=0; i<tagsList.length; i++){
var tags = tagsList[i];
if(tags.indexOf(targetTag) != -1){
// Found the tag - this targetTag appears in at least one product-tag list
targetInAny = true;
}
else{
// Did not find the tag - this targetTag is NOT in every product-tag list
targetInAll = false;
}
}
// Returns an object specifying if we found the target in any, all or none of the lists
return { targetInAny: targetInAny, targetInAll: targetInAll, targetInNone: !targetInAny }
}

Passing {{raw}} variable to snippet - Shopify

I have created a simple AJAX request which feeds back to the header template. However, I can not seem to be able to do any of the following assign, capture, render, include.
<script id="CartPopover" type="text/x-handlebars-template">
{% raw %}
{{#items}}
{% render "cart-item", item: item %}
{{/items}}
{% endraw %}
</div>
Update
I am attempting to update the sliding side cart on the website when a product is added to cart. Please see the ajax, /cart/add.js success
function below.
var showCartNotificationPopup = function (product) {
var addedQuantity = parseInt($('.quantity__input', this.$container).val());
$.get("/cart.json", function (data) {
var cart_items = data.items
$.each(cart_items, function (index, item) {
item.minus_quatinty = item.quantity - 1;
item.formatPrice = Shopify.formatMoney(item.final_price)
})
cart = {
items: data.items
}
$("#side-cart-container").find(".item").detach();
$("#CartOuter table tbody").prepend(template(cart));
console.log(cart);
$("#side-cart-container").addClass("visible");
});
clearTimeout(popoverTimer);
}
You are misunderstanding how Shopify works. Liquid code is parsed once by Shopify when a page is loaded. Shopify creates a huge string of HTML, CSS and JS and dumps it into the browser.
Once you are in the land of Javascript, you no longer play with Liquid. Instead, you play with data. So, if you want to update the cart, you use Javascript. If you want to know what is in the cart, you use Javascript. If you want to re-render the contents of the cart, you replace the DOM you no longer like with new DOM. Use Javascript templates for this.
No amount of Liquid in your JS will help you except during render time. At render time, you can certainly build and fill a Javascript data structure with data from Liquid.

Use js variable with Shopify liquid tag

Currently in Shopify we can create a file.js.liquid which grants access to liquid functionality.
<script>
var liquidData = {
myValue: {{ product.image | asset_url }}
}
</script>
How can I use a variable in the placeme of product.image?
In example:
var myVar = 'something.jpg'
var liquidData = {
myValue: {{ myVar | asset_url }}
}
Currently this does not work for me the path it out puts is myVar as a string not as a variable. I also tried concatenation and it also reads the variable name as a string. Any ideas?
You must remember that liquid is executed before the DOM. This applies to Javascript files as well.
The liquid code is executed before the JS file is processed so when you create a JS variable and try to pass it to liquid is not possible since liquid finished it's execution long before the Javascript started to execute.
So to sum it up you can't pass anything from the Javascript ot Liquid, but the other way is possible.
So back to your question.
It should look like so:
{% assign myVar = 'something.jpg' %}
var liquidData = {
myValue: "{{ myVar | asset_url }}"
}

Shopify Hide Best Sellers

I'm trying to hide access from competition viewing the best-sellers, specifically using a URL like this:
www.store.myshopify.com/collections/all?sort_by=best-selling
I've tried {% if collection.url contains 'sort_by=best-selling' %} but that doesn't work. Is there any way to target a URL with an attached query string?
If not, any suggestions?
Thanks!
Unfortunately collection.url doesn't return the query string, in your example, it would output /collections/all
I don't think there's a way in Liquid to get the current url query string. You can only set the default sort type with collection.default_sort_by : 'price'
Or to override all sorting with {% assign products = collection.products | sort: 'price' %}
You can override the sort_by query string parameter using jQuery to substitute best-selling by price:
<script type="text/javascript">
$.urlParam = function(name){
var results = new RegExp('[\?&]' + name + '=([^&#]*)').exec(window.location.href);
return results[1] || 0;
}
var sort_by = $.urlParam('sort_by');
if(sort_by == "best-selling") {
var url = window.location.href;
url = url.replace("best-selling", "price"); // override to sort by price
window.location.href = url; // redirect to url
}
<script>
Using this code with your example, it would automatically redirect the page www.store.myshopify.com/collections/all?sort_by=best-selling to www.store.myshopify.com/collections/all?sort_by=price
But keep in mind that your competitors could disable that JS code and still access the best-selling items.