Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
Linked options helper methods for Shopify. See this: http://docs.shopify.com/manual/configuration/store-customization/advanced-navigation/linked-product-options - Updated to work with sectioned themes (tested with District)
<script>
// (c) Copyright 2016 Caroline Schnapp. All Rights Reserved. Contact: mllegeorgesand@gmail.com
// See https://docs.shopify.com/themes/customization/navigation/link-product-options-in-menus
// Modified by Jonathan Moore (Style Hatch) https://github.com/jonathanmoore
/*
Updated to work with sectioned themes
- Added required methods from the deprecated options_selection.js
- Triggers an initial variant change
- Hides sold out variants with only one option
*/
window.addEventListener('DOMContentLoaded', function() {
var Shopify = Shopify || {};
// Required functionality from depricated options_selection.js
Shopify.arrayIncludes = function(e, t) {
for (var n = 0; n < e.length; n++)
if (e[n] == t) return !0;
return !1
}, Shopify.uniq = function(e) {
for (var t = [], n = 0; n < e.length; n++) Shopify.arrayIncludes(t, e[n]) || t.push(e[n]);
return t
}
Shopify.optionsMap = {};
Shopify.updateOptionsInSelector = function(selectorIndex) {
switch (selectorIndex) {
case 0:
var key = 'root';
var selector = jQuery('.single-option-selector:eq(0)');
break;
case 1:
var key = jQuery('.single-option-selector:eq(0)').val();
var selector = jQuery('.single-option-selector:eq(1)');
break;
case 2:
var key = jQuery('.single-option-selector:eq(0)').val();
key += ' / ' + jQuery('.single-option-selector:eq(1)').val();
var selector = jQuery('.single-option-selector:eq(2)');
}
var initialValue = selector.val();
selector.empty();
var availableOptions = Shopify.optionsMap[key];
for (var i=0; i<availableOptions.length; i++) {
var option = availableOptions[i];
var newOption = jQuery('<option></option>').val(option).html(option);
selector.append(newOption);
}
jQuery('.swatch[data-option-index="' + selectorIndex + '"] .swatch-element').each(function() {
if (jQuery.inArray($(this).attr('data-value'), availableOptions) !== -1) {
$(this).removeClass('soldout').show().find(':radio').removeAttr('disabled','disabled').removeAttr('checked');
}
else {
$(this).addClass('soldout').hide().find(':radio').removeAttr('checked').attr('disabled','disabled');
}
});
if (jQuery.inArray(initialValue, availableOptions) !== -1) {
selector.val(initialValue);
}
selector.trigger('change');
};
Shopify.linkOptionSelectors = function(product) {
// Building our mapping object.
for (var i=0; i<product.variants.length; i++) {
var variant = product.variants[i];
if (variant.available) {
// Gathering values for the 1st drop-down.
Shopify.optionsMap['root'] = Shopify.optionsMap['root'] || [];
Shopify.optionsMap['root'].push(variant.option1);
Shopify.optionsMap['root'] = Shopify.uniq(Shopify.optionsMap['root']);
// Gathering values for the 2nd drop-down.
if (product.options.length > 1) {
var key = variant.option1;
Shopify.optionsMap[key] = Shopify.optionsMap[key] || [];
Shopify.optionsMap[key].push(variant.option2);
Shopify.optionsMap[key] = Shopify.uniq(Shopify.optionsMap[key]);
}
// Gathering values for the 3rd drop-down.
if (product.options.length === 3) {
var key = variant.option1 + ' / ' + variant.option2;
Shopify.optionsMap[key] = Shopify.optionsMap[key] || [];
Shopify.optionsMap[key].push(variant.option3);
Shopify.optionsMap[key] = Shopify.uniq(Shopify.optionsMap[key]);
}
}
}
// Update options right away.
Shopify.updateOptionsInSelector(0);
if (product.options.length > 1) Shopify.updateOptionsInSelector(1);
if (product.options.length === 3) Shopify.updateOptionsInSelector(2);
// When there is an update in the first dropdown.
jQuery(".single-option-selector:eq(0)").change(function() {
Shopify.updateOptionsInSelector(1);
if (product.options.length === 3) Shopify.updateOptionsInSelector(2);
return true;
});
// When there is an update in the second dropdown.
jQuery(".single-option-selector:eq(1)").change(function() {
if (product.options.length === 3) Shopify.updateOptionsInSelector(2);
return true;
});
};
{% if product.available and product.options.size > 1 %}
var $addToCartForm = $('form[action="/cart/add"]');
if (window.MutationObserver && $addToCartForm.length) {
if (typeof observer === 'object' && typeof observer.disconnect === 'function') {
observer.disconnect();
}
var config = { childList: true, subtree: true };
var observer = new MutationObserver(function() {
Shopify.linkOptionSelectors({{ product | json }});
observer.disconnect();
});
observer.observe($addToCartForm[0], config);
}
{% endif %}
var selector = jQuery('.single-option-selector:eq(0)');
selector.trigger('change');
{% if product.options.size == 1 %}
{% for variant in product.variants %}
{% unless variant.available %}
jQuery('.single-option-selector option').filter(function() { return jQuery(this).text().trim() === {{ variant.title | json }}; }).remove();
{% endunless %}
{% endfor %}
jQuery('.single-option-selector').trigger('change');
{% endif %}
});
</script>
@akenger

