Advanced Logic
Complex patterns, state machines, and performance optimization
This guide covers advanced Liquid patterns for power users who need to implement complex business logic, state management, and data transformations.
Advanced Liquid Patterns
Custom Helper Functions
While Liquid doesn't support custom functions directly, you can simulate them with assign blocks and variables.
{% comment %} Calculate tax helper {% endcomment %}
{% liquid
assign _price = include.price
assign _taxRate = include.taxRate | default: 0.1
assign _tax = _price | times: _taxRate
assign result = _tax
%}
{% comment %} Usage {% endcomment %}
{% liquid
assign include = ""
assign include.price = subtotal
assign include.taxRate = 0.15
%}
Tax: ${{ result }}
State Machines
Create complex workflows with state tracking. This is useful for multi-step processes where the path depends on a combination of previous actions.
{% liquid
assign state = current_state | default: "initial"
assign nextState = ""
case state
when "initial"
if has_account == "yes"
assign nextState = "login"
else
assign nextState = "registration"
endif
when "login"
if login_successful == "yes"
assign nextState = "dashboard"
else
assign nextState = "password-reset"
endif
when "registration"
if registration_complete == "yes"
assign nextState = "verification"
endif
when "verification"
if verified == "yes"
assign nextState = "dashboard"
endif
endcase
%}
{{ nextState }}
Data Transformation Pipelines
Chain multiple transformations to clean and format data.
{% liquid
assign raw = user_input
assign cleaned = raw | strip | downcase
assign words = cleaned | split: " "
assign unique = words | uniq
assign sorted = unique | sort_natural
assign result = sorted | join: ", "
%}
Processed: {{ result }}
Common Advanced Patterns
Pattern 1: Multi-Stage Approval Workflow
{% liquid
assign stage = approval_stage | default: "pending"
assign nextStage = ""
if stage == "pending"
if manager_approved == "yes"
assign nextStage = "director-review"
else
assign nextStage = "rejected"
endif
elsif stage == "director-review"
if director_approved == "yes"
assign nextStage = "final-approval"
else
assign nextStage = "rejected"
endif
elsif stage == "final-approval"
if ceo_approved == "yes"
assign nextStage = "approved"
else
assign nextStage = "rejected"
endif
endif
echo nextStage
%}
Pattern 2: Dynamic Pricing Engine
{% liquid
assign basePrice = base_price
assign quantity = quantity
# Volume discount
if quantity >= 100
assign volumeDiscount = 0.2
elsif quantity >= 50
assign volumeDiscount = 0.15
elsif quantity >= 10
assign volumeDiscount = 0.1
else
assign volumeDiscount = 0
endif
# Loyalty discount
if loyalty_years >= 5
assign loyaltyDiscount = 0.1
elsif loyalty_years >= 2
assign loyaltyDiscount = 0.05
else
assign loyaltyDiscount = 0
endif
# Calculate
assign subtotal = basePrice | times: quantity
assign volumeSavings = subtotal | times: volumeDiscount
assign afterVolume = subtotal | minus: volumeSavings
assign loyaltySavings = afterVolume | times: loyaltyDiscount
assign total = afterVolume | minus: loyaltySavings
%}
Subtotal: ${{ subtotal }}
Volume Discount (-{{ volumeDiscount | times: 100 }}%): -${{ volumeSavings }}
Loyalty Discount (-{{ loyaltyDiscount | times: 100 }}%): -${{ loyaltySavings }}
Total: ${{ total }}
Pattern 3: Risk Assessment Scoring
{% liquid
assign riskScore = 0
# Age factor
assign age = birth_date | diff_time: today, "year"
if age < 25
assign riskScore = riskScore | plus: 20
elsif age < 35
assign riskScore = riskScore | plus: 10
endif
# Income factor
assign income = annual_income
if income < 30000
assign riskScore = riskScore | plus: 30
elsif income < 60000
assign riskScore = riskScore | plus: 15
endif
# Credit history
if credit_score < 600
assign riskScore = riskScore | plus: 40
elsif credit_score < 700
assign riskScore = riskScore | plus: 20
endif
# Determine level
if riskScore >= 60
assign riskLevel = "High"
assign approved = false
elsif riskScore >= 30
assign riskLevel = "Medium"
assign approved = true
else
assign riskLevel = "Low"
assign approved = true
endif
%}
Risk Score: {{ riskScore }}
Risk Level: {{ riskLevel }}
{% if approved %}Approved{% else %}Denied{% endif %}
Performance Optimization
Minimize Repeated Calculations
❌ Inefficient:
Total: {{ price | times: quantity | times: 1.1 }}
Tax: {{ price | times: quantity | times: 0.1 }}
Subtotal: {{ price | times: quantity }}
✅ Efficient:
{% assign subtotal = price | times: quantity %}
Subtotal: {{ subtotal }}
Tax: {{ subtotal | times: 0.1 }}
Total: {{ subtotal | times: 1.1 }}
Cache Complex Lookups
{% liquid
assign userType = membership
case userType
when "platinum"
assign discount = 0.25
assign priority = 1
assign support = "24/7"
when "gold"
assign discount = 0.15
assign priority = 2
assign support = "business hours"
else
assign discount = 0
assign priority = 5
assign support = "email only"
endcase
%}
Avoid Nested Loops
❌ Slow:
{% for item in items %}
{% for category in categories %}
{% if item.category == category.id %}
{{ item.name }} - {{ category.name }}
{% endif %}
{% endfor %}
{% endfor %}
✅ Better:
{% assign categoryMap = categories | map: "id" %}
{% for item in items %}
{{ item.name }} - {{ categoryMap[item.category] }}
{% endfor %}
Debugging Techniques
Output Debugging
DEBUG: {{ values | json: 2 }}
Step-by-Step Tracing
{% liquid
echo "Step 1: Input = " | append: input
assign cleaned = input | strip
echo "\nStep 2: Cleaned = " | append: cleaned
assign processed = cleaned | upcase
echo "\nStep 3: Processed = " | append: processed
%}
Conditional Debugging
{% if debug_mode == "yes" %}
<pre>
Values: {{ values | json: 2 }}
Calculations:
- Subtotal: {{ subtotal }}
- Tax: {{ tax }}
- Total: {{ total }}
</pre>
{% endif %}
