Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Shopify - make variant id change in url when selecting product options

I think I'm working with an old theme since new themes seem to have a js file already in place to update the variant ID in the URL upon making options selections for a product. I've been trying to figure it out but I'm totally lost. The theme I have doesn't seem to have anything like that at all.

I have been trying different things with jQuery to get the variant ID values from the options and history.pushState to change the id in the URL but it's not the greatest solution and doesn't work consistently, nor it is a true "fix."

As much as I would like to just change the theme to a newer, working one, that's sadly not an option, and I am aware this theme is probably terrible.

Here is the site: https://elizabethsuzann.com/collections/all-products

Here is the product file:

    <div id="content" class="main-content">
    <div id="page">
        <div class="row full-width clearfix">
            <div id="product-{{ product.id }}">
                <div class="column medium-6 large-6 product-photos product__images left show-for-small-only">
                    {% include "product-toggler" %}
                </div>
                <div class="column medium-6 large-6 product__description right" id="product-right">
                    <div id="product-description">
                        <div class="row product__details">
                            <div class="column medium-9">
                                {% if settings.vendor %}<h3>{{ product.vendor }}</h3>{% endif %}
                                <h1 class="product__title medium-text-left small-text-center">{% include "product-title-replacer" %}</h1>
                                <h2 class="product__fabric medium-text-left small-text-center">
                                    {% include 'tag-looper' %}
                                </h2>
                                <div class="yotpo bottomLine"
                                     data-appkey="ydEHp58GjhymPiIi6x0gT4BYZjK5cAQOeGanUwmT"
                                     data-domain="{{ shop.permanent_domain | escape }}"
                                     data-product-id="{{ product.id }}"
                                     data-product-models="{{ product.id }}"
                                     data-name="{{ product.title | escape }}"
                                     data-url="{{ shop.url }}{{ product.url }}"
                                     data-image-url="{{ product.featured_image | product_img_url: 'large' |replace: '?', '%3F' | replace: '&','%26' }}"
                                     data-description="{{ product.description | escape }}"
                                     data-bread-crumbs="{% for tag in product.tags %}{{ tag | escape }};{% endfor %}">
                                </div>
                                <div class="spacer-20"></div>
                                {% if settings.subtitle %}<p>{{ page_title }}</p>{% endif %}
                            </div>
                            <div class="column medium-3">
                                {% if product.available %}
                                    {% if product.compare_at_price > product.price %}
                                        <h3 class="product-price product__price medium-text-right small-text-center onsale"
                                            itemprop="price"><span
                                                    style="color:#f46e6e;">{{ product.price | money }}</span>
                                            <br>
                                            <span class="compare-price was"
                                                  style="text-decoration: line-through;">{{ product.compare_at_price | money }}</span>
                                        </h3>
                                    {% else %}
                                        <h3 class="product-price product__price medium-text-right small-text-center"
                                            itemprop="price">{{ product.price | money }}</h3>
                                    {% endif %}
                                    <!--OUT OF STOCK!-->
                                {% else %}
                                    <h3 class="product-price product__price medium-text-right small-text-center soldout-text"
                                        itemprop="price">Sold Out</h3>
                                    <p>
                                        <a href="https://elizabethsuzann.com/pages/contact" target="_blank"
                                           class="ask-a-question-product">Ask A Question
                                        </a>
                                    </p>
                                {% endif %}
                            </div>
                        </div>
                        {% include 'short-form' %}
                        <div class="clearfix"></div>
                        <div class="product__accordions text-editor">
                            <ul class="accordion" data-accordion id="productAccordion">
                                <li class="accordion-navigation active">
                                    <a href="#panel1a">Description</a>
                                    <div id="panel1a" class="content active">
                                        {{ product.description | replace: '<h5>', '</div></li><li class="accordion-navigation"><a href="#panela">' | replace: '</h5>', '</a><div id="panela" class="content">' }}
                                    </div>
                                </li>
                            </ul>
                        </div>
                        {% if settings.popups %}
                            <div class="product__modals">
                                <ul class="inline-list">
                                    <li>
                                        <a href="#" data-reveal-id="sizeChart">Size Chart</a>
                                    </li>
                                    <li>
                                        <a href="#" data-reveal-id="returnPolicy">Return Policy</a>
                                    </li>
                                    <li>
                                        <a href="#" data-reveal-id="question">Ask A Question</a>
                                    </li>
                                </ul>
                            </div>
                        {% endif %}
                    </div>
                </div>
                <div class="column medium-6 large-6 product-photos product__images left show-for-medium-up">
                    {% include "product-toggler" %}
                    {% include "customer-slideshow" %}
                </div>
                <div class="show-for-small-only">{% include "customer-slideshow" %}</div>
            </div>
        </div>
    </div>