This comment has been minimized.

Copy link

commented Feb 26, 2017

Hey Jonathan,

I'm trying to use this and for the life of me can't figure out why it seems like jQuery is not available when this loads. I get "Can't find variable $" on this line var $addToCartForm = $('form[action="/cart/add"]');

Any ideas? I imagine maybe it's a race condition of some kind b/c if I put a debugger on it, I can run that selector.

I'm using the debut theme...

@JordanNZ

This comment has been minimized.

Copy link

commented Mar 30, 2017

Is there anyway that we can have it load up the default variants value with out having to select another to fire the script?

@AnnaBanana124

This comment has been minimized.

Copy link

commented May 10, 2017

Thank you, this amazingly worked for me! However, when I switch options, the default variant is automatically listed as unavailable but will show as available if i click another variant and then click back to the default. I can live with this but I figured I'd let you know how it's working for me. I am using the Colors theme. Thanks again!!

@HandHugs

This comment has been minimized.

Copy link

commented May 18, 2017

Im getting an error:
Uncaught TypeError: Cannot read property 'length' of undefined
at Object.Shopify.updateOptionsInSelector
at Object.Shopify.linkOptionSelectors
at MutationObserver.

They seem to have to do with the section of code:
var availableOptions = Shopify.optionsMap[key]; for (var i=0; i<availableOptions.length; i++) { var option = availableOptions[i]; var newOption = jQuery('<option></option>').val(option).html(option); selector.append(newOption); }

Any ideas on how I can get this to work?


@hnashenda

This comment has been minimized.

Copy link

commented May 27, 2017

@HandHugs... that problem is related to your dropdown selection class. It is probably different from that in the code.
Solution : replace all instances of "single-option-selector__radio" with the class from your select dropdown linked list.
eg:
my class for the select drop down list is "single-option-selector__radio"
THus
var selector = jQuery('.single-option-selector:eq(0)');
I changed to
var selector = jQuery('.single-option-selector__radio:eq(0)');

@ybyalik

This comment has been minimized.

Copy link

commented Jul 21, 2017

Hi, maybe someone can help. This works for me but only after I refresh the product page. I'm using Shopify Turbo theme from OOTS
Any ideas?

@namurray

This comment has been minimized.

Copy link

commented Jul 25, 2017

@jonathanmoore thanks for this, i made one change, i removed .removeAttr('checked') from line 55 because, in this one theme built off Debut that I've looked at anyway, after initial page load I had to check another available variant twice to apply the checked status (which has a style associated to it). This change seems to have taken care of it, can you foresee any issues?

