I am trying to figure out a way to automatically rename the size variants "Small" "Medium" "large" "x-large" "xx-large" "xxx-large", to "S" "M" "L" "XL "XXL" .. etc.
The reason why I want to rename the size variants is because of the amount of extra space that is being taken up.
I am creating products from an app that doesn't let me change the name of the size variants prior to creating the products in shopify. It wouldn't make sense to manually go and change each product's variant titles because it's not time efficient.
I'm thinking the best way to do this is by using Javascript, but I don't know exactly how to go about doing this so it doesn't break anything.
Here is an example of the HTML source code of the Medium size variant.
<div data-value="Medium" class="swatch-element medium-swatch available"> <label for="swatch-1-medium-286472667159">
Medium <span class="crossed-out"></span></label></div>
Liquid Source for the swatches.
<div class="swatch clearfix" data-option-index="{{ option_index }}">
<div class="option_title">{{ swatch }}</div>
{% assign values = '' %}
{% for variant in product.variants %}
{% assign value = variant.options[option_index] %}
{% unless values contains value %}
{% assign values = values | join: ',' %}
{% assign values = values | append: ',' | append: value %}
{% assign values = values | split: ',' %}
<input id="swatch-{{ option_index }}-{{ value | handle }}-{{ product.id }}" type="radio" name="option-{{ option_index }}" value="{{ value | escape }}"{% if forloop.first %} checked{% endif %} />
<div data-value="{{ value | escape }}" class="swatch-element {% if is_color %}color {% endif %}{{ value | handle }}-swatch {% if variant.available %}available{% else %}soldout{% endif %}">
{% if is_color %}
<div class="tooltip">{{ value }}</div>
{% endif %}
{% if is_color %}
<label for="swatch-{{ option_index }}-{{ value | handle }}-{{ product.id }}" style="background-image: url({{ value | handle | append: '.' | append: file_extension | asset_img_url: '50x' }}); background-color: {{ value | split: ' ' | last | handle }};">
<span class="crossed-out"></span>
</label>
{% else %}
<label for="swatch-{{ option_index }}-{{ value | handle }}-{{ product.id }}">
{{ value }}
<span class="crossed-out"></span>
</label>
{% endif %}
</div>
{% endunless %}
{% endfor %}
</div>
As the workaround, I can suggest you this way:
Export products from Shopify in plain CSV
Open CSV file in excel
Rename all size variants in excel with "find and replace"
Import again into Shopify (make sure, you selected Overwrite existing products that have the same handle)
Related
I have created a gift note functionality which store notes but the problem is it is showing title on orders even though textarea is blank could you please help to get rid of this problem
if textarea is blank still order page is showing "cart note:"
{% if line_item.properties != empty %}
<ul class="CartItem__PropertyList">
{% for property in line_item.properties %}
{% assign first_character_in_key = property.first | truncate: 1, '' %}
{% if property.last == blank or first_character_in_key == '_' %}
{% continue %}
{% endif %}
<li class="CartItem__Property">{{ property.first }}: <p class="cart_note_txt">{{ property.last }}</p></li>
{% endfor %}
</ul>
{% endif %}
<textarea class="gift_note_pro" maxlength="300" name="properties[Cart Note]" style="display:none;" placeholder="Add a note">
</textarea>
Can someone help me to get rid of this problem ?
I want to connect my option value to my swatches like when I click the variant swatches the option value will change also.
Example when I click on the swatches[circle color] dropdown options will change also.
image sample
Here's my code below and site link:
https://strokes-test.myshopify.com/collections/frontpage
and Im using JQuery v1.8.1
HTML
<form action="/cart/add" method="post">
{% if product.variants.size == 1 %}
<input type="hidden" name="id" value="{{ product.variants[0].id }}" />
{% else %}
<select name="id">{% for variant in product.variants %}<option value="{{ variant.id }}">{{ variant.title }}</option>{% endfor %}</select>
{% endif %}
<ul class="item-swatch color_swatch_Value">
{% for option in product.options %}
{% if option == 'Shades' %}
{% assign index = forloop.index0 %}
{% assign colorlist = '' %}
{% assign color = '' %}
{% for variant in product.variants %}
{% capture color %}
{{ variant.options[index] }}
{% endcapture %}
{% unless colorlist contains color %}
{% assign text = color | handleize %}
<li>
<label value="{{ variant.id}}" style="{% if text == 'white' %}border: 1px solid #cbcbcb; {% endif %}background-color: {{ color | split: ' ' | last | handle }}; background-image: url({{ text | append: '.png' | file_url }});"></label>
{% if variant.image != null %}
<div class="hidden">
<img src="{{ variant.image.src | product_img_url: 'grande' }}" alt="{{ text }}"/>
</div>
{% endif %}
</li>
{% capture tempList %}
{{ colorlist | append: color | append: ' ' }}
{% endcapture %}
{% assign colorlist = tempList %}
{% endunless %}
{% endfor %}
{% endif %}
{% endfor %}
</ul>
<div><button type="submit" name="add">Add to cart</button></div>
</form>
JS
initColorSwatchGrid: function() {
jQuery('.item-swatch li label').click(function(){
var newImage = jQuery(this).parent().find('.hidden img').attr('src');
jQuery(this).parents('.item-row').find('.featured-image').attr({ src: newImage });
return false;
});
}
Try this one
initColorSwatchGrid: function() {
jQuery('.item-swatch li label').click(function () {
var newImage = jQuery(this).next().find('img').attr('src');
jQuery(this).parents('.product-detail').prev().find('.featured-image').attr({ src: newImage });
// JS code for product switching
jQuery(this).parents('ul.item-swatch').prev().val(jQuery(this).attr('value'));
return false;
});
}
I'm trying to validate an image URL if it exists in javascript. So I add this code in javascript which accepts a URL and returns the http status code.
function imageExists(image_url){
var http = new XMLHttpRequest();
http.open('HEAD', image_url, false);
http.send();
return http.status != 404;
}
And in the liquid template, I want to check the image URL if it exists before displaying kinda like this
<div class="variant-cat-attributes">
{% assign tags = product.metafields.product_meta.tag | split: "," %}
{% for tag in tags %}
<div class="item">
{% capture tag_slug %}{{ tag | replace: " ", "_"}}{% endcapture %}
{% assign img_png = 'tag' | append: '-' | append: tag_slug | append: '.png'%}
{% capture png_exists %}<script>imageExists({{ img_png }})</script>{% endcapture %}
{% if png_exists%}
<img src="{{ img_png | file_img_url: '32x32' }}" />
{% else %}
{% assign img_jpg = 'tag' | append: '-' | append: tag_slug | append: '.jpg'%}
{% capture jpg_exists %}<script>imageExists({{ img_jpg }})</script>{% endcapture %}
{% if jpg_exists%}
<img src="{{ img_png | file_img_url: '32x32' }}" />
{% else %}
{% assign img_default = 'tag' | append: '-' | append: 'default' | append: '.png'%}
<img src="{{ img_default | file_img_url: '32x32' }}" />
{% endif %}
{% endif %}
<p class="item-name">{{ tag | capitalize }}</p></div>
{% endfor %}
</div>
I'm just starting to understand liquid so I don't know if its correct this way. But what happens with this code is the script tag is taken up as a string and the code in it is not run
png_exists = imageExists({{ img_png }})
How do I solve this?
You are mix matching JS with Liquid, which is OK if you only pass liquid content.
At the moment liquid see your code like so:
{% capture png_exists %}<script>imageExists({{ img_png }})</script>{% endcapture %}
png_exists => <script>imageExists(http://asset_img_url.jpg)</script>
You can't execute Javascript code and expect liquid to know about it, Javascript is executed AFTER liquid, so liquid finish it's logic and Javascript will run it's code afterwards.
So you you can't use javascript functionality in liquid.
I am experimenting with creating a slideshow that has four images, for example. And the thing is I want to create a link button with its own url link for each image. But what I have done is created four link buttons that appears on the slideshow, instead of the one link button that changes along with each image, and with its own url link.
{% if settings.show_block_lookbook %}
<div id="lookbook-section" class="section-full lookbook-section">
<div class="lookbook-wrapper">
<div class="lookbook-text">
<div class="lookbook-container">
<div class="container">
<div class="lb-text">
{% assign lbText1 = settings.block_lookbook_text_1 %}
{% assign lbText2 = settings.block_lookbook_text_2 %}
{% assign lbText3 = settings.block_lookbook_text_3 %}
{% assign lbText4-1 = settings.block_lookbook_text_4_1 %}
{% assign lbText4-2 = settings.block_lookbook_text_4_2 %}
{% assign lbText4-3 = settings.block_lookbook_text_4_3 %}
{% assign lbText4-4 = settings.block_lookbook_text_4_4 %}
{% assign lbLink-1 = settings.block_lookbook_link_1 %}
{% assign lbLink-2 = settings.block_lookbook_link_2 %}
{% assign lbLink-3 = settings.block_lookbook_link_3 %}
{% assign lbLink-4 = settings.block_lookbook_link_4 %}
{% if lbText1 != blank %}<h3>{{ lbText1}}</h3>{% endif %}
<div class="bg-slider-arrows">
<span class="button-prev no-border"></span>
<span class="button-next no-border"></span>
</div>
{% if lbText2 != blank %}<h2>{{ lbText2 }}</h2>{% endif %}
{% if lbText3 != blank %}<p>{{ lbText3 }}</p>{% endif %}
{% if lbText4-1 != blank %}{{ lbText4-1 }}{% endif %}
{% if lbText4-2 != blank %}{{ lbText4-2 }}{% endif %}
{% if lbText4-3 != blank %}{{ lbText4-3 }}{% endif %}
{% if lbText4-4 != blank %}{{ lbText4-4 }}{% endif %}
</div>
</div>
</div>
</div>
</div>
<div class="lookbook-bg">
{% for i in (1..4) %}
{% assign newShow = 'block_lookbook_img_' | append: i %}
{% if settings[newShow] %}
{% assign newImage = 'block_lookbook_img_' | append: i %}
<div class="lookbook-item">
<img src = "{{ newImage | append: '.jpg' | asset_url}}" alt="" />
</div>
{% endif %}
{% endfor %}
</div>
</div>
{% endif %}
I am totally lost as to what to do, as I am very very new to this. I would think I somehow need to link the images with the urls and link buttons etc, but have no idea how to code it so that each image has its own link button and url link...Any help? Any examples?
Hold on, you are not using much of angular here. I think its django or some other template with {% if %} .
Use something like:
<div ng-repeat="object in objects">
{{object.name }}
<img src="{{ object.img_path}}" />
</div>
For look try this link for ng-repeat
For the functionality u need, I would recommend you to look into cleaner approach of Carousel
I am sort of new with Shopify and I´ve been playing around with it for the ast week or so without much success when trying to solve my issue.
I am currently using the Brooklyn template and the way they represent the Product Page doesn´t precisely give the best user experience. The way it´s representing the images by default is by having all the product variants images showed to the customer all the time even if he hasn´t actually picket that variant (i.e. a specific colour for the product). It also displays all the product images in a vertical way which makes navigation for the user quite frustrating if you have more than a couple of pictures per product variant.
I´ve found online a tutorial ( http://littlesnippets.ca/blogs/tutorials/15665261-grouping-images-with-variants )that addresses the part of my issue to hide the pictures of the variants that are not selected by the customer, and show them once the user click on it.(you can see an example of what I want here http://group-variant-images.myshopify.com/collections/frontpage/products/anson-chair ). This is more or less how it looks my site now (https://themes.shopify.com/themes/brooklyn/styles/brooklyn/preview).
The problem is that that tutorial is being applied to a website that is not using the exact theme/functionality that Ii do, although it´s similar.
I´ve failed to apply those changes to my theme, can anybody give me a hand?
This is my product.liquid piece of code at the moment:
<!-- /templates/product.liquid -->
<div itemscope itemtype="http://schema.org/Product">
<meta itemprop="url" content="{{ shop.url }}{{ product.url }}">
<meta itemprop="image" content="{{ product.featured_image.src | img_url: 'grande' }}">
{% assign current_variant = product.selected_or_first_available_variant %}
<div class="grid product-single">
<div class="grid__item large--seven-twelfths medium--seven-twelfths text-center">
<div class="product-single__photos">
{% assign featured_image = current_variant.featured_image | default: product.featured_image %}
{% comment %}
Display current variant image, or default first
{% endcomment %}
<div class="product-single__photo-wrapper">
<img class="product-single__photo" id="ProductPhotoImg" src="{{ featured_image | img_url: 'grande' }}" {% if settings.product_zoom_enable %}data-mfp-src="{{ featured_image | img_url: '1024x1024' }}"{% endif %} alt="{{ featured_image.alt | escape }}" data-image-id="{{ featured_image.id }}">
</div>
{% comment %}
Display rest of product images, not repeating the featured one
{% endcomment %}
{% for image in product.images %}
{% unless image contains featured_image %}
<div class="product-single__photo-wrapper">
<img class="product-single__photo" src="{{ image.src | img_url: 'grande' }}" {% if settings.product_zoom_enable %}data-mfp-src="{{ image.src | img_url: '1024x1024' }}"{% endif %} alt="{{ image.alt | escape }}" data-image-id="{{ image.id }}">
</div>
{% endunless %}
{% endfor %}
</div>
</div>
<div class="grid__item product-single__meta--wrapper medium--five-twelfths large--five-twelfths">
<div class="product-single__meta">
{% if settings.product_vendor_enable %}
<h2 class="product-single__vendor" itemprop="brand">{{ product.vendor }}</h2>
{% endif %}
<h1 class="product-single__title" itemprop="name">{{ product.title }}</h1>
<div itemprop="offers" itemscope itemtype="http://schema.org/Offer">
{% comment %}
Optionally show the 'compare at' or original price of the product.
{% endcomment %}
{% if product.compare_at_price_max > product.price %}
<span class="product-single__price--wrapper">
<span class="visually-hidden">{{ 'products.general.regular_price' | t }}</span>
<span id="ComparePrice" class="product-single__price--compare-at">
{% if current_variant.compare_at_price > current_variant.price %}
{{ current_variant.compare_at_price | money }}
{% endif %}
</span>
<span class="visually-hidden">{{ 'products.general.sale_price' | t }}</span>
</span>
{% endif %}
<span id="ProductPrice" class="product-single__price{% if product.compare_at_price > product.price %} on-sale{% endif %}" itemprop="price">
{{ current_variant.price | money }}
</span>
<hr class="hr--small">
<meta itemprop="priceCurrency" content="{{ shop.currency }}">
<link itemprop="availability" href="http://schema.org/{% if product.available %}InStock{% else %}OutOfStock{% endif %}">
<form action="/cart/add" method="post" enctype="multipart/form-data" class="product-single__form" id="AddToCartForm">
<select name="id" id="ProductSelect" 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>
{% comment %}
<div class="product-single__quantity">
<label for="Quantity" class="product-single__quantity-label js-quantity-selector">{{ 'products.product.quantity' | t }}</label>
<input type="number" hidden="hidden" id="Quantity" name="quantity" value="1" min="1" class="js-quantity-selector">
</div>
{% endcomment %}
<div class="product-single__add-to-cart">
<button type="submit" name="add" id="AddToCart" class="btn">
<span id="AddToCartText">{{ 'products.product.add_to_cart' | t }}</span>
</button>
</div>
</form>
</div>
<div class="product-single__description rte" itemprop="description">
{{ product.description }}
</div>
{% if settings.social_sharing_products %}
{% include 'social-sharing' %}
{% endif %}
</div>
</div>
</div>
{% if collection %}
<hr class="hr--clear">
<div class="text-center">
← {{ 'products.general.collection_return' | t: collection: collection.title }}
</div>
{% endif %}
</div>
{% comment %}
*IMPORTANT:*
This theme uses a customized version of `option_selection.js` to support using radio inputs for color and size variants. The custom version is in `variant_selection.js`.
If you wish to enable the default dropdowns for size and color
you can change the liquid asset tag below from:
{{ 'variant_selection.js' | asset_url | script_tag }}
to
{{ 'option_selection.js' | shopify_asset_url | script_tag }}
If you use the default `option_selection.js` the labels for the dropdowns will appear outside the dropdown.
You will also need to change `.radio-wrapper` to `.selector-wrapper` below.
{% endcomment %}
{{ 'variant_selection.js' | asset_url | script_tag }}
<script>
var selectCallback = function(variant, selector) {
timber.productPage({
money_format: "{{ shop.money_format }}",
variant: variant,
selector: selector,
translations: {
addToCart : {{ 'products.product.add_to_cart' | t | json }},
soldOut : {{ 'products.product.sold_out' | t | json }},
unavailable : {{ 'products.product.unavailable' | t | json }}
}
});
};
jQuery(function($) {
new Shopify.OptionSelectors('ProductSelect', {
product: {{ product | json }},
onVariantSelected: selectCallback,
enableHistoryState: true
});
// Add label if only one product option and it isn't 'Title'. Could be 'Size'.
{% if product.options.size == 1 and product.options.first != 'Title' %}
$('.radio-wrapper:eq(0)').prepend('<label for="ProductSelect-option-0" class="single-option-radio__label">{{ product.options.first | escape }} </label>');
{% endif %}
// Hide drop-down selectors if we only have 1 variant and its title contains 'Default'.
{% if product.variants.size == 1 and product.variants.first.title contains 'Default' %}
$('.selector-wrapper').hide();
{% endif %}
});
</script>
Shopify's admin interface only allows for one product image per variant. For this reason, to do what you are trying to do isn't as easy as you are hoping. Through the Shopify API you can add metafields to products and product variants and in these metafields you can store whatever information you want -- including links to additional images. Here is a link to the documentation for the metafields on variants: https://docs.shopify.com/api/reference/product_variant
Since the admin interface doesn't really give you the ability to modify the metafields directly, you have a couple of choices:
Spend the time and energy (or money) to hook up your own management tool to the API and modify it yourself.
Purchase an app from the Shopify app store that already does this for you. Here is a link to some of these apps that should guide you in the right direction: https://apps.shopify.com/search/query?utf8=%E2%9C%93&q=variant
Either way, you'll need to come up with some sort of property name convention so you know you're dealing with images because the metafields accept whatever you feel like dropping into them.
Once you are able to define the images for your product variants, then you'll need to update the logic in your liquid/javascript to accomplish the desired functionality. You can do this a few different ways, and different people will have different opinions based on SEO but my suggestion for the path of least resistance is to do something like this:
{% for v in product.variants %}
<div id="variant_{{ v.id }}">
{% for m in v.metafields %}
{% if m.key contains "WHATEVER_CONVENTION_YOU_USED_TO_DENOTE_IMAGES" %}
{% comment %}
OUTPUT THE IMAGE TAG - PROBABLY WRAPPED IN AN ANCHOR
{% endcomment %}
{% endif %}
{% endfor %}
</div>
{% endfor %}
You'll want to incorporate some logic to show and hide the div based on the variant. Note the <div id="variant_{{ v.id }}">
The reason for this approach rather than using the api to populate js objects is that your links are already in the DOM and you can create javascript handlers when the page loads. If you wait to populate your images and links until the user selects the variant, then you'll have to deal with the event handling of dynamically created nodes.
Hope all this guides you in a good direction. If you have questions or need help feel free to reach out to me via my profile.
Additional Note: Good software developers will note the O(n^2) time complexity in the code above. Shopify doesn't execute your backend code when the page loads, rather it is executed and cached when your theme is uploaded or modified. Because of this, the poor O(n^2) time complexity won't hurt your page load performance.
As a side fun fact, this is the reason Shopify cannot create Liquid tags for things like current_time or random. Their caching mechanism which keeps sites from crashing even when being presented on Shark Tank also relies on the fact that their liquid tags, filters, and blocks don't return variable results. So, they can cache the resulting HTML and serve it directly from their caching servers...thus tags like random or current_time would only ever have an opportunity to run once.
you can try variant-image-automator paid app. this hides unnecessary images from the product page.