# Liquid Context Reference Guide

**Complete reference of Liquid drops, filters, and context available in Modyo templates, pages, and widgets.**

---

## Table of Contents

1. [Overview](#overview)
2. [Liquid in Modyo](#liquid-in-modyo)
3. [Context by Resource Type](#context-by-resource-type)
4. [Global Drops](drops-and-filters.md#global-drops)
5. [Page-Specific Drops](drops-and-filters.md#page-specific-drops)
6. [Content Drops](drops-and-filters.md#content-drops)
7. [Navigation Drops](drops-and-filters.md#navigation-drops)
8. [User & Session Drops](drops-and-filters.md#user--session-drops)
9. [Modyo-Specific Filters](drops-and-filters.md#modyo-specific-filters)
10. [Common Patterns](drops-and-filters.md#common-patterns)
11. [Limitations](drops-and-filters.md#limitations)
12. [Best Practices](drops-and-filters.md#best-practices)

---

## Overview

**What is Liquid?**

Liquid is a templating language created by Shopify. Modyo uses Liquid for dynamic content rendering in:
- Layouts
- Page templates
- Snippets
- Widget HTML
- CSS templates (limited)
- JS templates (limited)

**Liquid Syntax**:
```liquid
{{ variable }}           <!-- Output variable -->
{% if condition %}       <!-- Control flow -->
{% for item in items %}  <!-- Iteration -->
{{ item | filter }}      <!-- Apply filter -->
{% snippet 'name' %}     <!-- Include snippet -->
```

**Key Concept: Drops**

"Drops" are objects available in Liquid context. Modyo provides specific drops depending on where the code executes:

```liquid
{{ site.name }}         <!-- site drop -->
{{ page.title }}        <!-- page drop -->
{{ current_user.name }} <!-- user drop -->
{{ menus['main'] }}     <!-- menus drop -->
```

---

## Liquid in Modyo

### Where Liquid Works

| Resource | Liquid Support | Private Drops | CDN Cached |
|----------|----------------|---------------|------------|
| **Layouts** | ✅ Full | ✅ Yes | ❌ Server-rendered |
| **Page Templates** | ✅ Full | ✅ Yes | ❌ Server-rendered |
| **Snippets** | ✅ Full | ✅ Yes | ❌ Server-rendered |
| **Widget HTML** | ✅ Full | ✅ Yes | ❌ Server-rendered |
| **CSS Templates** | ⚠️ Partial | ❌ No | ✅ CDN-cached |
| **JS Templates** | ⚠️ Partial | ❌ No | ✅ CDN-cached |

### Full vs Partial Liquid Support

**Full Liquid (Layouts, Snippets, Pages, Widgets)**:
```liquid
<!-- ✅ All drops available -->
{{ site.url }}
{{ page.title }}
{{ current_user.name }}
{{ session.authenticated }}

<!-- ✅ All tags available -->
{% if current_user %}
{% for entry in entries %}
{% snippet 'header' %}

<!-- ✅ All filters available -->
{{ product.price | money }}
{{ entry.published_at | date: "%B %d, %Y" }}
```

**Partial Liquid (CSS/JS Templates)**:
```liquid
<!-- ✅ Public drops available -->
{{ site.url }}
{{ spaces['blog'].types['post'].entries }}

<!-- ✅ Snippets available -->
{% snippet 'colors' %}

<!-- ❌ Private drops NOT available -->
{{ current_user.name }}     <!-- FAILS -->
{{ session.authenticated }} <!-- FAILS -->

<!-- ✅ Tags and filters work -->
{% for color in colors %}
{{ entry.title | upcase }}
```

**Why the limitation?** CSS/JS templates are CDN-cached. Private user data would be cached and served to wrong users.

**See**: [CSS_ORGANIZATION.md](CSS_ORGANIZATION.md) for complete CSS/JS template guide.

---

## Context by Resource Type

### Layouts

**Available Drops**: ALL (full Liquid support)

**Context**:
```liquid
{{ site }}              <!-- Site object -->
{{ page }}              <!-- Current page object -->
{{ menus }}             <!-- All published menus -->
{{ spaces }}            <!-- All published spaces -->
{{ current_user }}      <!-- Current user (if authenticated) -->
{{ session }}           <!-- Session object -->
{{ html5 }}             <!-- HTML5 helpers -->
{{ content_for_layout }}<!-- Page content placeholder -->
```

**Example Layout**:
```liquid
{{ html5.open_tag }}
<head>
  {% snippet 'head' %}
  <title>{{ page.title }} - {{ site.name }}</title>
</head>
<body>
  {% snippet 'header' %}

  <main>
    {{ content_for_layout }}  <!-- Page renders here -->
  </main>

  {% snippet 'footer' %}
</body>
{{ html5.close_tag }}
```

### Page Templates (Content Pages)

**Available Drops**: ALL + content-specific drops

**Context**:
```liquid
{{ site }}              <!-- Site object -->
{{ page }}              <!-- Current content page -->
{{ menus }}             <!-- All published menus -->
{{ spaces }}            <!-- All published spaces -->
{{ current_user }}      <!-- Current user -->
{{ session }}           <!-- Session object -->

<!-- Content-specific drops -->
{{ entries }}           <!-- All entries of type (index template) -->
{{ entry }}             <!-- Single entry (show template) -->
{{ categories }}        <!-- Categories for space -->
```

**Example Index Template** (`/blog`):
```liquid
<div class="blog-index">
  <h1>{{ page.name }}</h1>

  {% for entry in entries %}
    <article>
      <h2>
        <a href="/blog/{{ entry.slug }}">
          {{ entry.fields['Title'] }}
        </a>
      </h2>
      <p>{{ entry.fields['Excerpt'] }}</p>
      <time>{{ entry.published_at | date: "%B %d, %Y" }}</time>
    </article>
  {% endfor %}
</div>
```

**Example Show Template** (`/blog/{slug}`):
```liquid
<article class="blog-post">
  <h1>{{ entry.fields['Title'] }}</h1>
  <time>{{ entry.published_at | date: "%B %d, %Y" }}</time>

  <div class="content">
    {{ entry.fields['Body'] }}
  </div>

  {% if entry.fields['Author'] %}
    <div class="author">
      By {{ entry.fields['Author'] }}
    </div>
  {% endif %}
</article>
```

### Snippets

**Available Drops**: ALL (full Liquid support)

**Context**: Same as layouts + any variables passed via `with` parameter

```liquid
<!-- Calling snippet -->
{% snippet 'product_card' with product %}

<!-- Inside product_card snippet -->
<div class="product-card">
  <h3>{{ product.name }}</h3>
  <p>{{ product.price | money }}</p>

  <!-- Can also access global drops -->
  <a href="{{ site.url }}/products/{{ product.slug }}">
    View Details
  </a>
</div>
```

### Widget HTML

**Available Drops**: ALL (full Liquid support)

**Context**:
```liquid
{{ site }}              <!-- Site object -->
{{ page }}              <!-- Current page -->
{{ menus }}             <!-- All menus -->
{{ spaces }}            <!-- All spaces -->
{{ current_user }}      <!-- Current user -->
{{ session }}           <!-- Session -->
{{ variables }}         <!-- Widget variables -->
```

**Example Widget**:
```liquid
<div class="product-carousel">
  <h2>{{ variables.title }}</h2>

  {% assign products = spaces['catalog'].types['product'].entries %}

  {% for product in products limit: variables.limit %}
    <div class="product-slide">
      <img src="{{ product.fields['Image'] }}" alt="{{ product.fields['Name'] }}">
      <h3>{{ product.fields['Name'] }}</h3>
      <p>{{ product.fields['Price'] | money }}</p>

      {% if current_user %}
        <button>Add to Cart</button>
      {% else %}
        <a href="/login">Login to Purchase</a>
      {% endif %}
    </div>
  {% endfor %}
</div>
```

### CSS Templates

**Available Drops**: Public drops only (NO private drops)

**Context**:
```liquid
<!-- ✅ Allowed -->
{{ site.url }}
{{ spaces['blog'].types['post'].entries }}
{% snippet 'colors' %}

<!-- ❌ NOT allowed -->
{{ current_user.name }}
{{ session.authenticated }}
```

**Example CSS Template**:
```liquid
/* Import color variables from snippet */
{% snippet 'colors' %}

/* Use public drops */
.site-link::after {
  content: "{{ site.name }}";
}

/* Dynamic styles from content */
{% assign themes = spaces['config'].types['theme'].entries %}
{% for theme in themes %}
  .theme-{{ theme.slug }} {
    --primary: {{ theme.fields['Primary Color'] }};
    --secondary: {{ theme.fields['Secondary Color'] }};
  }
{% endfor %}
```

### JS Templates

**Available Drops**: Public drops only (NO private drops)

**Context**: Same as CSS templates

**Example JS Template**:
```liquid
// Site configuration
window.SITE_CONFIG = {
  name: "{{ site.name }}",
  url: "{{ site.url }}",
  locale: "{{ site.default_locale }}"
};

// Dynamic config from content
{% assign config = spaces['config'].types['settings'].entries | first %}
window.APP_CONFIG = {
  apiUrl: "{{ config.fields['API URL'] }}",
  gaId: "{{ config.fields['Google Analytics ID'] }}"
};

// ❌ CAN'T USE
// user: {
//   name: "{{ current_user.name }}"  // FAILS - private drop
// }
```

---
