# Liquid Basics
## Overview
The following are fundamental concepts needed to effectively work with Liquid tags, filters, and objects.
## Object Handles
Objects representing store resources—such as products, collections, articles, and blogs—have handles for identifying individual resources. Handles are used to construct resource URLs or retrieve properties.
Objects like `linklists`, `links`, and `settings` also have handles.
### Creating and Modifying Handles
Handles are automatically generated from resource titles following these rules:
- Always lowercase
- Whitespace and special characters convert to hyphens
- Multiple consecutive special characters become a single hyphen
- Leading whitespace or special characters are removed
Handles must be unique. Duplicate titles result in auto-incremented handles (e.g., `potion` and `potion-1`).
**Important:** Changing a resource title after creation does not update the handle.
You can modify handles in the Shopify admin within the Handle or Edit website SEO sections. When referencing resources by handle, remember to update references if the handle changes.
*Note: Individual linklist links derive handles from titles and cannot be modified directly. Settings get handles from their `id` property.*
### Example
```liquid
{{ product.title | handle }}
```
With data `{"product": {"title": "Health potion"}}`, outputs: `health-potion`
### Referencing Handles
All objects with handles expose a `handle` property. Reference objects by handle using two methods:
**Square bracket notation:** `pages['about-us'].url` (accepts quoted handles, variables, or object references)
**Dot notation:** `settings.predictive_search_enabled` (accepts unquoted handles)
## Logical and Comparison Operators
Liquid supports these operators for conditional tags (`case`, `else`, `if`, `unless`):
| Operator | Function |
|----------|----------|
| `==` | equals |
| `!=` | does not equal |
| `>` | greater than |
| `<` | less than |
| `>=` | greater than or equal to |
| `<=` | less than or equal to |
| `or` | Condition A or Condition B |
| `and` | Condition A and Condition B |
| `contains` | Checks for strings in strings or arrays |
### contains Operator
The `contains` operator checks for strings within arrays or other strings. However, it cannot check for objects within object arrays.
```liquid
{% if product.tags contains 'healing' %}
This potion contains restorative properties.
{% endif %}
```
### Order of Operations
When multiple operators appear in a tag, evaluation proceeds right to left. This order cannot be changed.
**Caution:** Parentheses are invalid in Liquid tags and will prevent rendering.
## Data Types
Liquid output can be one of six data types:
### String
Any character sequence wrapped in single or double quotes. Check if empty using the `blank` object.
### Number
Numeric values including floats and integers.
### Boolean
Binary value: `true` or `false`.
### Nil
An undefined value. Tags or outputs returning `nil` print nothing and are treated as `false`.
*Note: The string "nil" differs from the `nil` value.*
### Array
A list of variables of any type. Access all items using `for` or `tablerow` tags. Use square bracket notation `[ ]` to access specific items (zero-indexed). Arrays cannot be initialized with Liquid alone, though the `split` filter breaks strings into arrays.
### Empty
An `empty` object is returned when accessing defined objects without values (deleted pages/products or valueless settings). Compare objects with `empty` to verify existence before accessing attributes.
```liquid
{% unless pages.about-us == empty %}
<h1>{{ page.title }}</h1>
<div>{{ page.content }}</div>
{% endunless %}
```
## Truthy and Falsy
All data types return either `true` or `false`. Truthy values return true by default; falsy values return false.
| Value | Truthy | Falsy |
|-------|--------|-------|
| `true` | ✓ | |
| `false` | | ✓ |
| `nil` | | ✓ |
| Empty string | ✓ | |
| `0` | ✓ | |
| Integer | ✓ | |
| Float | ✓ | |
| Array | ✓ | |
| Empty array | ✓ | |
| Page | ✓ | |
| Empty object | ✓ | |
### Example
Only `nil` and `false` are falsy. Empty strings are truthy, requiring the `blank` check. EmptyDrop objects are also truthy, requiring `empty` comparison.
```liquid
{% if settings.featured_potions_title != blank -%}
{{ settings.featured_potions_title }}
{%- else -%}
No value selected.
{%- endif %}
```
## Whitespace Control
Liquid tags output lines even when producing no text. Include hyphens in tags to strip generated whitespace. Hyphens on either side control whitespace removal on that side only.
```liquid
{%- if collection.products.size > 0 -%}
The '{{ collection.title }}' collection contains product types:
{% for type in collection.all_types -%}
{% unless type == blank -%}
- {{ type }}
{%- endunless -%}
{%- endfor %}
{%- endif -%}
```
This approach prevents unwanted blank lines in rendered output.