DJson Template Syntax
DJson is a powerful template engine that extends JSON with conditional logic and loops while maintaining valid JSON structure.
DJson Reference
For complete DJson documentation, syntax examples, and advanced features, visit the official DJson documentation at djson.dev
Overview
DJson allows you to:
- Conditionally render sections with @djson if
- Loop through collections with @djson for
- Use variables with {{variable.name}}
- Nest snippets with {{snippet.identifier}}
All while keeping your templates as valid JSON!
Conditional Rendering
Basic If Statement
Show a section only when a condition is met:
{
"@type": "Product",
"name": "{{product.name}}",
"@djson if product.manufacturer": {
"brand": {
"@type": "Brand",
"name": "{{product.manufacturer}}"
}
}
}
How it works:
1. DJson checks if product.manufacturer exists in the context
2. If it exists and is truthy, the brand section is included
3. If it doesn't exist or is null/empty, the entire brand section is removed
Output when manufacturer exists:
Output when manufacturer doesn't exist:
Multiple Conditional Sections
You can have multiple conditional sections in the same object:
{
"@type": "Product",
"name": "{{product.name}}",
"@djson if product.manufacturer": {
"brand": {
"@type": "Brand",
"name": "{{product.manufacturer}}"
}
},
"@djson if product.reviewCount": {
"aggregateRating": {
"@type": "AggregateRating",
"ratingValue": "{{product.ratingValue}}",
"reviewCount": "{{product.reviewCount}}"
}
}
}
Nested Conditionals
Conditionals can be nested:
{
"@type": "Product",
"@djson if product.reviewCount": {
"aggregateRating": "{{snippet.aggregate-rating}}",
"review": {
"@djson for productReviews as review": {
"@type": "Review",
"author": "{{review.nickname}}"
}
}
}
}
Loop Syntax
Basic Loop
Iterate through a collection:
{
"@type": "ItemList",
"itemListElement": {
"@djson for products as product": {
"@type": "ListItem",
"position": "{{product.position}}",
"name": "{{product.name}}"
}
}
}
Input Context:
[
'products' => [
['position' => '1', 'name' => 'Product A'],
['position' => '2', 'name' => 'Product B'],
['position' => '3', 'name' => 'Product C']
]
]
Output:
{
"@type": "ItemList",
"itemListElement": [
{
"@type": "ListItem",
"position": "1",
"name": "Product A"
},
{
"@type": "ListItem",
"position": "2",
"name": "Product B"
},
{
"@type": "ListItem",
"position": "3",
"name": "Product C"
}
]
}
Loop Variable Access
Inside a loop, use the loop variable as a prefix:
{
"@djson for productReviews as review": {
"@type": "Review",
"author": "{{review.nickname}}",
"reviewBody": "{{review.detail}}",
"datePublished": "{{review.createdAt}}"
}
}
Loop Variable Naming:
- Collection: productReviews
- Loop variable: review (singular)
- Access fields: {{review.field_name}}
Nested Loops
Loops can be nested (though use sparingly for performance):
{
"@djson for categories as category": {
"@type": "Category",
"name": "{{category.name}}",
"products": {
"@djson for category.products as product": {
"@type": "Product",
"name": "{{product.name}}"
}
}
}
}
Empty Collections
If a collection is empty, the loop produces an empty array:
Output when no reviews:
Combining Conditionals and Loops
Loop Inside Conditional
Show reviews only if they exist:
{
"@type": "Product",
"name": "{{product.name}}",
"@djson if product.reviewCount": {
"review": {
"@djson for productReviews as review": {
"@type": "Review",
"author": {
"@type": "Person",
"name": "{{review.nickname}}"
},
"reviewBody": "{{review.detail}}",
"datePublished": "{{review.createdAt}}"
}
}
}
}
Benefits: - Entire review section is hidden when no reviews exist - Cleaner output without empty arrays - Better Schema.org compliance
Conditional Inside Loop
Apply conditions to each loop item:
{
"@djson for products as product": {
"@type": "Product",
"name": "{{product.name}}",
"@djson if product.specialPrice": {
"offers": {
"@type": "Offer",
"price": "{{product.specialPrice}}"
}
}
}
}
Real-World Examples
Example 1: Product with Optional Features
{
"@context": "https://schema.org/",
"@type": "Product",
"name": "{{product.name}}",
"description": "{{product.shortDescription}}",
"sku": "{{product.sku}}",
"image": "{{product.image}}",
"@djson if product.manufacturer": {
"brand": {
"@type": "Brand",
"name": "{{product.manufacturer}}"
}
},
"offers": {
"@type": "Offer",
"price": "{{product.finalPrice}}",
"priceCurrency": "{{store.currencyCode}}",
"availability": "{{enum.availability.InStock}}"
},
"@djson if product.reviewCount": {
"aggregateRating": {
"@type": "AggregateRating",
"ratingValue": "{{product.ratingValue}}",
"reviewCount": "{{product.reviewCount}}",
"bestRating": "5"
},
"review": {
"@djson for productReviews as review": {
"@type": "Review",
"author": {
"@type": "Person",
"name": "{{review.nickname}}"
},
"reviewBody": "{{review.detail}}",
"datePublished": "{{review.createdAt}}"
}
}
}
}
What this does: 1. Always shows basic product info (name, SKU, image, offers) 2. Conditionally shows brand if manufacturer exists 3. Conditionally shows ratings and reviews if reviews exist 4. Loops through all reviews when they exist
Example 2: Breadcrumb Navigation
{
"@context": "https://schema.org/",
"@type": "BreadcrumbList",
"itemListElement": {
"@djson for breadcrumbs as breadcrumb": {
"@type": "ListItem",
"position": "{{breadcrumb.position}}",
"name": "{{breadcrumb.label}}",
"item": "{{breadcrumb.link}}"
}
}
}
Output:
{
"@context": "https://schema.org/",
"@type": "BreadcrumbList",
"itemListElement": [
{
"@type": "ListItem",
"position": "1",
"name": "Home",
"item": "https://example.com/"
},
{
"@type": "ListItem",
"position": "2",
"name": "Gear",
"item": "https://example.com/gear.html"
},
{
"@type": "ListItem",
"position": "3",
"name": "Bags",
"item": "https://example.com/gear/bags.html"
}
]
}
Example 3: Category Product Listing
{
"@context": "https://schema.org/",
"@type": "ItemList",
"itemListElement": {
"@djson for products as product": {
"@type": "ListItem",
"position": "{{product.position}}",
"url": "{{product.productUrl}}",
"name": "{{product.name}}",
"@djson if product.image": {
"image": "{{product.image}}"
}
}
}
}
Example 4: FAQ with Dynamic Questions
{
"@context": "https://schema.org/",
"@type": "FAQPage",
"mainEntity": {
"@djson for faqItems as faq": {
"@type": "Question",
"name": "{{faq.question}}",
"acceptedAnswer": {
"@type": "Answer",
"text": "{{faq.answer}}"
}
}
}
}
DJson Syntax Rules
Valid Conditional Placement
✅ Correct:
❌ Incorrect:
Valid Loop Placement
✅ Correct:
❌ Incorrect:
Condition Evaluation
Conditions are truthy if:
- Variable exists in context
- Value is not null
- Value is not empty string ""
- Value is not false
- Value is not 0
Conditions are falsy if:
- Variable doesn't exist
- Value is null, "", false, or 0
Performance Considerations
Keep Loops Shallow
✅ Good:
❌ Avoid:
{
"@djson for categories as category": {
"@djson for category.products as product": {
"@djson for product.reviews as review": {
"@type": "Review"
}
}
}
}
Use Conditionals to Reduce Nesting
✅ Good:
{
"@djson if product.reviewCount": {
"review": {
"@djson for productReviews as review": {
"@type": "Review"
}
}
}
}
✅ Better:
{
"@djson if product.reviewCount": {
"aggregateRating": "{{snippet.aggregate-rating}}",
"review": "{{snippet.review-list}}"
}
}
Debugging DJson
Enable Pretty Print
- Navigate to:
Stores→Configuration→Qoliber→SEO: Rich Snippets - Set Debug Mode to pretty
- View page source to see formatted JSON
Check Logs
Debug information is logged to var/log/debug.log:
[2024-11-18 10:00:00] main.DEBUG: Final context for DJson {"snippet_name":"product","has_productReviews":true,"review_count":3}
Common Issues
Issue: Loop not producing output
Solution: Check that: 1. Collection name is correct 2. Collection is in context 3. Collection is not empty 4. Loop variable syntax is correct
Issue: Conditional always false
Solution: Check that:
1. Variable exists in context
2. Variable is not null or empty
3. Condition syntax is correct: @djson if variable.name
Advanced DJson Patterns
Pattern: Fallback Values
Use nested snippets for complex fallbacks:
{
"@djson if product.specialPrice": {
"price": "{{product.specialPrice}}"
},
"@djson if !product.specialPrice": {
"price": "{{product.price}}"
}
}
Note: DJson doesn't support ! negation directly. Use separate snippets instead.
Pattern: Reusable Components
Create small, reusable snippet components:
Component: product-offer snippet
Usage:
Pattern: Conditional Snippets
Combine conditionals with snippets:
Next Steps
- Review Variables Reference for available variables
- Explore Default Snippets for real examples
- Read Advanced Topics for custom collections