Shopify Products Grid Section – Advanced

Shopify Liquid July 23, 2026

Shopify Products Grid Section – Advanced

{% comment %}

GV Featured Grid – NO SNIPPETS (Final Clean)

Requested updates:

– Mobile: Add to cart button goes to next line (below price)

– Image: NO background box, NO forced height/padding — only original image shows (natural ratio)

– Remove Card background settings (red box in editor) ✅

– Card background always follows Dawn color scheme (var(–color-background)) ✅

– Title uses scheme foreground (no blue)

– Title clamped so footer stays aligned

{% endcomment %}
{%- liquid
  assign sid = 'gvfp-' | append: section.id
  assign limit = section.settings.products_to_show | default: 4
  assign columns_desktop = section.settings.columns_desktop | default: 4
  assign columns_mobile = section.settings.columns_mobile | default: 2
-%}
<section id="{{ sid }}" class="gvfp color-{{ section.settings.color_scheme }} gradient">
  <div class="gvfp__wrap page-width">
    {%- if section.settings.heading != blank or section.settings.subheading != blank -%}
      <header class="gvfp__head gvfp__head--{{ section.settings.heading_align }}">
        {%- if section.settings.heading != blank -%}
          <h2 class="gvfp__title">{{ section.settings.heading | escape }}</h2>
        {%- endif -%}
        {%- if section.settings.subheading != blank -%}
          <p class="gvfp__sub">{{ section.settings.subheading | escape }}</p>
        {%- endif -%}
      </header>
    {%- endif -%}
    {%- if section.settings.collection != blank -%}
      <div class="gvfp__grid" style="--cols:{{ columns_desktop }};--cols-m:{{ columns_mobile }};">
        {%- for product in section.settings.collection.products limit: limit -%}
          {%- liquid
            assign badge = blank
            if section.settings.enable_badges
              if product.compare_at_price_max > product.price
                assign badge = 'Sale'
              elsif product.tags contains 'new' or product.tags contains 'New'
                assign badge = 'New'
              elsif product.tags contains 'bestseller' or product.tags contains 'Best Seller' or product.tags contains 'Best-Seller'
                assign badge = 'Best Seller'
              endif
            endif
            assign has_one_variant = false
            if section.settings.enable_quick_add and product.variants.size == 1 and product.available
              assign has_one_variant = true
            endif
            assign img = product.featured_media
          -%}
          <article class="gvfp__card">
            <a href="{{ product.url }}" class="gvfp__media" aria-label="{{ product.title | escape }}">
              {%- if badge != blank -%}
                <span class="gvfp__badge">{{ badge }}</span>
              {%- endif -%}
              {%- if img != blank -%}
                {{ img | image_url: width: 900 | image_tag:
                  loading: 'lazy',
                  class: 'gvfp__img',
                  widths: '360, 540, 720, 900',
                  sizes: '(max-width: 640px) 92vw, (max-width: 990px) 45vw, 23vw',
                  alt: product.title
                }}
              {%- endif -%}
            </a>
            <div class="gvfp__info">
              {%- if section.settings.show_vendor -%}
                <div class="gvfp__vendor">{{ product.vendor | escape }}</div>
              {%- endif -%}
              <h3 class="gvfp__name">
                <a class="gvfp__link" href="{{ product.url }}">{{ product.title | escape }}</a>
              </h3>
              {%- comment -%} Short description removed {%- endcomment -%}
              <div class="gvfp__foot">
                {%- if section.settings.show_price -%}
                  <div class="gvfp__price">{{ product.price | money }}</div>
                {%- endif -%}
                {%- if has_one_variant -%}
                  <form method="post" action="/cart/add" class="gvfp__form">
                    <input type="hidden" name="id" value="{{ product.variants.first.id }}">
                    <button type="submit" class="gvfp__btn">Add to cart</button>
                  </form>
                {%- else -%}
                  <a href="{{ product.url }}" class="gvfp__btn">Add to cart</a>
                {%- endif -%}
              </div>
            </div>
          </article>
        {%- endfor -%}
      </div>
      {%- if section.settings.show_view_all -%}
        <div class="gvfp__viewall">
          <a class="gvfp__viewallBtn" href="{{ section.settings.collection.url }}">View all</a>
        </div>
      {%- endif -%}
    {%- endif -%}
  </div>
  <style>
    #{{ sid }}{
      padding: {{ section.settings.padding_top }}px 0 {{ section.settings.padding_bottom }}px;
      --accent: #E10600;
      --radius: 14px;
      /* ✅ Card background always from Dawn scheme (no editor control) */
      --card-bg: var(--color-background);
      /* Content background optional (scheme/custom) */
      --content-bg: {% if section.settings.content_bg_mode == 'scheme' %} var(--color-background) {% else %} {{ section.settings.content_custom_bg }} {% endif %};
      --txt: var(--color-foreground);
      --muted: color-mix(in srgb, var(--color-foreground) 65%, transparent);
      --border: color-mix(in srgb, var(--color-foreground) 12%, transparent);
    }
    #{{ sid }} .gvfp__wrap{ width:min(1200px, 92vw); margin:0 auto; }
    #{{ sid }} .gvfp__head{ margin-bottom: 18px; }
    #{{ sid }} .gvfp__head--left{ text-align:left; }
    #{{ sid }} .gvfp__head--center{ text-align:center; }
    #{{ sid }} .gvfp__head--right{ text-align:right; }
    #{{ sid }} .gvfp__title{
      margin:0 0 6px;
      color: var(--txt);
      font-size: clamp(20px, 2.2vw, 34px);
      letter-spacing:.3px;
      text-transform: uppercase;
      font-weight: 800;
    }
    #{{ sid }} .gvfp__sub{ margin:0; color: var(--muted); }
    #{{ sid }} .gvfp__grid{
      display:grid;
      gap: 18px;
      grid-template-columns: repeat(var(--cols), minmax(0, 1fr));
    }
    @media(max-width:990px){
      #{{ sid }} .gvfp__grid{ grid-template-columns: repeat(2, minmax(0, 1fr)); }
    }
    @media(max-width:640px){
      #{{ sid }} .gvfp__wrap{ width:100%; padding: 0 12px; }
      #{{ sid }} .gvfp__grid{
        grid-template-columns: repeat(var(--cols-m), minmax(0, 1fr));
        gap: 12px;
      }
    }
    #{{ sid }} .gvfp__card{
      background: var(--card-bg);
      border-radius: var(--radius);
      overflow:hidden;
      border: 1px solid var(--border);
      box-shadow: 0 10px 28px rgba(0,0,0,.18);
      transition: transform .22s ease, box-shadow .22s ease, border-color .22s ease;
      display:flex;
      flex-direction:column;
      min-height: 100%;
    }
    #{{ sid }} .gvfp__card:hover{
      transform: translateY(-4px);
      box-shadow: 0 16px 34px rgba(0,0,0,.22);
      border-color: color-mix(in srgb, var(--color-foreground) 20%, transparent);
    }
    @media (prefers-reduced-motion: reduce){
      #{{ sid }} .gvfp__card{ transition:none; }
      #{{ sid }} .gvfp__card:hover{ transform:none; }
    }
    /* ✅ MEDIA: only original image, no background box, no forced height/padding */
    #{{ sid }} .gvfp__media{
      position: relative;
      display:block;
      text-decoration:none;
      color:inherit;
    }
    #{{ sid }} .gvfp__img{
      display:block;
      width:100%;
      height:auto;
    }
    #{{ sid }} .gvfp__badge{
      position:absolute;
      top:12px; left:12px;
      background: var(--accent);
      color:#fff;
      font-weight: 800;
      font-size: 11px;
      letter-spacing:.4px;
      text-transform: uppercase;
      padding: 6px 10px;
      border-radius: 6px;
      z-index: 2;
    }
    #{{ sid }} .gvfp__info{
      background: var(--content-bg);
      padding: 16px 16px 14px;
      display:flex;
      flex-direction:column;
      gap: 8px;
      min-height: 150px;
    }
    #{{ sid }} .gvfp__vendor{
      color: color-mix(in srgb, var(--accent) 80%, transparent);
      font-weight: 800;
      font-size: 11px;
      letter-spacing: 2.2px;
      text-transform: uppercase;
    }
    /* Title clamp (2 lines) to keep footer aligned */
    #{{ sid }} .gvfp__name{
      margin: 0;
      font-weight: 800;
      text-transform: uppercase;
      font-size: 14px;
      line-height: 1.25;
      display:-webkit-box;
      -webkit-box-orient: vertical;
      -webkit-line-clamp: 2;
      overflow:hidden;
      min-height: calc(14px * 1.25 * 2);
    }
    #{{ sid }} .gvfp__link{
      color: var(--txt);
      text-decoration:none;
    }
    #{{ sid }} .gvfp__link:hover{
      color: var(--accent);
      text-decoration:none;
    }
    /* Footer bottom aligned */
    #{{ sid }} .gvfp__foot{
      margin-top: auto;
      display:flex;
      align-items:center;
      justify-content:space-between;
      gap: 10px;
    }
    #{{ sid }} .gvfp__price{
      color: var(--txt);
      font-size: 18px;
      font-weight: 900;
      white-space: nowrap;
    }
    #{{ sid }} .gvfp__btn{
      display:inline-flex;
      align-items:center;
      justify-content:center;
      height: 38px;
      padding: 0 14px;
      background: var(--accent);
      color:#fff;
      border:0;
      border-radius: 0;
      text-decoration:none;
      font-weight: 900;
      letter-spacing: 1.6px;
      text-transform: uppercase;
      font-size: 12px;
      cursor:pointer;
      white-space: nowrap;
      min-width: 128px;
    }
    #{{ sid }} .gvfp__btn:hover{ filter: brightness(.92); }
    #{{ sid }} .gvfp__form{ margin:0; }
    /* ✅ Mobile: button on next row */
    @media(max-width:640px){
      #{{ sid }} .gvfp__foot{
        flex-direction: column;
        align-items: stretch;
      }
      #{{ sid }} .gvfp__btn{
        width: 100%;
        min-width: 0;
      }
    }
    #{{ sid }} .gvfp__viewall{ margin-top: 18px; text-align:center; }
    #{{ sid }} .gvfp__viewallBtn{
      display:inline-flex;
      align-items:center;
      justify-content:center;
      height: 40px;
      padding: 0 18px;
      color: var(--txt);
      text-decoration:none;
      border: 1px solid var(--border);
      border-radius: 10px;
      font-weight: 800;
      letter-spacing: 1.6px;
      text-transform: uppercase;
      font-size: 12px;
    }
    #{{ sid }} .gvfp__viewallBtn:hover{
      border-color: color-mix(in srgb, var(--color-foreground) 25%, transparent);
    }
  </style>
