Google Tag Manager Data Layer Variable undefined - Shopify - shopify

I'm using Shopify variables to try and push data through the Data Layer to use in Schema on particular pages. I used a Snippet to do this:
<!-- GTM Product Information via Data Layer -->
{% if product.url contains 'products' %}
{%- assign current_variant = product.selected_or_first_available_variant -%}
<script>
window.dataLayer = window.dataLayer || [];
window.dataLayer.push({
'gtm_product_url': '{{ product.url }}',
'gtm_product_title' : '{{ product.title }}',
'gtm_product_image' : '{{ product.featured_image }}',
'gtm_product_description' : '{{ product.description | strip_html | strip_newlines | replace: '"', '' }}',
'gtm_date' : '{{'now' | date: '%Y-%m-%d' }}',
'gtm_sku' : '{{ current_variant.sku }}'
});
</script>
{% endif %}
{% if page.url contains 'pages' %}
<script>
window.dataLayer = window.dataLayer || [];
window.dataLayer.push({
'gtm_page_title': '{{ page.title }}',
'gtm_page_published': {{ page.published_at }},
'gtm_page_image' : {{ page_image | img_url }},
'gtm_page_description' : {{ page_description }}
});
</script>
{% endif %}
I added the Variables in Google Tag Manager. The data shows up on the pages just fine (using the Shopify variables). And the product pages are actually pushing the data to GTM.
My problem is with the 'pages'. I see the data on the pages from Shopify and I've added the Variables into GTM, but they all show undefined when I try to add them to GTM.
I'm not sure what I'm doing wrong though. Any insights would be greatly appreciated!

You code works fine, but in case you had not noticed, you have not enclosed the values in quotes for the page section. You existing code without quotes throw
Uncaught SyntaxError: Unexpected token ':'
Wrapping quotes, it should work fine.
{% if page.url contains 'pages' %}
<script>
window.dataLayer = window.dataLayer || [];
window.dataLayer.push({
'gtm_page_title': "{{ page.title }}",
'gtm_page_published': "{{ page.published_at }}",
'gtm_page_image' : "{{ page_image | img_url }}",
'gtm_page_description' : "{{ page_description }}"
});
</script>
{% endif %}
Moreover, console.log values for testing to see if you are receiving the expected values.

Related

Shopify: Display discount codes in new order email template

I want to display discount codes in new order email notification template, using this code:
{% for discount in discounts %}
{{ discount.code }} : {{ discount.savings | money_with_currency }}
{% endfor %}
It's displaying the discount amount but not the discount code name/title. It's returning blank even if the discount is manually entered in the back-end when creating an order.
How can I display discount codes no matter where it's entered i.e in admin or checkout?
In notifications you may access to discount_application object as explained here:
https://shopify.dev/docs/themes/liquid/reference/objects/discount-application
So (not tested), something like that might work:
{% for discount_application in discount_applications %}
{{ discount_application.title }} : {{ discount_application.value }}
{% endfor %}
HTH
You can get it from your cookies:
<div id="discount-message"></div>
<script type="text/javascript">
var codeCookieValue;
var getCookie = function(name) {
var value = "; " + document.cookie;
var parts = value.split('; '+name+'=');
if (parts.length == 2) return parts.pop().split(";").shift();
};
codeCookieValue = getCookie('discount_code');
</script>

Product Price % OFF not changing with selected variant

Please help me to resolve this code. I have some % off discount to show based on the variant choose, its not getting changed on clicking on pack of 2 and pack of 3, as we have different % in discounts. This is my shopify product url https://us.buywow.com/products/wow-apple-cider-shampoo-cocounut-oil-conditioner-set-500ml
Callback function is written, but I am not understanding why its not changing
Product.liquid
<!-- /templates/product.liquid -->
{% assign on_sale = false %}
{% if product.compare_at_price > product.price %}
{% assign on_sale = true %}
{% endif %}
.
.
.
.
{% comment %}
------ Product Price ------
{% endcomment %}
<div class="product_prices">
<span class="visually-hidden">{{ 'products.general.regular_price' | t }}</span>
<h4 id="ProductPrice" class="product-regular-price" itemprop="price" content="{{ current_variant.price | divided_by: 100.00 }}">
{{ current_variant.price | money }}
</h4>
<span class="old-price">{{ current_variant.compare_at_price | money }}</span>
{% if on_sale %}
<div class="save_money_block">
<span class="save_off">
{% if current_variant.compare_at_price > current_variant.price %}
{{ current_variant.compare_at_price | minus: current_variant.price | times: 100.0 |
divided_by: current_variant.compare_at_price | money_without_currency | times: 100
| replace: '.0', ''}}% OFF{% endif %}
</span>
</div>
{% endif %}
</div>
.
.
.
.
.
<script>
(function(s3d) {
if (!s3d) {
console.warn('"window.Shopify3d" does not exist. Please ensure you\'ve added the <script> to your theme');
return;
}
{% for variant in product.variants %}
s3d.mapMetafieldAssets('{{ variant.id }}', '{{ variant.metafields.shopify3d['assets'] }}');
{% endfor %}
})(window.Shopify3d);
</script>
<script>
var selectCallback = function(variant, selector) {
timber.productPage({
money_format: "{{ shop.money_format }}",
variant: variant,
selector: selector
});
};
</script>
On selecting Pack Of 3 - 60% OFF should be the resultant.
that is not happening auto refresh.
Remember that Liquid is compiled server-side before the document is sent to the client's browser, so the result is not dynamic and will not be able to automatically update when a variant is selected.
In order to make the percent-off part change appropriately when the selections change, you will need to add javascript code that will run whenever the variant selection changes. Fortunately, you already have a function that will do that, in your theme it happens to be called selectCallback, which then calls a function called timber.productPage to do all the heavy lifting.
You will want to update either selectCallback or timber.productPage with the javascript code needed to update your percent-off field. (The latter is probably the better option in your case, as that would keep all of the relevant price-display-updating code close together.) The variant parameter will either be the currently-selected variant or undefined if the current option selections do not match any of the variants in the product; the selector parameter will contain a lot of generally-useful information, such as the parent product object.
Hope this helps!
In the selectCallback function add next code:
<script>
var selectCallback = function(variant, selector) {
var $discount = $('#offpercent'),
$productPrice = $('#productPrice'),
$comparePrice = $('#comparePrice');
alert(Shopify.formatMoney(variant.price, Shopify.money_format));
alert(Shopify.formatMoney(variant.compare_at_price, Shopify.money_format));
var percDiff = Math.round((variant.compare_at_price-variant.price)/variant.compare_at_price * 100);
alert(percDiff);
$discount.html(percDiff);
};
</script>