</div>
<div class="clear"></div>
<div class="product-single-extras">
    {% if settings.diversity_slideshow_enable %}
        {% assign hasDiversity = false %}
        {% for image in product.images %}{% assign alt_text = image.alt %}{% if alt_text contains "DIVERSITY_" %}{% assign hasDiversity = true %}{% endif %}{% endfor %}
        {% if hasDiversity == true %}
            <div class="full-width row collapse diversity-panel">
                <div class="small-12 columns diversity-panel-container">
                    <div>{% for image in product.images %}{% assign alt_text = image.alt %}{% if alt_text contains "DIVERSITY_" %}
                            <img src="{{ image | img_url: 'master' }}"
                                 alt="{{ alt_text | remove: 'DIVERSITY_' | replace: '\"', '$quot;' }}"/>{% break %}{% endif %}{% endfor %}
                    </div>
                    <ul class="diversity-panel-details brandon"></ul>
                </div>
            </div>
        {% endif %}
    {% endif %}

    {% assign hasSlides = false %}
    {% for image in product.images %}
        {% assign alt_text = image.alt %}
        {% if alt_text contains "SLIDESHOW" %}
            {% assign hasSlides = true %}
        {% endif %}
    {% endfor %}
    {% if settings.product_slideshow_enable and hasSlides == true %}
        <div class="full-width row collapse image-slideshow">
            <div class="small-12 columns">
                <div class="loader">
                    <div class="load-watch">
                        <div class="slider">
                            {% for image in product.images %}
                                {% assign alt_text = image.alt %}
                                {% if alt_text contains "SLIDESHOW_" %}
                                    <div>
                                        {% if alt_text contains "http://" or alt_text contains "https://" %}
                                        <a href="{{ alt_text | remove: 'SLIDESHOW_[[' | remove: ']]' }}">{% endif %}
                                            <img src="{{ image | img_url: 'master' }}"
                                                 alt="{{ alt_text | remove: 'SLIDESHOW_' }}"/>
                                            {% if alt_text contains "http://" or alt_text contains "https://" %}
                                        </a>{% endif %}
                                    </div>
                                {% endif %}
                            {% endfor %}
                        </div>
                    </div>
                </div>
            </div>
        </div>
    {% endif %}

    {% include 'related-products-tag' %}
    <div class="clear"></div>
</div>
<div class="yotpo yotpo-main-widget" data-product-id="{{ product.id }}" data-name="{{ product.title | escape }}"
     data-url="{{ shop.url }}{{ product.url }}"
     data-image-url="{{ product.featured_image | product_img_url: "large" |replace: '?', '%3F' | replace: '&','%26' }}"
     data-description="{{ product.description | escape }}"></div>
{{ 'inStockAlerts.js' | asset_url | script_tag }}
{{ 'extendedSizes.js' | asset_url | script_tag }}

collection file:

    <!-- /snippets/collection-sidebar.liquid -->
