Geeks With Blogs

News Meta
Gruff Code Code and tech musings from Jesse Taber. If I call it a blog I'll feel bad when I don't update it every week.

As I mentioned in my last post I talked some about how my side project, PiX Eyewear, has given me an opportunity to venture out of the predominantly server-side .NET programming that I’ve been doing at my “day job” for the past several years. In this post I’ll be digging into a simple way that I’ve been able to leverage jQuery to solve a little problem I had with my Shopify site.

Before I go any further I want to call out an excellent approach for displaying “related products” on a product page that Caroline Schnapp posted up on the Shopify Design forums a little while back. This is a really clever approach to doing this, and one that I only discovered recently after coming up with the approach that I’m about to describe. I think that both approaches have their relative merits, and go into that in a bit more detail toward the end of this post. As always, choose the right tool for the job at hand.

demo_chain_verticalThe Problem

PiX Eyewear sells sunglasses and reading glasses that feature a channel embedded into the temple that accepts temple inserts. These temple inserts can feature virtually any design and can be made out of a variety of different materials. The idea is that you can buy a single pair of glasses and change up the look using these temple inserts. Pretty cool idea, right? :-)

We offer four different styles of sunglasses each available in two colors. Two of those styles are also available with two different lens colors. For reading glasses we have one frame style available in three different colors and about a half dozen different magnification strengths. Take all of those frame combinations and multiply it by an ever-expanding collection of temple inserts and you’ll begin to see why I’ve struggled a bit with finding the best way to get my products into my Shopify store in a way that makes sense and will let my customers find the things that they are looking for.

I’ve gone through three or four iterations of re-configuring my inventory to try and solve this problem. Obviously, Shopify features a very robust product database for storing and organizing the products for your store. Each product can have up to three different types of variants defined. Variants can be used to offer a single product in different sizes or colors and were perfect for letting users choose the various colors and magnification strengths that are offered with our frames. The problem with variants is that they don’t scale enough to manage all of the various combinations of frames and temple styles that my store offers. At first, we offered frames and temple inserts as completely different products. This approach made a lot of sense because we wanted to let people buy a single pair of frames and pick out as many different temple styles as they wanted. This approach lead to the situation where customers were seeing the temple styles that they liked while browsing the site but then not realizing that buying the temple style didn’t include any frames!

After having to give away frames to a few confused customers I decided I needed a different approach. This temple insert system is patented, so there’s no one else selling these inserts or frames anywhere else online (yet). That coupled with the fact that we’re such a new business made me realize that offering the temple inserts as products by themselves is pretty much pointless right now. Practically all of our potential customers are going to need to buy a pair of frames along with their temple inserts. That said, I wanted to be sure that people understood that the temple inserts were available by themselves as well. What I really wanted to be able to do was define a bunch of products that represented “frame combos”. A combo would be a temple style that comes with a frame of your choice. By making the frames variants of the temple insert products things became much simpler and easier to manage. I still didn’t have a good way to denote that fact that all of the “combo” styles are also available as inserts by themselves. I could have made one of the variants “inserts only”, but that felt clunky at best. What I really wanted to do was have temple inserts offered by themselves and temple inserts offered as combos managed as completely separate products with some means to establish a link between them. To the best of my knowledge Shopify doesn’t support explicitly linking two products together, so I had to get a little creative.

Enter jQuery

Shopify exposes a neat little jQuery API that you can easily load into your store. The API gives you quick and easy ways to perform some common tasks like add a product to the cart, or gather all the details of a given product. The best way to learn about the API is to check out the jQuery Ajax API Sandbox. In thinking about my problem I realized that I could leverage this API to do a quick look up on my product page to see if I had a complementary product that I wanted to show a link to. This can be accomplished using the ‘Shopify.getProduct’ method of the API. This is a simple method that takes a product handle and returns some JSON representing that product’s properties. Among those properties is the URL to access that product’s details page.

In order to use this, I first needed to load the Shopify API into my store. This is easily accomplished by adding a line to the <head> section of your ‘theme.liquid’. There are some convenient shortcuts for adding references to javascript libraries that are hosted by Shopify. Obviously, you also need to be sure to include a reference to jQuery as well. Here’s an example from my own theme.liquid (note that I’m using the Google CDN for hosting jQuery itself):

  <script type="text/javascript" src=""></script>
  {{ 'api.jquery.js' | shopify_asset_url | script_tag }}