</section>
{% schema %}
{
  "name": "GV Featured Grid",
  "settings": [
    { "type": "color_scheme", "id": "color_scheme", "label": "Color scheme", "default": "background-1" },
    { "type": "text", "id": "heading", "label": "Heading", "default": "Featured Products" },
    { "type": "text", "id": "subheading", "label": "Subheading", "default": "Shop premium GymVaro equipment" },
    { "type": "select", "id": "heading_align", "label": "Heading alignment", "default": "left",
      "options": [
        { "value": "left", "label": "Left" },
        { "value": "center", "label": "Center" },
        { "value": "right", "label": "Right" }
      ]
    },
    { "type": "collection", "id": "collection", "label": "Collection" },
    { "type": "range", "id": "products_to_show", "min": 1, "max": 12, "step": 1, "label": "Products to show", "default": 4 },
    { "type": "range", "id": "columns_desktop", "min": 2, "max": 6, "step": 1, "label": "Columns (desktop)", "default": 4 },
    { "type": "select", "id": "columns_mobile", "label": "Columns (mobile)", "default": "2",
      "options": [
        { "value": "1", "label": "1" },
        { "value": "2", "label": "2" }
      ]
    },
    { "type": "checkbox", "id": "show_vendor", "label": "Show vendor", "default": true },
    { "type": "checkbox", "id": "show_price", "label": "Show price", "default": true },
    { "type": "checkbox", "id": "enable_badges", "label": "Enable badges (sale/new/bestseller by tags)", "default": true },
    { "type": "checkbox", "id": "enable_quick_add", "label": "Quick add (only if 1 variant)", "default": true },
    { "type": "checkbox", "id": "show_view_all", "label": "Show View all", "default": true },
    { "type": "header", "content": "Content background" },
    { "type": "select", "id": "content_bg_mode", "label": "Content background mode", "default": "custom",
      "options": [
        { "value": "scheme", "label": "Use color scheme background" },
        { "value": "custom", "label": "Use custom color" }
      ]
    },
    { "type": "color", "id": "content_custom_bg", "label": "Content background color", "default": "#1c1c1c" },
    { "type": "range", "id": "padding_top", "min": 0, "max": 120, "step": 4, "label": "Padding top", "default": 40 },
    { "type": "range", "id": "padding_bottom", "min": 0, "max": 120, "step": 4, "label": "Padding bottom", "default": 40 }
  ],
  "presets": [
    { "name": "GV Featured Grid" }
  ]
}
{% endschema %}