<div id="page" class="row full-width">
      {% if collection.image %}
      <div class="full-width row collapse collection-header-image">
          <div class="small-12 columns">
            <div class="loader">
               <div class="load-watch">
                   {% if collection.image.alt contains "[a]"%}
                        {% assign altTextArray = collection.image.alt | split: "[a]" %}
                        {% assign urlArray = altTextArray[1] | split: "[/a]"%}
                   {% endif %}
                   {%if urlArray[0] %}<a href="{{ urlArray[0] }}" title="{{collection.title}}">{%endif%}
                      <img src="{{ collection.image | img_url: 'master' }}" alt="{{ collection.image.alt }}">
                   {%if urlArray[0] %}</a>{%endif%}
               </div>
            </div>
          </div>
      </div>{% endif %}
      <div class="row show-for-small-only">
        <div class="column text-center"><h1>{%if collection.title != "Materials" %}{{ collection.title }}{% else %}{%if current_tags.first %}{{current_tags.first}}{% endif %}{% endif %}</h1></div>  
        <div class="spacer-30"></div>
      </div>
      
      <div class="clear"></div>
      <div id="content" class="full-width">
        {% paginate collection.products by 21 %}
          <!-- START SIDEBAR -->
            {% include 'sidebar-collection' %}
          <!-- END SIDEBAR -->
          <div class="column medium-9 large-10 main-content" id="product-collection"> 
            {% if collection.description.size > 0 %}
                <div class="collection-description text-editor hide-for-small">
                    {{ collection.description }}  
                </div>
            {% endif %}
            
            <ul class="small-block-grid-1 medium-block-grid-2 large-block-grid-3 xxlarge-block-grid-4">

              {% for product in collection.products %}
                  <li class="product-index" id="prod-{{ product.id }}" data-alpha="{{ product.title }}" data-price="{{ product.price }}">
                          <div class="product-index-inner">
                            {% if product.available %}
                              {% for col in product.collections %}
                                {% if col.handle == 'new' %}
                                <div class="new icn">NEW IN</div>
                                {% endif %}
                              {% endfor %}

                              {% if product.price < product.compare_at_price %}
                              <div class="sale-item icn">SALE</div>
                              {% endif %}

                            {% else %}
                            <div class="so icn">SOLD OUT</div>
                            {% endif %}             
                        </div>
                        <div class="image_hover">
                                <div class="loader">
                                  <div class="load-watch">
                                  <a href="{{ product.selected_or_first_available_variant.url | within: collection }}" title="{{ product.title | escape }}" style="display:block;">
                                    {% for image in product.images %}
                                        {% if forloop.first %}
                                          <img class="variant-image" src="{{ product.images[0] | product_img_url: 'master' }}" alt="image.alt" data-holder="{{ product.images[0] | product_img_url: 'master' }}" />
                                        {% endif %}
                                    {% endfor %}
                                  </a>
                                  </div>
                                </div>
                              {% if product.available %}
                                  {% assign v_image = false %}
                                  {% for vimage in product.variants %}
                                      {% if vimage.image %}
                                        {% assign v_image = true %}
                                        {% endif %}
                                  {% endfor %}

                                  {% if v_image %}
                                    <div class="variants" style="padding: 5px;">
                                      {% for option in product.options %}
                                        {% assign opt_index = -1 %}
                                          {% if option == 'Color' %}
                                            {% assign opt_index = forloop.index0 %}
                                          {% endif %}
                                          {% if opt_index > -1 %}
                                            {% assign color_done = '' %}
                                            {% for variant in product.variants %}
                                                {% assign color = variant.options[opt_index] %}
                                                {% assign colorFirst = color | split: ' ' %}
                                                {% for coloring in colorFirst %}
                                                    {%if forloop.first%}
                                                        {% assign colorClass = coloring %}
                                                    {%endif%}
                                                {% endfor %}
                                                {% unless color_done contains color %}
                                                    {% assign color_image = color | downcase | replace: ' ','-' | append: '.png' %}
                                                    {% if variant.image %}
                                                        <div class="variant {{ colorClass | downcase }}{% if forloop.first %} active{% endif %}" data-link="{{ product.url | within: collection }}?variant={{ variant.id }}" data-variant="{{ variant.image | img_url: 'original' }}" title="{{ variant.title }}" style="background: url({{ color_image | asset_url }});"></div>
                                                    {% endif %}
                                                    {% assign color_done = color_done | append: color | append: ',' %}
                                                {% endunless %}
                                            {% endfor %}
                                          {% endif %}
                                      {% endfor %}
                                    </div>
                                  {% endif %}
                              {% endif %}
                        </div>    

                        <div class="product-info"> 
                          <div class="product-info-inner row"> 
                            <div class="column medium-8 small-text-center medium-text-left">

                                {% if settings.vendor %}<h4><a href="{{ product.url }}"> {{ product.vendor }}</a></h4>{% endif %}
                                <h3><a href="{{ product.url }}">{% include "product-title-replacer" %}</a></h3>
                                  <h2 class="product__fabric medium-text-left small-text-center">
                                  {% include "tag-looper" %}
                                  </h2>
                            </div>
                            <div class="column medium-4 small-text-center medium-text-right">
                                <div class="price">
                                  {% if product.price < product.compare_at_price %}
                                  <div class="onsale">{{ product.price | money }}</div>
                                  <div class="was" style="display:block;">{{ product.compare_at_price | money }}</div>
                                  {% else %}
                                  <div class="prod-price">{% if product.price_varies %} from {{ product.price_min | money }} - {{ product.price_max | money }} {% else %}{{ product.price | money }}{% endif %}</div>
                                  {% endif %}   
                                </div>
                            </div>
                          </div>
                        </div>
                  </li>
              {% endfor %} 

            </ul>
          </div>
          <div class="column text-center">
                <div id="pagination"> 
    <!--           <span class="count">Showing items {{ paginate.current_offset | plus: 1 }}-{% if paginate.next %}{{ paginate.current_offset | plus: paginate.page_size }}{% else %}{{ paginate.items }}{% endif %} of {{ paginate.items }}.</span> -->

              {% if paginate.previous %}
              {{ '<' | link_to: paginate.previous.url }}
              {% endif %}
              {% for part in paginate.parts %}
              {% if part.is_link %}
              {{ part.title | link_to: part.url }}
              {% else %}
              {% if part.title == '&hellip;' %}
              {{ part.title }}
              {% else %}
              <span class="current">{{ part.title }}</span>
              {% endif %}
              {% endif %}
              {% endfor %}
              {% if paginate.next %}
              {{ '>' | link_to: paginate.next.url }}
              {% endif %}
                </div>
          </div>
        {% endpaginate %}
      </div>
