Changing variant image in Shopify - shopify

I have a product on a Shopify hosted website that has several colors. I am trying to change the code so that all of the thumbnails are hidden, except for the color that is selected. The code is shown below, and works, except that the main image does not change when the color selected is changed. Any suggestions?
Here's the live page: https://www.palmettowoodshop.com/collections/featured/products/docking-station-cherry?variant=33412918350
{% assign option_name = 'Color' %}
{% if product.options contains option_name %}
<script>
// Grabbing product thumbnails
// Covers: Editions, Launchpad Star, Lookbook, Kickstand, Startup, Simple, Radiance, Minimal, Supply, New Standard and many more.
var thumbnails = jQuery('img[src*="/products/"]') /* All product images */
.not('#related-products img') /* Except related products, thumbnails not clickable */
.not('a[href^="/collections/"] img') /* Except related products */
.not('a[href^="/products/"] img') /* Except mini-cart products */
.not('header img') /* Except mini-cart products, thumbnails not clickable */
.not('#drawer img') /* Except mini-cart products, thumbnails not clickable, in Simple theme. */
.not(':first'); /* Except first one, i.e the main image */
var optionSelect;
{% assign option_index = 0 %}
{% for option in product.options %}
{% if option == option_name %}
{% assign option_index = forloop.index0 %}
{% endif %}
{% endfor %}
{% if product.options.size == 1 %}
optionSelect = '.single-option-selector';
{% else %}
optionSelect = 'label:contains({{ option_name }}) + .single-option-selector';
{% endif %}
jQuery('form[action="/cart/add"]').on('change', optionSelect, function() {
var optionValue = $(this).val();
thumbnails.each(function() {
var wrapper = $(this);
while ( wrapper.parent().children().length === 1 ) {
wrapper = wrapper.parent();
}
if ( jQuery(this).attr('alt') === optionValue ) {
wrapper.show();
}
else {
wrapper.hide();
}
});
});
</script>
{% endif %}

In your code, change .not(':first'); to .not('.feature-row__image') or whatever the class name of your featured image.

Related

DBT - how can i add model configuration (using a macro on {{this}}) in dbt_project.yml

I want to add node_color to all of my dbt models based on my filename prefix to make it easier to navigate through my dbt documentation :
fact_ => red
base__ => black.
To do so i have a macro that works well :
{% macro get_model_color(model) %}
{% set default_color = 'blue' %}
{% set ns = namespace(model_color=default_color) %}
{% set dict_patterns = {"base__[a-z0-9_]+" : "black", "ref_[a-z0-9_]+" : "yellow", "fact_[a-z0-9_]+" : "red"} %}
{% set re = modules.re %}
{% for pattern, color in dict_patterns.items() %}
{% set is_match = re.match(pattern, model.identifier, re.IGNORECASE) %}
{% if is_match %}
{% set ns.model_color = color %}
{% endif %}
{% endfor %}
{{ return({'node_color': ns.model_color}) }}
{% endmacro %}
And i call it in my model .sql :
{{config(
materialized = 'table',
tags=['daily'],
docs=get_model_color(this),
)}}
This works well but force me to add this line of code in all my models (and in all the new ones).
Is there a way i can define it in my dbt_project.yml to make it available to all my models automatically?
I have tried many things like the config jinja function or this kind of code in dbt_project.yml
+docs:
node_color: "{{ get_model_color(this) }}"
returning Could not render {{ get_model_color(this) }}: 'get_model_color' is undefined
But nothing seems to work
Any idea? Thanks

Shopify - best way to incrementally build up a string in Liquid

I have an array of cities. I want to create a formatted string that can be output to the page... something like New York, Miami and Denver.
In JavaScript, I'd do something like this (rough):
const cities = ['nEW-york','MIAMI FL', 'denver'];
let out = '';
cities.forEach((city, i) => {
if(i === cities.length-1 && i !== 0) {
out += ` and ${formatCity(city)}.`;
} else {
if(i !== 0) {
out += ', ';
}
out += city;
}
});
console.log(out);
You can assume my formatCity() function knows what different kinds of input to expect and how to transform it into a nicely formatted city name (ex nEW-york --> New York).
The first way I thought to do this in Liquid was to use a for loop and capture, which just creates a mess of whitespace and newlines and whatnot.
Instead, I went with an approach similar to how i' do it in JavaScript, using the append filter.
{% assign cities = 'nEW-york,MIAMI FL,denver' | split: ',' %}
{% assign out = '' %}
{% for city in cities %}
{% if forloop.last and forloop.first == false %}
{% assign out = out | append: ' and ' | append: city | append: '.' %}
{% elsif forloop.first == false %}
{% assign out = out | append: ', ' | append: city %}
{% else %}
{% assign out = out | append: city %}
{% endif %}
{% endfor %}
{%- capture prettyCityStr -%}
{%- render 'format-cities', str: out -%}
{% endcapture %}
{{- prettyCityStr -}}
And you can assume that my format-cities snippet does the same as the formatCity() function above. You should also assume that it's not just as simple as throwing the word and in before the last city.
I have no idea if this method (used extensively on any given page... with WAY larger arrays of cities) would cause any performance issues (it seems to me that re-initializing the out variable over and over again may be problematic) or if there's just a more standard way.
I don't work in Liquid often - any input from anyone who does would be greatly appreciated.