one problem i am still having (might be related to @AnnaBanana124 's): On first load of an available variant (eg Color Pink / Size 2), an option that is unavailable for another (eg no size 4 for Black, but there is a 4 for Pink) is hidden (size 4). If I click a new color this is resolved but obviously it's an issue for first page load.

I'll work on it but maybe you'll find a solution before me.

@maxg23

This comment has been minimized.

Copy link

commented Aug 14, 2017

im trying to run this script with the Envy Theme, doesnt seem to work. where do i paste the {% include 'linked-options' %} . Help please!

@ajensen27

This comment has been minimized.

Copy link

commented Aug 22, 2017

What JordanNZ said: Is there anyway that we can have it load up the default variants value with out having to select another to fire the script?

Is there?

@tracynicholas

This comment has been minimized.

Copy link

commented Aug 23, 2017

@jonathanmoore This is fantastic, thank you so much!
Is there any way I can add some code in that still shows the unavailable options, but has them greyed out?

Thanks, Tracy

@AlejandroRomeo

This comment has been minimized.

Copy link

commented Oct 1, 2017

Thank you!!!!!!!!!
Solved my problem

@AlejandroRomeo

This comment has been minimized.

Copy link

commented Nov 3, 2017

Hi @jonathanmoore, I encountered a bug after further developing a website.

The scripts works just fine when using "dropdown menus" on product page. However, when implementing "product swatch", an error occurs. The available variants show up fine for every click on the first variable selector, but when clicking to choose on the 2nd variable for some options, the selection doesn't apply.
screenshot_1
Did any one encounter this same problem? I'm using Showtime Theme (sectioned theme)
I did manage to figure out that the ocurrence of this bug depends on the order of the variants on the product page.
For example:
image
I replicated the error on this test store if anyone wants to help me, it would be much appreciated.
url: https://livewellargentina.myshopify.com/products/copy-of-100-whey-protein?variant=4588430655520
pass: loowha
Thanks

@voskresla

This comment has been minimized.

Copy link

commented Nov 22, 2017

Quickly change it for Brooklyn Theme. Test only for my shop.
gist

@jonathanmoore

This comment has been minimized.

Copy link
Owner Author

commented Jan 10, 2018

Hey @AlejandroRomeo - This specific snippet was modified to ensure it works with our District premium Shopify theme. If you're working with another theme or a custom built one, you might want to try referencing Shopify's guide or working with a developer.

@tracynicholas

This comment has been minimized.

Copy link

commented Jan 22, 2018

Hi @jonathanmoore, this function seems to have stopped working over the last couple of days (not sure exactly when). We haven't updated our website / code in any way.
Have there been any updates that you know of that occurred over the weekend?
Thanks in advance, Tracy

@rjpt-339

This comment has been minimized.

Copy link

commented Mar 10, 2018

Hello Every One,
Tons of information there. @jonathanmoore Sir i was looking to implement this on Venture Free Theme. I tried the above code but not working. But i tried it on Supply Theme it worked.
Can any one help me setup Linked-Options over Venture Theme.
Regards
Arslan Akram

@hanihsdd

This comment has been minimized.

Copy link

commented Mar 14, 2018

Hello,

Thanks for the script.

For those of you who are having issues with the default variant not loading and requiring the user to select a variant before the script fires:

This is what worked for me on the Shopify Debut Theme.

Find the following code:
Shopify.linkOptionSelectors({{ product | json }});

It is located in the following if statement

{% if product.available and product.options.size > 1 %}
...
Shopify.linkOptionSelectors({{ product | json }});
...
{% endif %}

Simply move it directly outside of the if statement:

{% if product.available and product.options.size > 1 %}
...
// Line removed from here
...
{% endif %}

// Line added here
Shopify.linkOptionSelectors({{ product | json }});
@elucan

This comment has been minimized.

Copy link

commented Apr 3, 2018

Anyone been successful with getting this to work on the Symmetry theme?

@nutriprash

This comment has been minimized.

Copy link

commented Sep 12, 2018

The code by Jonathan works perfectly on my Debut theme without any change in code.

@nutriprash

This comment has been minimized.

Copy link

commented Sep 12, 2018

Thanks Hanihsdd & Jonathan, It worked for my Debut Theme

@thousandzero

This comment has been minimized.

Copy link

commented Sep 18, 2018

Hey Please help me. Everything tried but not working for me.

  jQuery(function($) {
    {% if product.available and product.variants.size > 1 %}
    new Shopify.OptionSelectors('product-selectors', {
      product: {{ product | json }},
      onVariantSelected: selectCallback, 
      enableHistoryState: true
    });   

    {% comment %}
    Use color swatch and linked options (copyright by @carolineschnapp)
    {% endcomment %}
    {% if section.settings.use_color_swatch and product.available and product.options.size > 1 %}
    Shopify.linkOptionSelectors({{ product | json }});
    {% endif %} 

    {% if section.settings.use_color_swatch != true %}
    jQuery('.single-option-selector').selectize();
    jQuery('.selectize-input input').attr("disabled","disabled");
    {% endif %}

    {% endif %}
@nutriprash

This comment has been minimized.

Copy link

commented Oct 1, 2018

Hello,
I made the changes in Jonathans code recomended by hanihsdd (without first checking how Jonathans code works), in my debut theme, which caused most of the products to show as "out of stock". On reversing Hanihsdd's code change, my problem got resolved. So you don't need to make any changes in Jonathans code.

Thanks again

@baisho

This comment has been minimized.

Copy link

commented Dec 5, 2018

Hey, I tried to use @jonathanmoore's solution in Debut theme, and the functionality works perfectly, but unfortunately the loading time has been increased big time. So big that a lot of times the page just crashes. Before applying Jonathan's code it hadn't happen. Do you have any suggestions why it occurs and how to solve it? Thank you! :)

@baisho

This comment has been minimized.

Copy link

commented Dec 7, 2018

Now it seems the page loads okay, it crashes significantly less then 2 days ago. BUT! Jonathan's code works only for the first loading of the page. If I go to another product it stops working. Do you have an idea why it can happen? I am using the Debut theme. Thank you for all of your answers!

@MohdQasim00

This comment has been minimized.

Copy link

commented Feb 23, 2019

@baisho I am encountering the same issue which is the product page never load and crashes. have you successfully been able to solve that issue? Thanks.

@numzie

This comment has been minimized.

Copy link

commented May 13, 2019

Script seems to work with my Venture theme.

Has anyone come up with a way to DISABLE/GREY OUT unavailable/sold out items instead of removing them?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.