Note: Shopify now supports multiple "traits" per product, so this technique is no longer required. Thanks for visiting though! You may want to check out my Shopify Consulting site if you are interested in customizing Shopify themes.
This page explains how I customized my Shopify site - Poetry in Flowers - by adding a color attribute to products, allowing shoppers to select their preferred color.
Before we begin
- Poetry in Flowers is based on the Vogue theme.
- This solution uses mootools - a very neat lightweight javascript library that Vogue, and other themes, use. One drawback of moo though, is that it doesn't play nice with prototype or scriptaculous. If you use a different theme, make sure those libraries are not being used.
- Although I've shown how to display a list of colors, it could be any attribute, or combination of attributes, you care to associate with a product - e.g. material choice or shirt size for example.
Step 1 - Set up your product catalog as normal.
I set up my product catalog using variants for the different sizes (and prices) of flowers being offered.
Step 2 - Mootools
This solution uses mootools. Vogue uses this by default, but you should double check that it is referenced in the header section of theme.liquid.
{{ 'mootools.js' | global_asset_url | script_tag }}
Step 3 - Product.liquid
Open up product.liquid. We will be enhancing it so it will display available colors, and save the user's selection to a cookie when they click "purchase".
At the top of the file, add the following:
<script type="text/javascript">
var colors = [];
var variants = [];
</script>
Search for where it says "{% for variant in product.variants %}" and add the following lines inside the for loop:
<script type="text/javascript">
variants.push(Json.evaluate('{"id":"{{ variant.id }}", "desc":"{{ variant.title }}"}'));
</script>
We will now add some code inside the form that will display the available colors as radio buttons:
<script type="text/javascript">
if (colors.length > 0) {
document.write("<strong><em>Available Colours</em></strong><div id=\"product-variants\"><ul>");
for (i=0; i < colors.length; i++) {
document.write("<li class='" + (i % 2 == 0 ? "odd" : "even") + "'>");
document.write("<input type=\"radio\" name=\"color\" value=\"" + colors[i] + "\" id=\"radio_color_" + i + "\"");
if (i == 0) {
document.write(" checked=\"checked\" ");
}
document.write("\"/>");
document.write(" <label for=\"radio_color_" + i + "\" class=\"radio\"><strong>" + colors[i] + "</strong></label>");
document.write("</li>");
}
document.write("</ul></div>");
}
</script>
Still in the form, find the purchase image element and add an id="purchase" attribute to it.
At the bottom of product.liquid, add the following javascript:
<script type="text/javascript">
function findVariantDesc(id) {
for (var i = 0; i < variants.length; i++) {
if (variants[i].id == id) {
return variants[i].desc;
}
}
}
function getSelectedColor() {
for (var i = 0; i < colors.length; i++) { // find selected color
var chk = $('radio_color_' + i);
if (chk && chk.checked) {
return chk.value;
}
}
}
function getSelectedVariant() {
for (var i = 0; i < variants.length; i++) { // find selected variant
var chk = $('radio_' + variants[i].id);
if (chk && chk.checked) {
return chk.value;
}
}
}
$('purchase').addEvent('click', function(evt) {
// invoked when "purchase" is clicked
if (colors.length > 0) { // any custom color options?
var variant = getSelectedVariant();
var color = getSelectedColor();
// get the product colors cookie (the cookie is session bound)
var cookie = new Hash.Cookie('product-colors', {path: '/'});
// colors are stored as an array of json tuples {product.id, product.variant, desc, color}
var ac = $defined(cookie.get('{{ product.id }}')) ? Json.evaluate(cookie.get('{{ product.id }}')) : [];
ac.push(Json.evaluate('{"id":"{{ product.id }}", "variant":"' + variant + '", "desc":"' + findVariantDesc(variant) + ' {{ product.title }}", "color":"' + color +'"}'));
cookie.set('{{ product.id }}', Json.toString(ac));
}
});
</script>
Step 4 - Cart.liquid
We will now enhance cart.liquid so that it displays the color selected by the user. I've chosen to display the colors in a dropdown so the user still has a chance to change colors if they wish.
Insert the following code just above the <form> tag:
<script type="text/javascript">
var colors = [];
var cookie = new Hash.Cookie('product-colors', {path: '/'});
function getProductColor(product, variant) {
var ac = $defined(cookie.get(product)) ? Json.evaluate(cookie.get(product)) : [];
for (i = 0; i < ac.length; i++) {
if (ac[i].variant == variant) {
return ac[i].color;
}
}
}
function remove_item(product, variant) {
var ac = $defined(cookie.get(product)) ? Json.evaluate(cookie.get(product)) : [];
var nac = [];
for (i = 0; i < ac.length; i++) {
if (ac[i].variant != variant) {
nac.push(ac[i]);
}
}
cookie.set(product, Json.toString(nac));
$('updates_'+variant).value = 0;
$('cartform').submit();
}
</script>
Add an additional table header (<th>) and column (<td>). Inside the <td> tag, add the following:
<script type="text/javascript">
var color = getProductColor({{ item.product.id }}, {{ item.variant.id }});
if ($defined(color)) {
document.write('<select name="select_{{item.product.id}}_{{item.variant.id}}" id="select_{{item.product.id}}_{{item.variant.id}}">');
for (i = 0; i < colors.length; i++) {
document.write('<option ');
if (colors[i] == color) {
document.write('selected ');
}
document.write('value="' + colors[i] + '">');
document.write(colors[i]);
document.write('</option>');
}
document.write('</select>');
}
</script>
While you are here, change everywhere it says "{{ item.product.description | strip_html | truncate: 50 }}" to "{{ item.product.description }}".
We need to make a couple of changes to the form elements. First, find the checkout image element and add an id="checkout" attribute to it. Second, add a hidden textarea. This will be used to store the selected colors (as an 'attributes' item), and can be used in your email notifications when an order arrives (described in Step 7):
<textarea name="attributes[color_choices]" id="color_choices" style="display:none;"></textarea>
Finally, add the code that will save the selected colors just above the last {%endif%}:
<script type="text/javascript">
$('checkout').addEvent('click', function(evt) {
// invoked when checkout is clicked
$('color_choices').value = "";
cookie.each(function(value, key){
var ac = Json.evaluate(value);
for (i = 0; i < ac.length; i++) {
var select = $('select_' + ac[i].id + '_' + ac[i].variant);
$('color_choices').value += ac[i].desc + ' = ' + select.value + '\n';
}
});
});
</script>
Step 5 - Specifying those colors
Ok, you've done the hard work. Hopefully you are still with me as we are almost done. We now need to add the available color selections to each product page. For each product that offers color choices, edit its description and add the following:
<notextile>
<script type="text/javascript">
colors = ['Pastels', 'Pinks', 'Whites', 'Yellows & Oranges'];
</script>
</notextile>
Step 6 - Clearing the cookie
We need to put in a sanity check to make sure when the cart is empty (e.g. after a checkout) the colors cookie is also empty. In theme.liquid, add the following:
{% if cart.item_count == 0 %}
<script type="text/javascript">
var cookie = new Hash.Cookie('product-colors', {path: '/'});
cookie.empty();
</script>
{% endif %}
Step 7 - Notifications
Now open up the New Order Notification email template and add a reference to the colors:
{{ attributes.color_choices }}
That's it - you are done!
Limitations
There are some things I'd like to improve on...
- This approach only allows users to select the colors for a product + variant combo. This means you can't simultaneously select a Large White Rose Box and a Large Pink Rose Box, for example.
- Every time the product description is used javascript is executed. In this case it is benign, but you may want to consider storing colors in a blog article or javascript file asset instead.
- It would be nice to be able to put the selected colors in the notification emails along with the line items they belong to. I think I have a way to do this -I just need a rainy day to play around a bit.
Wrapping Up
Shopify is a great solution for small to midsize business that need to get an ecommerce site up and running quickly. There is an awesome ecosystem of designers working with the platform, creating some truly remarkable sites. Hopefully you have found this tutorial useful, and given you some ideas on how to make your shop a success. Please let me know if you find any problems, or have any other suggestions, so that I can incorporate your feedback and improve this page.
Update: I am now offering Shopify consulting help for back-end Shopify development. Web Designers and Shopify Store Owners, if you are looking for someone to help with liquid, javascript, webhooks or any other of the technical aspects behind a Shopify site I'd love to help - give me a shout.
Posted by: Dan Grigsby | 2008.05.20 at 11:49 AM
Posted by: Phil Horne | 2008.07.31 at 01:17 PM
Posted by: Gavin Terrill | 2008.09.01 at 09:31 PM
Does this still work? Maybe I am missing something but I can't get colors displayed by editing the product description, adding,
notextile
script type="text/javascript"
colors = ['Navy', 'Black', 'White'];
/script
/notextile
I edited the code on product.liquid so it says,
if (colors.length > 0) {...} else { document.write("no colors available"); }
and it says that no colors are available.
Then I defined colors in the script at the top of product.liquid so it says,
script type="text/javascript"
var colors = ["Red", "Orange", "Blue"];
var variants = [];
/script
And then Red, Orange and Blue displayed correctly. This leads me to think it is a problem with the code in the product description.
Did I forget something?
Thanks.
Posted by: Brad Manning | 2009.03.10 at 07:59 PM
Posted by: BBG | 2009.03.10 at 09:50 PM
Posted by: Brad Manning | 2009.03.21 at 05:40 PM
Posted by: Phil Campbell | 2009.04.06 at 09:26 AM
Posted by: BBG | 2009.04.06 at 10:16 AM
Posted by: rc helicopter reviews | 2011.12.21 at 05:37 AM