Shopify Palo Alto Theme; Attempting to include an 'Add To Cart' in product-grid-item

I know that Timber/Palo Alto is no longer supported but I am working on an old account that uses it and am not familiar with the theme.
I have been able to create a button that adds an item to a cart but after clicking add to cart it redirects to the cart page, I just want to add the item and allow the user to still browse the collection.
Any suggestions will be helpful, Thank you in advance
<!-- /snippets/product-grid-item.liquid -->
<form action="/cart/add" data-productid="{{product.id}}" method="post" enctype="multipart/form-data" id="AddToCartForm--{{section.id}}">
<div class = "variants-wrapper">
{% if variants_count > 1 %}
<select name="id" data-productid="{{product.id}}" id="productSelect--{{section.id}}" class="product-single__variants">
{% for variant in product.variants %}
{% if variant.available %}
<option {% if variant == product.selected_or_first_available_variant %} selected="selected" {% endif %} data-sku="{{ variant.sku }}" value="{{ variant.id }}">{{ variant.title }} - {{ variant.price | money_with_currency }}</option>
{% else %}
<option disabled="disabled">
{{ variant.title }} - {{ 'products.product.sold_out' | t }}
</option>
{% endif %}
{% endfor %}
</select>
{% else %}
<input name="id" data-productid="{{product.id}}" type="hidden" value="{{ product.variants[0].id }}">
{% endif %}
{% if sold_out %}
<input type="hidden" type="text" id="Quantity1" name="quantity" value="0" min="0" class="quantity-selector quantity-input">
<a class="btn" href="{{ product.url | within: collection }}">{{ 'products.product.view_item' | t }}</a>
{% else %}
<div class="qtydiv">
<input type="text" id="Quantity1" name="quantity" value="1" min="1" class="quantity-selector quantity-input">
</div>
<button type="submit" name="add" id="AddToCart" class="btn" style="display: inline">
<span id="AddToCartText">{{ 'products.product.add_to_cart' | t }}</span>
</button>
{% endif %}
</div>
</form>
ajax-cart.js.liquid
ShopifyAPI.addItemFromForm = function(form, callback, errorCallback) {
var params = {
type: 'POST',
url: '/cart/add.js',
data: jQuery(form).serialize(),
dataType: 'json',
success: function(line_item) {
if ((typeof callback) === 'function') {
callback(line_item, form);
}
else {
ShopifyAPI.onItemAdded(line_item, form);
}
},
error: function(XMLHttpRequest, textStatus) {
if ((typeof errorCallback) === 'function') {
errorCallback(XMLHttpRequest, textStatus);
}
else {
ShopifyAPI.onError(XMLHttpRequest, textStatus);
}
}
};
jQuery.ajax(params);
};
This redirects to cart page, because that is how form action value is defined. So if you want to add it without page redirect and reload, use Shopify AJAX API that allows you manage CRUD operations on cart. Shopify AJAX API.
In the above scenario, you need to have a look at Add to Cart functionality.
Post Data
{
quantity: 2,
id: 794864229
}
Sample Code
// Send a seralized form
jQuery.post('/cart/add.js', $('form[action="/cart/add"]').serialize());
// or construct post data
jQuery.post('/cart/add.js', {
quantity: 1,
id: 794864229,
properties: {
'First name': 'Caroline'
}
});
Another approach that is a bit easy to implement is to use CartJS
So using data API, it would just be
<button data-cart-add="12345678">Add Product</button>
Sample implementation on Timber Shopify theme
in theme.liquid after timber.js load CartJS
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/shopify-cartjs/0.4.1/cart.min.js"></script>
Then below that in the jQuery ready function, initialize CartJS
CartJS.init({{ cart | json }}, {
"dataAPI": true
});
The add this code in product-grid-item.liquid
<button data-cart-add="{{ product.variants.first.id }}">Add Product</button>
This is working on my test installation of Timber theme.