That’s all you need to be able to start using the ‘getProduct’ method on your site’s pages. The only problem I had now was knowing the product handle for the related product that I wanted to show a link to. At first I was trying to figure out if there was a way that I could embed the related product via some specially named product tag or some similar hack. If I could find a way to render the handle of the related product in the mark up of my product details page it would be easy to grab it with jQuery after the page was loaded and asynchronously get the related product’s details to display on the page somewhere. I probably could have accomplished this with some clever manipulation of product tags, but that seemed like it would be hard to maintain over the long term.

Convention Over Configuration

I eventually realized that the problem I was having could probably be solved with a convention rather than having to manually configure each product with tags that pointed to the related product. I would be sacrificing some flexibility (this flexibility being one of the main strengths to the alternative approach that I linked to at the beginning of this post), but my current needs are pretty simple. I have two basic scenarios that I need to support:

  • When a user is viewing a “frame combo” that features a temple style with a frame, I want to show a link to the “temple style only” product.
  • When a user is viewing a “temple style only” product I want to show a link to the “combo” offering for that same temple style.

I decided to use a naming convention for product handles that would let me easily take any given product handle and derive the handle of a related product. By default Shopify creates your product handles by just taking the product’s display name and replacing any white space or special characters with dashes. Product handles have to be unique on a store by store basis, so Shopify will automatically add a number to the end of any potential duplicates. I decided to link my products together by giving them the same handle but appending a suffix to the end of the handle to denote what type of product it was. For example, a suffix of “rc” would indicate that a product was a “reading glasses combo” product whereas a suffix of “ri” would indicate that it was a “reading glasses insert-only” product. So how do we deal with product handles that might happen to end in the letters “rc” or “ri”?

Since product handles are used to construct the unique URL of each product in your store, they can’t contain any crazy special characters. From what I can tell, they can only contain letters, numbers, dashes and underscores. Since Shopify already uses the dashes to make the handles more human readable I decided to use underscores to denote where a product type suffix begins in a product handle. This way I can easily tell that the product with handle “blue-butterfly_sc” represents a “sunglasses combo” for the blue butterfly style and that the corresponding “insert only” option should be named “blue-butterfly_si”. Note that I opted for simple two-letter suffixes, though these could easily be made longer and more descriptive if desired.

Show Me The Code

To make this a easier I packaged up some of the common bits of code into a little javascript library. It’s available in both minified and original flavors over at github. You’re free to download, use, and change this code however you like. This library takes care of determining what the related product handle should be, calling the AJAX API to get that product’s handle, dealing with the situation where that corresponding handle can’t be found, and finally showing the link to the corresponding product in some pre-determined area of your product details page. The code sample below shows how to use the library as an external javascript reference after you’ve added it as an asset to your store’s theme.

To make this work, you need to tell the library a few things including what product type suffixes you’re using, how they relate to each other, and where on the product details page you want to display the related product link. We’ll do all of this in our ‘product.liquid’ template. First, you’ll want to define some HTML element that will serve as a container for your related product link. I opted to use a div with the id ‘relatedProducts’:

<div id="relatedProducts">

I put this div just below my product price / product type display, but you can put it anywhere you like and style it any way that you want. I would suggest using an ‘id’ attribute to uniquely identify it on the page, as that will make it easier for the related products library to find it later. You’ll also want to expose the handle of the product being viewed somewhere on the page. I opted to do this in a hidden field by adding this little bit of code to my product.liquid template:

<input type="hidden" id="prodHandle" value="{{ product.handle }}"/>

Next, we just need to define some javascript that will configure the related products library and show the related products link once the product detail page has been completely loaded. The following code snippet comes directly from the very top of my own ‘product.liquid’ template:

{{ 'RelatedProducts.min.js' | asset_url | script_tag }}

<script type="text/javascript">