working with 'strings' as 'arrays' in shopify liquid

I am trying to display color boxes next to items based on item varients. However, it has been giving me weird results in my array. Yes I know there are no real arrays in liquid. I have two options below. The first one doesnt work. It gives me things like "background-color: [''''''' ". Along with all the correct ones too.
So the second option i just hard coded all the colors and checked against that. This works as long as the colors are in order... but if the colors are not in order than it will display duplicates.
New to liquid but this seems super ugly and probably means i am doing it wrong.
<div class="color-box-wrapper">
{% assign values = '' %}
{% for variant in product.variants %}
{% assign value = variant.option2%}
{% unless values contains value %}
{% assign values = values | append: ',' | append: value %}
{% assign values = values | split: ',' %}
{% for color in values %}
{% if color.size > 0%}
<div class="product-color-box" style="background-color:{{color}}"></div>
{% endif %}
{% endfor %}
{% endunless %}
{% endfor %}
</div>
THIS WAY KINDA WORKS BUT SEEMS HACKY.
<div class="color-box-wrapper">
{% assign realColors = 'yellow, blue, white, burgandy, black, red, green, purple, beige, light_brown' | split: ", "%}
{% assign values = '' %}
{% for variant in product.variants %}
{% assign value = variant.option2 | downcase%}
{% unless values contains value %}
{% assign values = values | append: ',' | append: value %}
{% assign values = values | split: ',' %}
{% for color in values %}
{% if realColors contains color %}
<div class="product-color-box" style="background-color:{{color}}"></div>
{% endif %}
{% endfor %}
{% endunless %}
{% endfor %}
</div>
It might work better to use the product.options_with_values field, something like this:
{% assign color_option = product.options_with_values | where: 'name', 'color' | first %}
<h1>Color option is in position {{ color_option.position }}!</h1>
<h2>Array of all values is: {{ color_option.values | json }}</h2>
{% for value in color_option %}
<h3>Gimmie a {{ value }}!! {% if value == color_option.selected_value %}(Selected){% endif %}</h3>
{% endfor %}
It's a bit trickier if your colours are not CSS-recognized colour names, but there are certainly a number of things you can do for that. I typically prefer adding a CSS layer that can translate colour values into the appropriate display values (either background images or colour hex-codes). Some ideas are:
Add a data attribute or a class to your element (usually using the | handle filter to standardize the output) and use a CSS sheet to assign background images or colours appropriately
Create a section with blocks that allows you to map colour values to hex codes. If you are creating this for someone other than yourself, it would allow the merchant to set up the colours themselves and fine-tune all the shades.
Use metafields on your product that can generate the correct colour code using the options as the lookup. (Eg: If you create a metafield namespace on your products of product.metafields.colors and use the colour names as the keys and hex codes as the values, you can output {{ product.metafields.colors[value] }} to get the right computer colour. (This generally requires installing an app to manage - though metafields themselves are native Shopify functionality, Shopify doesn't have any native way to set them in the admin)
Hope this helps!
References:
Shopify Liquid Reference - Product objects: https://help.shopify.com/en/themes/liquid/objects/product#product-options_with_values
Shopify Liquid Reference - Product Option objects (from options_with_values): https://help.shopify.com/en/themes/liquid/objects/product_option

specify variable array index for liquid

My liquid code is
{% assign _product_id = product.id %}
{% assign _product_tag = product.collections[0].title}
{% assign _product_name = product.title %}
{{_product_tag}}
{% assign pagla_array = collections[_product_tag].products %}
{{ pagla_array.first.title }}
Here last line showing nothing. if I use a static index for assigning pagla_array like {% assign pagla_array = collections['Beans'].products %} then it show value. What wrong did I make here?
This line:
{% assign _product_tag = product.collections[0].title}
Is not closed correctly. It should end with %}
In addition you should use handles for the collections, not title.
So it should become:
{% assign _product_tag = product.collections[0].handle %}
....
{% assign pagla_array = collections[_product_tag].products %}

How to use variables in Twig filter 'replace'

Handing over an array from php of form
$repl_arr = array('serach-string1' => 'replace1', ...)
to a Twig template I would like to replace strings in a Twig variable per replace filter similar to this:
{{ block | replace({ repl_arr }) }}
That does not function and neither a variable loop like
{% for key,item in repla_arr %}
{% set var = block | replace({ key : item }) %}
{% endfor %}
does. What is wrong with it? How could it work?
Either you pass the whole array, or you loop the replaces.
But when looping the replaces you need to wrap key and value in parentheses to force interpolation of those
{% set replaces = {
'{site}' : '{stackoverflow}',
'{date}' : "NOW"|date('d-m-Y'),
} %}
{% set haystack = '{site} foobar {site} {date} bar' %}
{{ haystack | replace(replaces) }}
{% set output = haystack %}
{% for key, value in replaces %}
{% set output = output|replace({(key) : (value),}) %}
{% endfor %}
{{ output }}
fiddle