</div>

And the custom js file that I've been working in:

var extendedSizes = (function () {
var request = new XMLHttpRequest();
// request.open("GET", "https://cdn.shopify.com/s/files/1/0474/8573/files/models.xml?12460120219966895535", false);
request.open("GET", "https://cdn.shopify.com/s/files/1/0474/8573/files/models.xml?428914189903248951", false);
request.send();
var xml = request.responseXML;
var models = [].slice.call(xml.getElementsByTagName('Model'));
var colorButton = [].slice.call(document.querySelectorAll('#colors .swatch-element'));
var thumbnails = [].slice.call(document.querySelectorAll('.thumbnail'));

if ($('#physical-gift-card').length < 1) {
    var initialAlt = [].slice.call(document.querySelectorAll('.thumbnail'))[0].getAttribute('alt');
}


var name, height, bust, waist, hip, size, onClick, clickAlt, color, colorAlt;
var destination = $('.zoomer');

// Primary function for getting data and calling appendMeasurements to append it
function measurements(alt, size) {
    for (var i = 0; i < models.length; i++) {
        if (models[i].hasAttribute('name')) {
            name = models[i].getAttribute('name');
            // If clicked thumbnail alt matches a model in the XML doc
            if (alt.indexOf(name) > -1 && alt.length > 0) {
                var children = models[i].childNodes;
                // Nested loop to get child attributes
                for (var t = 0; t < children.length; t++) {
                    switch (children[t].nodeName) {
                        case 'Height':
                            height = children[t].firstChild.nodeValue
                            break;
                        case 'Bust':
                            bust = children[t].firstChild.nodeValue
                            break;
                        case 'Waist':
                            waist = children[t].firstChild.nodeValue
                            break;
                        case 'Hip':
                            hip = children[t].firstChild.nodeValue
                            break;
                    }
                    appendMeasurements(name, height, bust, waist, hip, size)
                }
            }
        }
    }
}

// Append size/fit measurements after image gallery with updated grammar for it with fallback


function appendMeasurements(name, height, bust, waist, hip, size) {
    $(destination).find('.extended-sizes-model-text').remove();
    if (typeof size != 'undefined') {
        var grammarA = ['S', 'M', 'L', '2XL', '3XL', '4XL'];
        var grammarAN = ['XL', 'XXS', 'XS', 'OSM', 'OS', 'OSP', 'OSP2', 'OSP3'];
        if ($.inArray(size, grammarAN) !== -1 || ($.inArray(size, grammarA) == -1 && $.inArray(size, grammarAN) == -1)) {
            $(destination).append("<div class='extended-sizes-model-text'><p>" + name + " is " + height + " tall with a " + bust + " bust, " + waist + " waist, and " + hip + " hip," + " and she is wearing an " + size + ".</p> </div>")
        }
        if ($.inArray(size, grammarA) !== -1) {
            $(destination).append("<div class='extended-sizes-model-text'><p>" + name + " is " + height + " tall with a " + bust + " bust, " + waist + " waist, and " + hip + " hip," + " and she is wearing a " + size + ".</p> </div>")
        }

    } else {
        $(destination).append("<div class='extended-sizes-model-text'><p>" + name + " is " + height + " tall with a " + bust + " bust, " + waist + " waist, and " + hip + " hip." + "</p> </div>")
    }

}

// Run on default
if ($('#physical-gift-card').length < 1) {
    if (initialAlt.indexOf('-') > -1) measurements(initialAlt.split('- ')[1]);
}
// Run measurements function on thumbnail click
thumbnails.forEach(function (img) {
    img.addEventListener('click', function (event) {
        var clicked = event.target;
        clickAlt = clicked.getAttribute('alt');
        // console.log(clickAlt.split('-'));
        // console.log(clickAlt.split('-').slice(-1).pop());
        if (clickAlt.split('-').length > 2) {
            var size = clickAlt.split('-').slice(-1).pop().trim();
        }
        onClick = true;
        if (clickAlt.indexOf('-') > -1) clickAlt = clickAlt.split('- ')[1];
        measurements(clickAlt, size);
    })
})

// Run measurements function each time SELECT COLOR is clicked
colorButton.forEach(function (button) {
    button.addEventListener('click', function (event) {
        color = event.currentTarget.getAttribute('data-color');
        colorAlt = $('.product-photos').find("." + color).find('.product__sideimages').find('img:first-child:first').attr('alt');
        // console.log(colorAlt.split('-'));
        if (colorAlt.split('-').length > 2) {
            var size = colorAlt.split('-').slice(-1).pop().trim();
        }
        if (initialAlt.indexOf('-') > -1) measurements(colorAlt.split('- ')[1], size);
        var selectorDropdown = $(".select option:selected").val();

        console.log("color: "+color);
        if (history.pushState) {
            var newurl = window.location.protocol + "//" + window.location.host + window.location.pathname + "?variant=" + selectorDropdown;
            window.history.pushState({path: newurl}, '', newurl);

        }
    })
})

// all varient selection add to cart class change
var sizeListItem = $('div.swatch > #sizes > li');
var lengthListItem = $('div.swatch > #length > li');

var sizeClicked = false;
var lengthClicked = false;

sizeListItem.each(function (e){
    $(this).on("click", function() {
        $(this).addClass('size-selected');
        console.log('at least one size list item selected');
        sizeClicked = true;

        var variantClass = $(this).find("input").attr("class");
        var availabilityState = $(this).find(".swatch-element");
        var emailBtn = $(".swym-add-to-watchlist");

        if (history.pushState) {
            var newurl = window.location.protocol + "//" + window.location.host + window.location.pathname + "?variant=" + variantClass;
            window.history.pushState({path: newurl}, '', newurl);

            if (availabilityState.hasClass("soldout") || availabilityState.hasClass("unavailable")) {
                emailBtn.show();
            }
            else {
                emailBtn.hide();
            }
        }
    });
})

lengthListItem.click(function () {
    $(this).addClass('length-selected');
    console.log('at least one length item selected');
    lengthClicked = true;

    var variantClass = $(this).find("input").attr("class");
    var availabilityState = $(this).find(".swatch-element");

    if (history.pushState) {
        var newurl = window.location.protocol + "//" + window.location.host + window.location.pathname + "?variant=" + variantClass;
        window.history.pushState({path: newurl}, '', newurl);

        if (availabilityState.hasClass("soldout") || availabilityState.hasClass("unavailable")) {
            emailBtn.show();
        }
        else {
            emailBtn.hide();
        }
    }
});


if ($('#length').length > 0) {

    setInterval(function () {
        if ((lengthClicked === true) && (sizeClicked === true)) {
            $('.product__add').addClass('atc-activate');
            $('.product__description .product__add .disabled').css({
                'background': '#000',
                'color': '#fff'
            })
        }
        // console.log(true);

    }, 100);
} else {

    setInterval(function () {
        if ((sizeClicked === true)) {
            $('.product__add').addClass('atc-activate');
            $('.product__description .product__add .disabled').css({
                'background': '#000',
                'color': '#fff'
            })
        }
        // console.log(true);

    }, 100);
}


})();
like image 897
Dejsa Cocan Avatar asked Nov 18 '22 00:11

Dejsa Cocan


1 Answers

You can use this function:

function updateQueryString(key, value, url) {
    if (!url) url = window.location.href;

    let updated = ''
    var re = new RegExp("([?&])" + key + "=.*?(&|#|$)(.*)", "gi"),
        hash;

    if (re.test(url)) {
        if (typeof value !== 'undefined' && value !== null) {
            updated = url.replace(re, '$1' + key + "=" + value + '$2$3');
        } 
        else {
            hash = url.split('#');
            url = hash[0].replace(re, '$1$3').replace(/(&|\?)$/, '');
            if (typeof hash[1] !== 'undefined' && hash[1] !== null) {
                url += '#' + hash[1];
            }
            updated = url;
        }
    }
    else {
        if (typeof value !== 'undefined' && value !== null) {
            var separator = url.indexOf('?') !== -1 ? '&' : '?';
            hash = url.split('#');
            url = hash[0] + separator + key + '=' + value;
            if (typeof hash[1] !== 'undefined' && hash[1] !== null) {
                url += '#' + hash[1];
            }
            updated = url;
        }
        else {
            updated = url;
        }
    }

    window.history.replaceState({ path: updated }, '', updated);
}

The functionality is fairly simple. Just pass variant and the variant's id, like this:

updateQueryString('variant', '123123');

If the URL does not have the ?variant query string yet, it will automatically create it. If it does, it will update it.

like image 81
Diego Fortes Avatar answered Dec 10 '22 20:12

Diego Fortes