jQuery(document).ready(function () {
  relatedProductsLib.outputSelector = '#relatedProducts';
  relatedProductsLib.productLookupFunction = Shopify.getProduct;
  relatedProductsLib.suffixLookup = {
    'sc' : 'si',
    'rc' : 'ri',
    'si' : 'sc',
    'ri' : 'rc'

  relatedProductsLib.messageLookup = {
    'si' : 'Already have a pair of PiX frames? <br/><a href="{0}">You can buy these temple inserts without frames.</a>',
    'ri' : 'Already have a pair of PiX frames? <br/><a href="{0}">You can buy these temple inserts without frames.</a>',
    'sc' : 'Need a pair of PiX frames to go with these inserts? <br/><a href="{0}">You can buy these inserts with frames as a combo!</a>',
    'rc' : 'Need a pair of PiX frames to go with these inserts? <br/><a href="{0}">You can buy these inserts with frames as a combo!</a>'

  var fullHandle = jQuery('#prodHandle').val();

Let me talk through each piece of this:

First, I’ve used Liquid to output a <script> tag that will contain the minified version of the related products library that I linked to above. You’ll want to upload that .js file as an asset to your theme.

Next I’m configuring the related products library by setting a few properties that the library exposes:

  • outputSelector: This is the jQuery selector for the DOM element where the related products link should be output. I used a div with an id of ‘relatedProducts’, so my selector is simple: ‘#relatedProducts’.
  • productLookupFunction: This is the function that should be invoked to perform the actual product lookup. I exposed this as a property with the intention of possibly replacing it with a dummy function of some kind for use while developing/testing, but for your actual product.liquid template you’ll want to use the value shown there: ‘Shopify.getProduct’.
  • suffixLookup: This is a simple object containing key-value pairs defining the relationships between the product prefixes that you want to relate to one another. This could be cleaner, and I plan on revamping that a bit in a future update to this library. In the example above I’m basically saying ‘map all ‘sc’ products to ‘si’ products and all ‘rc’ products to ‘ri’ products and vice versa.
  • messageLookup: Again, I’m not completely happy with this as an API and there’s room for improvement. This property is another set of key-value pairs defining  the format of the link that you want to display for each product based on the suffix of the product being displayed. In the example above I’m saying ‘if the current product being viewed has a suffix of ‘si’ or ‘ri’, then the related product link should read ‘Already have a pair of PiX Frames?…’. Note that the ‘{0}’ token in that string is the place holder for where the related products URL will go.

After setting those four properties, I grab the product handle of the current product out of the hidden field I defined in my product.liquid template and pass that into the ‘showRelatedProducts’ method of the library. The library takes care of the rest. If a product is found with the expected product handle, the corresponding message and link will appear in the HTML element denoted by the ‘outputSelector’ property. If no product is found (or some error occurs during the product look up), nothing happens. This way you can safely add this code to your normal product.liquid template without fear of having javascript errors crop up in the event that some of your products don’t follow this naming convention, or you just haven’t gotten around to setting up all of your product handles with the correct suffixes yet.

You can see this approach in action on the PiX site today by checking out the Blue Butterfly Sunglasses Combo product. You’ll see a ‘You can buy these temple inserts without frames’ link appear in the product details area of the page that will link over to the “insert only” product.

Rough Around the Edges

I’m the first to admit that this approach is far from perfect, but it seems to suit my needs for the time being. I like this approach because it relies on some very simple naming conventions and requires very little configuration. I think it would pretty easy to do mass updates of product handles using the bulk inventory upload feature to add the needed product type suffixes to your product handles. I think that in some cases this would end up being a lot less work than trying to manage tags on each and every product to establish a relationship between that product and others in your store.

That said, I’m always open to making this better. A few ideas I have off the top of my head:

  • Add support for mapping a product type suffix to multiple other suffixes. For example, I’ll eventually want to be able to offer the same temple style as a “sunglasses combo”, “reading glasses combo” and “temple insert only”. The current code won’t support this scenario.
  • Add the ability to use jQuery templates to jazz up the presentation.
  • Explore ways to bake this into a pre-packaged Shopify theme.

In what other ways can I make this better?

Posted on Monday, October 11, 2010 9:34 PM | Back to top

Comments on this post: Linking Shopify Products Together With Naming Conventions (and a little jQuery)

No comments posted yet.
Your comment:
 (will show your gravatar)

Copyright © Jesse Taber | Powered by: