(SOLVED)how to build custom collection - specific variants with links directly to that variant

Highlighted
Tourist
31 0 1

Just wanted to update for everyone else that reads this thread. This is a summary of the coding that Brendin provided and coding that I added to do the remaining tasks. This assumes you already have a collection named 215/60R16   and your products have the exact same variant name  215/60R16. The variant name MUST MATCH the collection name for this method to work. the generated link for the collection does not have to match but the TITLE does

Objectives:

1. Generate collection with direct variant link, variant price, variant stock availability and variant compare_at_price

 

I will show you what to put and where to put it to do the following

First step, make a copy of your collection.liquid and your product-grid-view files . I called these files collection-variants.liquid and product-grid-view-variant Then link your collection in the shopify admin to use the new template copy you created.

Inside collection.liquid, there is a line 

 {% include 'product-grid-item' %}

change it to

 {% include 'product-grid-item-variant' %}

---- this makes the new template also use the new version of a product grid view

 

collection.liquid     - after this code

 {% for product in collection.products %}

add the following code

{% for variant_link in product.variants %}
      {% if variant_link.title contains collection.title %}
          {% assign product_link = variant_link.url %}
          {% assign wanted_var_price = variant_link.price %}
          {% assign wanted_var_available = variant_link.available %}
         {% assign wanted_var_compareprice = variant_link.compare_at_price %}
        {% break %}{%comment%}This brake stops the loop, making the url the FIRST variant that matches{%endcomment%}
      {%endif%}
  {% endfor %}

 

This assigns the variant information to some new variables to use in the product-grid-item-variant file

 

next:

product-grid-item-variant

 

change this code

{% assign on_sale = false %}
{% assign sale_text = 'products.product.sale' | t %}
{% if product.compare_at_price > product.price %}
  {% assign on_sale = true %}
{% endif %}

{% assign sold_out = true %}
{% assign sold_out_text = 'products.product.sold_out' | t %}
{% if product.available %}
  {% assign sold_out = false %}
{% endif %}

to: 

{% assign on_sale = false %}
{% assign sale_text = 'products.product.sale' | t %}
{% if wanted_var_compareprice > wanted_var_price %}
  {% assign on_sale = true %}
{% endif %}

{% assign sold_out = true %}
{% assign sold_out_text = 'products.product.sold_out' | t %}
{% if wanted_var_available %}
  {% assign sold_out = false %}
{% endif %}

 

--- this changes the compare at price and sold_out graphics to use the variant information to make sure that it matches that specific item we are linking to. It looked bad where it was showing instock then after clicking the link it actually wasnt in stock so this is a change I wanted to add so everything is consistent.

 

change this code:

{% if on_sale %}
        <br><s class="grid-link__sale_price">{{ product.compare_at_price | money }}</s>
      {% endif %}

 

to: 

{% if on_sale %}
        <br><s class="grid-link__sale_price">{{ wanted_var_compareprice | money }}</s>
      {% endif %}

 

-- this makes the correct compare at price to show if it was previously determined that the compare at price is higher than the selling price

 

change this line:

{% capture price %}<strong>{{ product.price | money }}</strong>{% endcapture %}

 

to:

{% capture price %}<strong>{{ wanted_var_price | money }}</strong>{% endcapture %}

--- this sets the price to the variant price

 

finally we need to set the correct link directly to the specific variant

change this code:

<a href="{{ product.url | within: collection }}" class="grid-link">

 

to :

 <a href="{{ product_link | within: collection }}" class="grid-link">

 

Here is a working example of what I have changed

https://gogotires.com/collections/215-60r16

 

Notice how the link has a ' - ' in it rather than a ' / ' , that is because  ' / ' is used to show directories and would mess up the links so shopify auto generates links with a ' - ' instead. This does not matter as long as the collection title matches the variant name. If your collection title is  "Blue Shirt" you would need to make your variant name "Blue Shirt" and not "Blue" or you would have to do further logic in matching the strings.

 

Let me know if you have any questions or if I missed anything in my code.

 

Cheers,

Matt

0 Likes
Highlighted
Tourist
31 0 1

let me know if i missed anything or if my code has any issues that I did not notice yet :) 

0 Likes
Highlighted
Shopify Partner
200 0 23

Nice summary! If I may point out one thing that could be usefull, forum posts do have syntax highlighting if you click the icon to the right of the "source" button in the edit post RTE. It might help people better read the code ;) 

Feel free to shoot me an email if you ever need any other help!

0 Likes
Highlighted
Tourist
31 0 1

updated my post with the cope snippets displayed properly thanks for that tip also!

is there a particular email address you can be reached on in the future? or get the email address off your website?

If you need any help you can hit me up also, I am a programmer but still getting used to shopify

Matt

0 Likes
Highlighted
Shopify Partner
200 0 23

brendin@internetbanditos.com

;) will do man! 

0 Likes
Highlighted
Tourist
31 0 1

perfect 

 

mattmillerpc@gmail.com

if you need any help :)

0 Likes
Highlighted
New Member
1 0 0

Great! Both you are ton awesome

0 Likes
Highlighted
New Member
3 0 0

Hi!

Sorry to exhume this thread but I'm trying to transpose this code to another theme (the "debut" theme") and I can't find exactly where I have to make the changes. I must say that I am a beginner in coding!

For example my collection.liquid calls collection-template which looks like this:

{% case section.settings.grid %}
  {% when '2' %}
    {%- assign max_height = 530 -%}
  {% when '3' %}
    {%- assign max_height = 345 -%}
  {% when '4' %}
    {%- assign max_height = 250 -%}
  {% when '5' %}
    {%- assign max_height = 195 -%}
{% endcase %}

{% if section.settings.layout == 'grid' %}
  {%- assign limit = section.settings.grid | times: section.settings.rows -%}
{% else %}
  {%- assign limit = 16 -%}
{% endif %}

{% paginate collection.products by limit %}

<div data-section-id="{{ section.id }}" data-section-type="collection-template">
  <header class="collection-header">

    {% if section.settings.show_collection_image and collection.image %}
      <div class="collection-hero">
        <div class="collection-hero__image ratio-container lazyload js"
             data-bgset="{% include 'bgset', image: collection.image %}"
             data-sizes="auto"
             data-parent-fit="cover"
             style="background-image: url('{{ collection.image | img_url: '300x300' }});"></div>
        <noscript>
          <div class="collection-hero__image" style="background-image: url({{ collection.image | img_url: '2048x600', crop: 'top' }});"></div>
        </noscript>
        <div class="collection-hero__title-wrapper">
          <h1 class="collection-hero__title page-width">{{ collection.title }}</h1>
        </div>
      </div>

      {% if collection.description != blank %}
        <div class="rte collection-description page-width">
          {{ collection.description }}
        </div>
      {% endif %}
    {% else %}
      <div class="page-width">
        <div class="section-header text-center">
          <h1>{{ collection.title }}</h1>
          {% if collection.description != blank %}
            <div class="rte">
              {{ collection.description }}
            </div>
          {% endif %}
        </div>
      </div>
    {% endif %}

    {% if section.settings.tags_enable or section.settings.sort_enable %}
      <div class="filters-toolbar-wrapper">
        <div class="page-width">
          <div class="filters-toolbar">
            {% if section.settings.tags_enable %}
              <div class="filters-toolbar__item">
                <label for="SortTags" class="label--hidden">{{ 'collections.filters.title_tags' | t }}</label>
                <select class="filters-toolbar__input filters-toolbar__input--filter hidden" name="SortTags" id="SortTags">
                  {% if current_tags %}
                    {% if collection.handle %}
                      <option value="/collections/{{ collection.handle }}">{{ 'collections.filters.all_tags' | t }}</option>
                    {% elsif collection.current_type %}
                      <option value="{{ collection.current_type | url_for_type }}">{{ 'collections.filters.all_tags' | t }}</option>
                    {% elsif collection.current_vendor %}
                      <option value="{{ collection.current_vendor | url_for_vendor }}">{{ 'collections.filters.all_tags' | t }}</option>
                    {% endif %}
                  {% else %}
                    {% if current_tags contains tag %}
                      <option value="">{{ 'collections.filters.all_tags' | t }}</option>
                    {% else %}
                      <option value="">{{ 'collections.filters.title_tags' | t }}</option>
                    {% endif %}
                  {% endif %}
                  {% for tag in collection.all_tags %}
                    <option value="/collections/{% if collection.handle != blank %}{{ collection.handle }}{% else %}all{% endif %}/{{ tag | handleize }}"{% if current_tags contains tag %} selected="selected"{% endif %}>{{ tag }}</option>
                  {% endfor %}
                </select>
              </div>
            {% endif %}

            <div class="filters-toolbar__item filters-toolbar__item--count">
              <span class="filters-toolbar__product-count">{{ 'collections.general.items_with_count' | t: count: collection.products_count }}</span>
            </div>

            {% if section.settings.sort_enable %}
              <div class="filters-toolbar__item text-right">
                {%- assign sort_by = collection.sort_by | default: collection.default_sort_by -%}
                <label for="SortBy" class="label--hidden">{{ 'collections.sorting.title' | t }}</label>
                <select name="SortBy" id="SortBy" class="filters-toolbar__input filters-toolbar__input--sort hidden">
                  {% if sort_by == collection.default_sort_by %}
                    <option value="title-ascending" selected="selected">{{ 'collections.sorting.title' | t }}</option>
                    {% if collection.default_sort_by != 'manual' %}
                      <option value="manual"{% if sort_by == "manual" %} selected="selected"{% endif %}>{{ 'collections.sorting.featured' | t }}</option>
                    {% endif %}
                    {% if collection.default_sort_by != 'best-selling' %}
                      <option value="best-selling"{% if sort_by == "best-selling" %} selected="selected"{% endif %}>{{ 'collections.sorting.best_selling' | t }}</option>
                    {% endif %}
                    {% if collection.default_sort_by != 'title-ascending' %}
                      <option value="title-ascending"{% if sort_by == "title-ascending"  %}selected="selected"{% endif %}>{{ 'collections.sorting.az' | t }}</option>
                    {% endif %}
                    {% if collection.default_sort_by != 'title-descending' %}
                      <option value="title-descending"{% if sort_by == "title-descending" %} selected="selected"{% endif %}>{{ 'collections.sorting.za' | t }}</option>
                    {% endif %}
                    {% if collection.default_sort_by != 'price-ascending' %}
                      <option value="price-ascending"{% if sort_by == "price-ascending" %} selected="selected"{% endif %}>{{ 'collections.sorting.price_ascending' | t }}</option>
                    {% endif %}
                    {% if collection.default_sort_by != 'price-descending' %}
                      <option value="price-descending"{% if sort_by == "price-descending" %} selected="selected"{% endif %}>{{ 'collections.sorting.price_descending' | t }}</option>
                    {% endif %}
                    {% if collection.default_sort_by != 'created-descending' %}
                      <option value="created-descending"{% if sort_by == "created-descending" %} selected="selected"{% endif %}>{{ 'collections.sorting.date_descending' | t }}</option>
                    {% endif %}
                    {% if collection.default_sort_by != 'created-ascending' %}
                      <option value="created-ascending"{% if sort_by == "created-ascending" %} selected="selected"{% endif %}>{{ 'collections.sorting.date_ascending' | t }}</option>
                    {% endif %}
                  {% else %}
                    <option value="manual"{% if sort_by == "manual" %} selected="selected"{% endif %}>{{ 'collections.sorting.featured' | t }}</option>
                    <option value="best-selling"{% if sort_by == "best-selling" %} selected="selected"{% endif %}>{{ 'collections.sorting.best_selling' | t }}</option>
                    <option value="title-ascending"{% if sort_by == "title-ascending"  %}selected="selected"{% endif %}>{{ 'collections.sorting.az' | t }}</option>
                    <option value="title-descending"{% if sort_by == "title-descending" %} selected="selected"{% endif %}>{{ 'collections.sorting.za' | t }}</option>
                    <option value="price-ascending"{% if sort_by == "price-ascending" %} selected="selected"{% endif %}>{{ 'collections.sorting.price_ascending' | t }}</option>
                    <option value="price-descending"{% if sort_by == "price-descending" %} selected="selected"{% endif %}>{{ 'collections.sorting.price_descending' | t }}</option>
                    <option value="created-descending"{% if sort_by == "created-descending" %} selected="selected"{% endif %}>{{ 'collections.sorting.date_descending' | t }}</option>
                    <option value="created-ascending"{% if sort_by == "created-ascending" %} selected="selected"{% endif %}>{{ 'collections.sorting.date_ascending' | t }}</option>
                  {% endif %}
                </select>
                <input id="DefaultSortBy" type="hidden" value="{{ collection.default_sort_by }}">
              </div>
            {% endif %}
          </div>
        </div>
      </div>
    {% endif %}
  </header>

  <div class="page-width" id="Collection">
    {% if section.settings.layout == 'grid' %}
      {% case section.settings.grid %}
      {% when '2' %}
        {%- assign grid_item_width = 'medium-up--one-half' -%}
      {% when '3' %}
        {%- assign grid_item_width = 'small--one-half medium-up--one-third' -%}
      {% when '4' %}
        {%- assign grid_item_width = 'small--one-half medium-up--one-quarter' -%}
      {% when '5' %}
        {%- assign grid_item_width = 'small--one-half medium-up--one-fifth' -%}
      {% endcase %}

      <div class="grid grid--uniform{% if collection.products_count > 0 %} grid--view-items{% endif %}">
        {% for product in collection.products %}
          <div class="grid__item grid__item--{{section.id}} {{ grid_item_width }}">
            {% include 'product-card-grid', max_height: max_height %}
          </div>
        {% else %}
          {% comment %}
          Add default products to help with onboarding for collections/all only.

          The onboarding styles and products are only loaded if the
          store has no products.
          {% endcomment %}
          {% if collection.handle == 'all' and collection.all_vendors.size == 0 and collection.all_types.size == 0 %}
            <div class="grid__item">
              <div class="grid grid--uniform">
                {% for i in (1..limit) %}
                  <div class="grid__item {{ grid_item_width }}">
                    <div class="grid-view-item">
                      <a href="#" class="grid-view-item__link">
                        <div class="grid-view-item__image">
                          {% capture current %}{% cycle 1, 2, 3, 4, 5, 6 %}{% endcapture %}
                          {{ 'product-' | append: current | placeholder_svg_tag: 'placeholder-svg' }}
                        </div>
                        <div class="h4 grid-view-item__title">{{ 'homepage.onboarding.product_title' | t }}</div>
                        <div class="grid-view-item__meta">
                          <span class="product-price__price">$19.99</span>
                        </div>
                      </a>
                    </div>
                  </div>
                {% endfor %}
              </div>
            </div>
          {% else %}
            {%- assign is_empty_collection = true -%}
          {% endif %}
        {% endfor %}
      </div>
    {% else %}
      <div class="list-view-items">
        {% for product in collection.products %}
          <a href="{{ product.url | within: collection }}" class="list-view-item">
            {% include 'product-card-list', product: product %}
          </a>
        {% else %}

          {% comment %}
          Add default products to help with onboarding for collections/all only.

          The onboarding styles and products are only loaded if the
          store has no products.
          {% endcomment %}
          {% if collection.handle == 'all' and collection.all_vendors.size == 0 and collection.all_types.size == 0%}
            {% for i in (1..4) %}
              <a href="#" class="list-view-item">
                <div class="list-view-item__image-column">
                  <div class="list-view-item__image-wrapper">
                    <div class="list-view-item__image">
                      {%- assign placeholder = 'placeholder-product-' | append: i -%}
                      {% include placeholder %}
                    </div>
                  </div>
                </div>

                <div class="list-view-item__title-column">
                  <div class="list-view-item__title">{{ 'homepage.onboarding.product_title' | t }}</div>
                </div>

                <div class="list-view-item__price-column">
                  <span class="product-price__price">$19.99</span>
                </div>
              </a>
            {% endfor %}
          {% else %}
            {%- assign is_empty_collection = true -%}
          {% endif %}
        {% endfor %}
      </div>
    {% endif %}

    {% if is_empty_collection %}
      <div class="grid__item small--text-center">
        <p class="text-center">{{ 'collections.general.no_matches' | t }}</p>
      </div>
    {% endif %}

    {% if paginate.pages > 1 %}
      {% include 'pagination' %}
    {% endif %}
  </div>
</div>

{% endpaginate %}

{% schema %}
  {
    "name": "Collection pages",
    "settings": [
      {
        "type": "select",
        "id": "layout",
        "label": "Layout",
        "default": "grid",
        "options": [
          {
            "value": "grid",
            "label": "Grid"
          },
          {
            "value": "list",
            "label": "List"
          }
        ]
      },
      {
        "type": "select",
        "id": "grid",
        "label": "Products per row (grid only)",
        "default": "4",
        "options": [
          {
            "value": "2",
            "label": "2"
          },
          {
            "value": "3",
            "label": "3"
          },
          {
            "value": "4",
            "label": "4"
          },
          {
            "value": "5",
            "label": "5"
          }
        ]
      },
      {
        "type": "select",
        "id": "rows",
        "label": "Rows per page (grid only)",
        "default": "2",
        "options": [
          {
            "value": "2",
            "label": "2"
          },
          {
            "value": "3",
            "label": "3"
          },
          {
            "value": "4",
            "label": "4"
          },
          {
            "value": "5",
            "label": "5"
          },
          {
            "value": "6",
            "label": "6"
          },
          {
            "value": "7",
            "label": "7"
          },
          {
            "value": "8",
            "label": "8"
          }
        ]
      },
      {
        "type": "checkbox",
        "id": "show_collection_image",
        "label": "Show collection image",
        "default": true
      },
      {
        "type": "checkbox",
        "id": "show_vendor",
        "label": "Show product vendors",
        "default": false
      },
      {
        "type": "checkbox",
        "id": "sort_enable",
        "label": "Enable sorting",
        "default": true
      },
      {
        "type": "checkbox",
        "id": "tags_enable",
        "label": "Enable tag filtering",
        "default": true
      }
    ]
  }
{% endschema %}

There are two:

 {% for product in collection.products %}

Do I have to add the code after both?

Then it seems to call both product-card-grid and product-card-list

Here is my product-card-grid.liquid

<div class="grid-view-item{% unless product.available %} product-price--sold-out grid-view-item--sold-out{% endunless %}">
  <a class="grid-view-item__link grid-view-item__image-container" href="{{ product.url | within: collection }}">
    {% capture img_id %}ProductCardImage-{{ section.id }}-{{ product.id }}{% endcapture %}
    {% capture wrapper_id %}ProductCardImageWrapper-{{ section.id }}-{{ product.id }}{% endcapture %}
    {%- assign img_url = product.featured_image | img_url: '1x1' | replace: '_1x1.', '_{width}x.' -%}

    {% unless product.featured_image == blank %}
      {% include 'image-style' with image: product.featured_image, width: max_height, height: max_height, small_style: true, wrapper_id: wrapper_id, img_id: img_id %}
    {% endunless %}

    <div id="{{ wrapper_id }}" class="grid-view-item__image-wrapper js">
      <div style="padding-top:{% unless product.featured_image == blank %}{{ 1 | divided_by: product.featured_image.aspect_ratio | times: 100}}%{% else %}100%{% endunless %};">
        <img id="{{ img_id }}"
             class="grid-view-item__image lazyload"
             src="{{ product.featured_image | img_url: '300x300' }}"
             data-src="{{ img_url }}"
             data-widths="[180, 360, 540, 720, 900, 1080, 1296, 1512, 1728, 2048]"
             data-aspectratio="{{ product.featured_image.aspect_ratio }}"
             data-sizes="auto"
             alt="{{ product.featured_image.alt | escape }}">
      </div>
    </div>

    <noscript>
      {% capture image_size %}{{ max_height }}x{{ max_height }}{% endcapture %}
      <img class="grid-view-item__image" src="{{ product.featured_image.src | img_url: image_size, scale: 2 }}" alt="{{ product.featured_image.alt }}" style="max-width: {{ max_height | times: product.featured_image.aspect_ratio }}px;">
    </noscript>

    <div class="h4 grid-view-item__title">{{ product.title }}</div>
    {% if section.settings.show_vendor %}
      <div class="grid-view-item__vendor">{{ product.vendor }}</div>
    {% endif %}
    <div class="grid-view-item__meta">
      {% include 'product-price' %}
    </div>
  </a>
</div>

And this is my product-card-list.liquid

<div class="list-view-item__image-column">
  <div class="list-view-item__image-wrapper">
    <img class="list-view-item__image" src="{{ product.featured_image.src | img_url: '95x95', scale: 2 }}" alt="{{ product.featured_image.alt | escape }}">
  </div>
</div>

<div class="list-view-item__title-column">
  <div class="list-view-item__title">{{ product.title }}</div>
  {% if product.compare_at_price > product.price %}
    <div class="list-view-item__on-sale">{{ 'products.product.on_sale' | t }}</div>
  {% endif %}
  {% if section.settings.show_vendor %}
    <div class="list-view-item__vendor medium-up--hide">{{ product.vendor }}</div>
  {% endif %}
  {% unless product.available %}
    <div class="list-view-item__sold-out">{{ 'products.product.sold_out' | t }}</div>
  {% endunless %}
</div>

{% if section.settings.show_vendor %}
  <div class="list-view-item__vendor-column small--hide">
    <div class="list-view-item__vendor">{{ product.vendor }}</div>
  </div>
{% endif %}

<div class="list-view-item__price-column">
  {% include 'product-price' %}
</div>

I can't find the code I'm supposed to change in this file.

I would be very gratefull if someone could help me on this, thank you!

0 Likes
Highlighted
New Member
1 0 0

I too want to make this happen in debut theme! Any help is GREATLY appreciated!

0 Likes
Highlighted
Excursionist
15 0 8

Can't believe this is not a standard feature on Shopify...Instead we get random developers offering us subscription based pricing on apps just to get our stores to function properly.... Pretty frustrating tbh.  Anyhow, maybe this might help, I haven't tried it yet though. https://dylanjh.com/blogs/19-show-all-products-as-separate-variants-on-the-collection-page-of-the-de...

0 Likes