Shopify variant swatches or radio buttons instead of dropdowns in Slate

Shopify's tutorial for color swatches isn't supported yet for Slate,
and the select callback referenced no longer exists in the code base. Is it possible to modify this tutorial to work on Slate themes to create radio buttons or swatches instead of a dropdown for selecting variants on the product template?
Yes. I was able to get this tutorial to work by modifying the code slightly. This workaround is only going to be relevant until the shopify tutorial is updated to correspond to Slate.
Follow the tutorial as per the directions.
When you get to the step "Locate your selectCallback function",
you will notice there is no selectCallback function in Slate. Yikes!
Instead find "_onSelectChange" in theme.js and add the code there.
This is the final function with the swatches code added:
/**
* Event handler for when a variant input changes.
*/
_onSelectChange: function() {
var variant = this._getVariantFromOptions();
this.$container.trigger({
type: 'variantChange',
variant: variant
});
if (!variant) {
return;
}
// BEGIN SWATCHES
var selector = this.originalSelectorId;
if (variant) {
var form = $(selector).closest('form');
for (var i=0,length=variant.options.length; i<length; i++) {
var radioButton = form.find('.swatch[data-option-index="' + i + '"] :radio[value="' + variant.options[i] +'"]');
if (radioButton.size()) {
radioButton.get(0).checked = true;
}
}
}
// END SWATCHES
this._updateMasterSelect(variant);
this._updateImages(variant);
this._updatePrice(variant);
this.currentVariant = variant;
if (this.enableHistoryState) {
this._updateHistoryState(variant);
}
},
Then, once you've completed the tutorial, you will notice it's still not working. This is because the code you add to theme.liquid uses a class that is no longer on your variant Selects.
On product.liquid (this is a Section on most Slate themes) Add the class "single-option-selector" to your selects, like so:
{% unless product.has_only_default_variant %}
{% for option in product.options_with_values %}
<div class="selector-wrapper js">
<label for="SingleOptionSelector-{{ forloop.index0 }}">
{{ option.name }}
</label>
<select
id="SingleOptionSelector-{{ forloop.index0 }}"
class="single-option-selector"
data-single-option-selector
data-index="option{{ option.position }}">
{% for value in option.values %}
<option value="{{ value | escape }}"
{% if option.selected_value == value %}selected="selected"{% endif %}>
{{ value }}
</option>
{% endfor %}
</select>
</div>
{% endfor %}
{% endunless %}
Now, the tutorial should work as it's supposed to. I hope this helps someone out!

Shopify: issue with url image in linklists

i'm pretty new to Shopify and I'm facing a strange issue in linklists.
Yesterday I changed the featured image for a category I displayed into a linklist, but I cannot see the changes in the page that prints the linklist.
I analyze the .liquid file that prints the linklists and I found the snippet that produces the divs:
{% for link in linklists[linklist].links cols: 4 %}
<div class="products item {{ link.handle }}">
<a href="{{ link.url }}" title="Browse our {{ link.object.title | escape }} collection.">
<img src="{{ link.object.image.src | collection_img_url: 'large' }}" alt="{{ link.object.title | escape }}" />
<big>{{ link.title }}</big>
</a>
</div>
{% endfor %}
After some shots I tried to add a data attribute to the image to print again the link.object.title:
{% for link in linklists[linklist].links cols: 4 %}
<div class="products item {{ link.handle }}">
<a href="{{ link.url }}" title="Browse our {{ link.object.title | escape }} collection.">
<img src="{{ link.object.image.src | collection_img_url: 'large' }}" alt="{{ link.object.title | escape }}" data-test="{{ link.object.image.src | collection_img_url: 'large' }}" />
<big>{{ link.title }}</big>
</a>
</div>
{% endfor %}
The strange fact is that it prints two different values for the same object!
<img src="https://cdn.shopify.com/s/files/1/0407/7545/files/trousers-woman_c4633f02-59f7-4a4b-809b-91662635ddc0.jpg?22734" alt="Women's Trousers" data-test="//cdn.shopify.com/s/files/1/0407/7545/collections/DSC_9685_grande_df826b7f-5645-4491-b866-8819c9ad8983_large.jpg?v=1429273629">
The src attribute shows the old image, and the test attribute shows the new one.
Is that because Shopify postprocess the src attributes of the image for caching them into their cdn? How can I fix this?
thanks to #Jason input I found a javascript script that changed the attribute "src" of the image:
$('.collection-woman .webshop .trousers a img').attr('src','https://cdn.shopify.com/s/files/1/0407/7545/collections/DSC_9685_grande_df826b7f-5645-4491-b866-8819c9ad8983_large.jpg?v=1429273629');