Custom Product Color Variations in Shopify

This page explains how I customized my Shopify site - Poetry in Flowers - so that users can choose flower colors.

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. Check that you have it referenced in the header section in 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:

<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 the colors

Ok, you've done the hard work. Hopefully you are still with me. The last step is to add the colors 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>

Limitations

  • This approach only allows users to select the colors for a product + variant combo. This means you can't select a Large White Rose Box and a Large Pink Rose Box, for example.
  • Everytime the product description is used, the javascript is executed. In this case it is benign, but you may want to consider storing it in a blog article instead.

Wrapping Up

Hopefully you will find this useful. Please let me know if you find any problems or have suggestions so I can incorporate your feedback and improve this page.

TrackBack

TrackBack URL for this entry:
http://www.typepad.com/t/trackback/198107/28987716

Listed below are links to weblogs that reference Custom Product Color Variations in Shopify:

Comments

Feed You can follow this conversation by subscribing to the comment feed for this post.

Gavin: great write up. I've been digging into Shopify customization and this is a superb example.

Post a comment

Comments are moderated, and will not appear on this weblog until the author has approved them.

If you have a TypeKey or TypePad account, please Sign In