Twig Filters Reference
Total CMS extends Twig with powerful custom filters for text processing, color manipulation, array handling, and more. This reference includes usage examples for each filter.
Text Filters
Section titled “Text Filters”String Manipulation
Section titled “String Manipulation”humanize(string $slug, string $sep = '-'): string
Section titled “humanize(string $slug, string $sep = '-'): string”Converts slugs to human-readable text.
{{ "hello-world" | humanize }}{# Output: Hello World #}
{{ "first_name" | humanize('_') }}{# Output: First Name #}titleize(string $slug, string $sep = '-'): string
Section titled “titleize(string $slug, string $sep = '-'): string”Converts to title case with proper capitalization.
{{ "the-quick-brown-fox" | titleize }}{# Output: The Quick Brown Fox #}
{{ "api_response_data" | titleize('_') }}{# Output: API Response Data #}basename(string $file): string
Section titled “basename(string $file): string”Extracts filename from path.
{{ "/path/to/document.pdf" | basename }}{# Output: document.pdf #}
{% set upload = cms.file('manual') %}<p>Download: {{ upload.file | basename }}</p>dirname(string $file): string
Section titled “dirname(string $file): string”Extracts directory from path.
{{ "/var/www/uploads/image.jpg" | dirname }}{# Output: /var/www/uploads #}String Trimming
Section titled “String Trimming”trim(string $string): string
Section titled “trim(string $string): string”Removes whitespace from both sides.
{{ " Hello World " | trim }}{# Output: "Hello World" #}rtrim(string $string): string
Section titled “rtrim(string $string): string”Removes whitespace from the right side.
{{ " Hello World " | rtrim }}{# Output: " Hello World" #}ltrim(string $string): string
Section titled “ltrim(string $string): string”Removes whitespace from the left side.
{{ " Hello World " | ltrim }}{# Output: "Hello World " #}Case Conversion
Section titled “Case Conversion”ucwords(string $string): string
Section titled “ucwords(string $string): string”Capitalizes the first letter of each word.
{{ "hello world" | ucwords }}{# Output: "Hello World" #}lcfirst(string $string): string
Section titled “lcfirst(string $string): string”Lowercases the first character of a string.
{{ "Hello World" | lcfirst }}{# Output: "hello World" #}Text Truncation
Section titled “Text Truncation”truncate(string $string, int $length, bool $keepWords = false): string
Section titled “truncate(string $string, int $length, bool $keepWords = false): string”Truncates text to specified length.
{% set post = cms.collection.object('blog', 'my-post') %}
{# Character-based truncation #}{{ post.content | truncate(100) }}
{# Word-safe truncation #}{{ post.content | truncate(100, true) }}
{# Usage in blog listing #}{% for post in cms.collection.objects('blog') %} <article> <h2>{{ post.title }}</h2> <p>{{ post.excerpt | truncate(150, true) }}...</p> </article>{% endfor %}truncateWords(string $string, int $length): string
Section titled “truncateWords(string $string, int $length): string”Truncates by word count instead of characters.
{{ post.content | truncateWords(25) }}{# Truncates to first 25 words #}
{# Perfect for excerpts #}<p class="excerpt">{{ post.content | truncateWords(30) }}...</p>Text Analysis
Section titled “Text Analysis”charcount(string $text): int
Section titled “charcount(string $text): int”Counts characters in text.
{% set content = cms.text('about-us') %}<p>About us ({{ content.text | charcount }} characters)</p>
{# Validation in forms #}{% if post.title | charcount > 100 %} <span class="error">Title too long</span>{% endif %}wordcount(string $text): int
Section titled “wordcount(string $text): int”Counts words in text.
{{ post.content | wordcount }} words
{# Reading time calculation #}{% set words = post.content | wordcount %}<time>{{ (words / 200) | round }} min read</time>readtime(string $text, int $wpm = 180): float
Section titled “readtime(string $text, int $wpm = 180): float”Calculates reading time in minutes.
{{ post.content | readtime }} min read{{ post.content | readtime(250) }} min read (fast reader)
{# Display reading time #}<div class="meta"> <span>{{ post.content | readtime | round }} minute read</span></div>Specialized Text Processing
Section titled “Specialized Text Processing”digitsOnly(string $text): string
Section titled “digitsOnly(string $text): string”Extracts only digits from text.
{{ "Phone: (555) 123-4567" | digitsOnly }}{# Output: 5551234567 #}
{# Clean phone numbers for tel: links #}<a href="tel:{{ contact.phone | digitsOnly }}"> {{ contact.phone | formatPhone }}</a>formatPhone(string $string, string $countryCode = 'US'): string
Section titled “formatPhone(string $string, string $countryCode = 'US'): string”Formats phone numbers by country.
{{ "5551234567" | formatPhone }}{# Output: (555) 123-4567 #}
{{ "5551234567" | formatPhone('CA') }}{# Output: (555) 123-4567 #}
{# Format contact information #}{% for contact in api('contact') %} <p>{{ contact.name }}: {{ contact.phone | formatPhone }}</p>{% endfor %}prefixSlug(string|array $value, string $prefix = '', string $separator = ' '): string
Section titled “prefixSlug(string|array $value, string $prefix = '', string $separator = ' '): string”Slugifies and optionally prefixes a string or array of strings. Useful for generating CSS classes, HTML attributes, or URL-safe identifiers from user content.
{# Basic array with prefix - great for tag CSS classes #}{{ post.tags | prefixSlug('tag-') }}{# Input: ['Web Design', 'UI/UX'] → Output: "tag-web-design tag-ui-ux" #}
{# Single string #}{{ "Hello World" | prefixSlug('prefix-') }}{# Output: "prefix-hello-world" #}
{# Custom separator #}{{ post.tags | prefixSlug('tag-', ', ') }}{# Input: ['php', 'javascript'] → Output: "tag-php, tag-javascript" #}
{# No prefix - just slugify and join #}{{ post.tags | prefixSlug }}{# Input: ['Web Design', 'UI/UX'] → Output: "web-design ui-ux" #}
{# Empty items are automatically filtered out #}{{ ['foo', '', 'bar'] | prefixSlug('x-') }}{# Output: "x-foo x-bar" #}Parameters:
value- String or array of strings to processprefix- String to prepend to each slugified item (default:'')separator- String used to join items (default:' 'space)
Real-World Examples:
{# Generate CSS classes for tags #}<article class="{{ post.tags | prefixSlug('tag-') }}"> {{ post.content }}</article>
{# Create data attributes #}<div data-categories="{{ post.categories | prefixSlug('', ',') }}">
{# Filter controls #}{% for tag in allTags %} <button class="filter-btn" data-filter=".tag-{{ tag | prefixSlug }}"> {{ tag }} </button>{% endfor %}
{# Body class based on page sections #}<body class="page-{{ page.id | prefixSlug }} {{ page.sections | prefixSlug('section-') }}">svgToSymbol(string $svg, string $symbolId): string
Section titled “svgToSymbol(string $svg, string $symbolId): string”Converts SVG to symbol for icon systems.
{% set icon = cms.svg('home-icon') %}{{ icon.svg | svgToSymbol('home') }}
{# Create icon library #}<svg style="display: none;"> {% for icon in cms.collection.objects('svg') %} {{ icon.content | svgToSymbol(icon.id) }} {% endfor %}</svg>
{# Use icons #}<svg><use href="#home"></use></svg>Markdown Filters
Section titled “Markdown Filters”markdown(mixed $value): string
Section titled “markdown(mixed $value): string”Processes full markdown syntax including block elements (paragraphs, headers, lists, etc.).
{% set content = "This is **bold** and [a link](https://example.com)" %}{{ content | markdown }}{# Output: <p>This is <strong>bold</strong> and <a href="https://example.com">a link</a></p> #}
{# Process blog post content #}<article> {{ post.content | markdown }}</article>
{# Markdown with tables and code blocks #}{{ documentation.content | markdown }}Features:
- Full markdown syntax support (headers, lists, blockquotes, etc.)
- GitHub Flavored Markdown (tables, fenced code blocks)
- Extended features (footnotes, definition lists)
- Wraps content in appropriate block elements (
<p>,<h1>, etc.)
markdownInline(mixed $value): string
Section titled “markdownInline(mixed $value): string”Processes only inline markdown syntax without wrapping content in <p> tags or other block elements. Perfect for processing markdown within existing HTML elements.
{% set text = "This is **bold** and [a link](https://example.com)" %}{{ text | markdownInline }}{# Output: This is <strong>bold</strong> and <a href="https://example.com">a link</a> #}
{# Use in headings #}<h2>{{ page.title | markdownInline }}</h2>
{# Use in existing paragraphs #}<p class="description">{{ product.tagline | markdownInline }}</p>
{# Use in list items #}<ul> {% for feature in product.features %} <li>{{ feature | markdownInline }}</li> {% endfor %}</ul>Supported Inline Syntax:
- Bold:
**text**→<strong>text</strong> - Italic:
*text*→<em>text</em> - Code:
`code`→<code>code</code> - Links:
[text](url)→<a href="url">text</a> - Auto-links:
<https://example.com>→<a href="...">...</a> - Images:
→<img src="url" alt="alt" /> - Combined styles:
**bold** with *italic*works perfectly
When to Use:
- Processing markdown within existing HTML tags
- Headings, button labels, or navigation items with markdown
- Form field labels or help text with formatting
- List items or table cells with inline formatting
- Meta descriptions or short text snippets
Comparison:
{# markdown filter - adds <p> wrapper #}{{ "Visit our **website**" | markdown }}{# Output: <p>Visit our <strong>website</strong></p> #}
{# markdownInline filter - no wrapper #}{{ "Visit our **website**" | markdownInline }}{# Output: Visit our <strong>website</strong> #}Real-World Examples:
{# Product features with inline formatting #}<ul class="features"> {% for feature in product.features %} <li>{{ feature | markdownInline }}</li> {# Input: "**High-speed** processing with *low power*" #} {# Output: <strong>High-speed</strong> processing with <em>low power</em> #} {% endfor %}</ul>
{# Page titles with emphasis #}<h1>{{ page.title | markdownInline }}</h1>{# Input: "Welcome to our **Amazing** Store!" #}{# Output: Welcome to our <strong>Amazing</strong> Store! #}
{# Navigation with inline links #}<nav> {% for item in menu %} <a href="{{ item.url }}">{{ item.label | markdownInline }}</a> {% endfor %}</nav>
{# Meta descriptions #}<meta name="description" content="{{ page.meta | markdownInline | striptags }}">
{# Testimonial quotes with formatting #}<blockquote> {{ testimonial.quote | markdownInline }} <cite>{{ testimonial.author }}</cite></blockquote>Security Note: Both markdown filters run in safe mode with XSS protection enabled.
Email and HTML Encoding
Section titled “Email and HTML Encoding”htmlencode(string $text): string
Section titled “htmlencode(string $text): string”Encodes text to HTML entities, useful for obfuscating email addresses from scrapers.
{{ "user@example.com" | htmlencode }}{# Output: user@example.com #}
{# Useful for displaying emails without making them easily scrapable #}<span>Contact: {{ contact.email | htmlencode }}</span>htmldecode(string $text): string
Section titled “htmldecode(string $text): string”Decodes HTML entities back to their original characters. Alias for html_entity_decode.
{{ "&copy; 2024" | htmldecode }}{# Output: © 2024 #}
{{ "<div>Hello</div>" | htmldecode }}{# Output: <div>Hello</div> #}
{# Useful when processing content from external sources #}{{ externalContent.title | htmldecode }}URL Encoding
Section titled “URL Encoding”urlencode(string $string): string
Section titled “urlencode(string $string): string”URL-encodes a string.
{{ "hello world" | urlencode }}{# Output: hello+world #}
<a href="/search?q={{ searchTerm | urlencode }}">Search</a>urldecode(string $string): string
Section titled “urldecode(string $string): string”Decodes a URL-encoded string.
{{ "hello+world" | urldecode }}{# Output: hello world #}rawurlencode(string $string): string
Section titled “rawurlencode(string $string): string”URL-encodes a string according to RFC 3986 (spaces become %20).
{{ "hello world" | rawurlencode }}{# Output: hello%20world #}Security Filters
Section titled “Security Filters”obfuscate(string $string): string
Section titled “obfuscate(string $string): string”Obfuscates a string for basic protection. Reversible with deobfuscate.
{{ "secret-data" | obfuscate }}deobfuscate(string $string): string
Section titled “deobfuscate(string $string): string”Reverses obfuscation applied by obfuscate.
{{ obfuscatedString | deobfuscate }}encrypt(string $string): string
Section titled “encrypt(string $string): string”Encrypts a string using the application’s encryption key.
{{ sensitiveData | encrypt }}decrypt(string $string): string
Section titled “decrypt(string $string): string”Decrypts a string that was encrypted with encrypt.
{{ encryptedData | decrypt }}mailto(string $email, string $subject = '', string $body = '', string $title = ''): string
Section titled “mailto(string $email, string $subject = '', string $body = '', string $title = ''): string”Creates an obfuscated mailto link that protects email addresses from spam bots. The email is not visible in the raw HTML source and is decoded via JavaScript.
{# Basic usage #}{{ "info@example.com" | mailto }}
{# With subject #}{{ "support@example.com" | mailto("Support Request") }}
{# With subject and body #}{{ "sales@example.com" | mailto("Product Inquiry", "I'm interested in your products...") }}
{# With custom link title #}{{ "contact@example.com" | mailto("", "", "Contact Our Team") }}
{# Real-world examples #}<div class="contact-info"> <p>General inquiries: {{ site.email | mailto }}</p> <p>Support: {{ "support@example.com" | mailto("Help needed") }}</p> <p>{{ "hr@example.com" | mailto("Job Application", "Position: ", "Apply Now") }}</p></div>How it works:
- Email addresses are split and base64 encoded in data attributes
- Displayed using HTML entities (e.g.,
@for @) - JavaScript converts to real mailto links on page load
- If JavaScript is disabled, the encoded email is still visible
Generated HTML:
<span class="mailto-obfuscated" data-user="aW5mbw==" data-domain="ZXhhbXBsZS5jb20=" title="Email" style="cursor:pointer;text-decoration:underline;"> info@example.com</span>Note: Requires content.js to be loaded on your pages for the JavaScript decoder to work.
Color Filters
Section titled “Color Filters”Color Conversion
Section titled “Color Conversion”hexToColor(string $hex): array
Section titled “hexToColor(string $hex): array”Converts hex color to color array.
{% set brand = "#3498db" | hexToColor %}{# Returns: {r: 52, g: 152, b: 219, h: 204, s: 70, l: 53} #}hex(array $color): string
Section titled “hex(array $color): string”Converts color array to hex.
{% set primary = cms.toggle('brand-color') %}<style> :root { --primary: {{ primary.color | hex }}; }</style>rgb(array $color, int $alpha = 100, bool $wrap = true): string
Section titled “rgb(array $color, int $alpha = 100, bool $wrap = true): string”Converts to RGB/RGBA format.
{% set primary = cms.color('primary') %}background-color: {{ primary | rgb }};background-color: {{ primary | rgb(50) }}; {# 50% opacity #}background-color: {{ primary | rgb(75, false) }}; {# No wrapper #}hsl(array $color, int $alpha = 100, bool $wrap = true): string
Section titled “hsl(array $color, int $alpha = 100, bool $wrap = true): string”Converts to HSL/HSLA format.
{% set accent = cms.color('accent') | hsl %}<div style="background: {{ accent }};">Content</div>
{# Semi-transparent overlay #}<div style="background: {{ cms.color('accent') | hsl(20) }};">Overlay</div>oklch(array $color, int $alpha = 100, bool $wrap = true): string
Section titled “oklch(array $color, int $alpha = 100, bool $wrap = true): string”Converts to modern OKLCH format.
{# Modern color space for better gradients #}background: {{ brand.primary | oklch }};color(array $color, int $alpha = 100, bool $wrap = true): string
Section titled “color(array $color, int $alpha = 100, bool $wrap = true): string”Alias for oklch. Converts to OKLCH format.
background: {{ brand.primary | color }};background: {{ brand.primary | color(50) }}; {# 50% opacity #}colour(array $color, int $alpha = 100, bool $wrap = true): string
Section titled “colour(array $color, int $alpha = 100, bool $wrap = true): string”British spelling alias for oklch.
background: {{ brand.primary | colour }};Color Adjustment
Section titled “Color Adjustment”lightness(array $color, string $lightness): array
Section titled “lightness(array $color, string $lightness): array”Adjusts color lightness.
{% set base = "#3498db" | hexToColor %}{% set light = base | lightness('+20') %}{% set dark = base | lightness('-20') %}
<style> .button-primary { background: {{ base | hex }}; } .button-primary:hover { background: {{ dark | hex }}; } .button-primary:active { background: {{ light | hex }}; }</style>chroma(array $color, string $chroma): array
Section titled “chroma(array $color, string $chroma): array”Adjusts color saturation/chroma.
{% set muted = brand.primary | chroma('-30') %}<p style="color: {{ muted | hex }};">Muted text</p>hue(array $color, string $hue): array
Section titled “hue(array $color, string $hue): array”Adjusts color hue.
{% set complementary = brand.primary | hue('+180') %}<div class="accent" style="border-color: {{ complementary | hex }};"></div>adjustColor(array $color, ?string $lightness = null, ?string $chroma = null, ?string $hue = null): array
Section titled “adjustColor(array $color, ?string $lightness = null, ?string $chroma = null, ?string $hue = null): array”Adjusts multiple color properties at once.
{% set variant = brand.primary | adjustColor('+10', '-20', '+30') %}Array Filters
Section titled “Array Filters”count(array $array): int
Section titled “count(array $array): int”Counts array elements.
{% set posts = cms.collection.objects('blog') %}<p>{{ posts | count }} blog posts available</p>
{# Conditional display #}{% if gallery.images | count > 0 %} <div class="gallery">...</div>{% endif %}ksort(array $array): array
Section titled “ksort(array $array): array”Sorts array by keys.
{% set categories = cms.collection.objects('categories') | ksort %}{% for category in categories %} <option value="{{ category.id }}">{{ category.name }}</option>{% endfor %}krsort(array $array): array
Section titled “krsort(array $array): array”Sorts array by keys in reverse order.
{% set years = posts | groupBy('year') | krsort %}{% for year, yearPosts in years %} <h3>{{ year }}</h3> {# Posts for this year #}{% endfor %}sortBy(array $array, string $key): array
Section titled “sortBy(array $array, string $key): array”Sorts an array of objects/arrays by a specific key.
{% set products = cms.collection.objects('products') | sortBy('price') %}{% for product in products %} <div>{{ product.name }} - ${{ product.price }}</div>{% endfor %}
{# Sort users alphabetically by name #}{% set users = cms.collection.objects('users') | sortBy('name') %}shuffle(array $array): array
Section titled “shuffle(array $array): array”Randomly shuffles array elements.
{% set testimonials = cms.collection.objects('testimonials') | shuffle | slice(0, 3) %}{% for testimonial in testimonials %} <blockquote>{{ testimonial.quote }}</blockquote>{% endfor %}paginate(array $array, int $limit, int $page = 1): array
Section titled “paginate(array $array, int $limit, int $page = 1): array”Returns a paginated slice of an array.
{% set page = get.page | default(1) | int %}{% set perPage = 10 %}{% set posts = cms.collection.objects('blog') | paginate(perPage, page) %}
{% for post in posts %} <article>{{ post.title }}</article>{% endfor %}
{# Pagination with navigation #}{% set allPosts = cms.collection.objects('blog') %}{% set totalPages = (allPosts | length / perPage) | round(0, 'ceil') %}<nav> {% for p in 1..totalPages %} <a href="?page={{ p }}" {{ p == page ? 'class="active"' : '' }}>{{ p }}</a> {% endfor %}</nav>unique(array $array): array
Section titled “unique(array $array): array”Removes duplicate values from an array.
{% set tags = ["php", "javascript", "php", "css", "javascript"] %}{{ tags | unique | join(', ') }}{# Output: php, javascript, css #}
{# Get unique categories from blog posts #}{% set allCategories = [] %}{% for post in cms.collection.objects('blog') %} {% set allCategories = allCategories | merge([post.category]) %}{% endfor %}{% set uniqueCategories = allCategories | unique %}
{# Build category filter #}<select name="category"> <option value="">All Categories</option> {% for category in uniqueCategories %} <option value="{{ category }}">{{ category | titleize }}</option> {% endfor %}</select>
{# Unique tags across all posts #}{% set allTags = [] %}{% for post in cms.collection.objects('blog') %} {% set allTags = allTags | merge(post.tags) %}{% endfor %}{% set uniqueTags = allTags | unique | sort %}
<div class="tag-cloud"> {% for tag in uniqueTags %} <a href="/blog?tag={{ tag | urlencode }}">{{ tag }}</a> {% endfor %}</div>
{# Remove duplicate authors #}{% set authors = posts | map(p => p.author) | unique %}<p>Authors: {{ authors | join(', ') }}</p>Collection Aggregation Filters
Section titled “Collection Aggregation Filters”These filters provide powerful ways to aggregate, transform, and analyze collections without writing verbose loops. They’re especially useful for calculating statistics, creating lookup tables, and organizing data.
sum(array $collection, string $property): float
Section titled “sum(array $collection, string $property): float”Calculates the sum of a numeric property across all items in a collection.
{# Basic usage #}{% set total = cms.collection.objects('orders') | sum('amount') %}<p>Total sales: ${{ total | number_format(2) }}</p>
{# Calculate revenue #}{% set revenue = cms.collection.objects('transactions') | sum('price') %}
{# Sum with filtering #}{% set completedTotal = cms.collection.objects('orders') | filterCollection([{property: 'status', operator: 'eq', value: 'completed'}]) | sum('amount') %}
{# Real-world example: Business totals #}{% set bustot = cms.collection.objects('busamount') | sum('amt') %}<p>Total business generated: ${{ bustot | number_format(0, '.', ',') }}</p>avg(array $collection, string $property): float
Section titled “avg(array $collection, string $property): float”Calculates the average of a numeric property across all items.
{# Basic usage #}{% set avgPrice = cms.collection.objects('products') | avg('price') %}<p>Average price: ${{ avgPrice | number_format(2) }}</p>
{# Calculate average rating #}{% set avgRating = cms.collection.objects('reviews') | avg('rating') %}<div class="rating">{{ avgRating | round(1) }} / 5 stars</div>
{# Average order value #}{% set aov = cms.collection.objects('orders') | avg('total') %}<p>Average order value: ${{ aov | number_format(2) }}</p>
{# Combine with sum for more stats #}{% set orders = cms.collection.objects('orders') %}<div class="stats"> <p>Total: ${{ orders | sum('amount') | number_format(2) }}</p> <p>Average: ${{ orders | avg('amount') | number_format(2) }}</p> <p>Count: {{ orders | length }}</p></div>min(array $collection, string $property): float|null
Section titled “min(array $collection, string $property): float|null”Finds the minimum value of a numeric property.
{# Basic usage #}{% set lowestPrice = cms.collection.objects('products') | min('price') %}<p>Starting at ${{ lowestPrice | number_format(2) }}</p>
{# Find earliest date (works with sortable date strings) #}{% set firstPost = cms.collection.objects('blog') | min('date') %}
{# Price range display #}{% set products = cms.collection.objects('products') %}{% set minPrice = products | min('price') %}{% set maxPrice = products | max('price') %}<p>Prices range from ${{ minPrice }} to ${{ maxPrice }}</p>
{# Handle null (no valid values) #}{% set lowest = products | min('sale_price') %}{% if lowest is not null %} <p>Sale prices from ${{ lowest }}</p>{% endif %}max(array $collection, string $property): float|null
Section titled “max(array $collection, string $property): float|null”Finds the maximum value of a numeric property.
{# Basic usage #}{% set highestPrice = cms.collection.objects('products') | max('price') %}<p>Up to ${{ highestPrice | number_format(2) }}</p>
{# Find highest rated #}{% set topRating = cms.collection.objects('reviews') | max('rating') %}
{# Display price range #}{% set products = cms.collection.objects('products') %}<p> ${{ products | min('price') | number_format(2) }} - ${{ products | max('price') | number_format(2) }}</p>
{# Find largest file #}{% set gallery = cms.render.gallery('portfolio') %}{% set largestFile = gallery | max('size') %}<p>Largest image: {{ largestFile | filesize }}</p>pluck(array $collection, string $property): array
Section titled “pluck(array $collection, string $property): array”Extracts a single property from all items, returning a flat array of values.
{# Basic usage - get all email addresses #}{% set emails = cms.collection.objects('members') | pluck('email') %}{# Result: ['john@example.com', 'jane@example.com', ...] #}
{# Get all IDs #}{% set ids = cms.collection.objects('products') | pluck('id') %}
{# Create comma-separated list #}{% set names = cms.collection.objects('team') | pluck('name') %}<p>Team: {{ names | join(', ') }}</p>
{# Get all tags from posts (then flatten and unique) #}{% set allTags = cms.collection.objects('blog') | pluck('tags') | flatten | unique %}<div class="tag-cloud"> {% for tag in allTags %} <a href="/blog?tag={{ tag | urlencode }}">{{ tag }}</a> {% endfor %}</div>
{# Get SKUs for inventory check #}{% set skus = cms.collection.objects('products') | pluck('sku') %}{# Use for API call or validation #}
{# Build select options #}<select name="author"> {% for author in cms.collection.objects('authors') | pluck('name') %} <option>{{ author }}</option> {% endfor %}</select>keyBy(array $collection, string $property = 'id'): array
Section titled “keyBy(array $collection, string $property = 'id'): array”Converts a collection into an associative array keyed by a specific property. This is extremely useful for creating lookup tables and avoiding N+1 query patterns.
{# Basic usage - create lookup table by ID #}{% set memberLookup = cms.collection.objects('members') | keyBy %}{# Same as: | keyBy('id') #}
{# Access by ID (O(1) lookup instead of loop) #}{% set member = memberLookup['000042'] %}<p>{{ member.fname }} {{ member.lname }}</p>
{# Key by different property #}{% set productsBySku = cms.collection.objects('products') | keyBy('sku') %}{% set product = productsBySku['ABC-123'] %}
{# Key by slug #}{% set pagesBySlug = cms.collection.objects('pages') | keyBy('slug') %}{% set aboutPage = pagesBySlug['about-us'] %}
{# IMPORTANT: Avoid N+1 pattern #}{# BAD - calls cms.collection.object() 50 times: #}{% for order in orders %} {% set customer = cms.collection.object('customers', order.customer_id) %}{% endfor %}
{# GOOD - calls cms.collection.objects() once, then O(1) lookups: #}{% set customerLookup = cms.collection.objects('customers') | keyBy %}{% for order in orders %} {% set customer = customerLookup[order.customer_id] | default({}) %} <p>{{ customer.name }} ordered {{ order.total | price }}</p>{% endfor %}
{# Real-world example: Display referrals with member names #}{% set memberLookup = cms.collection.objects('members') | keyBy %}{% for referral in cms.collection.objects('referrals') | paginate(50, page) %} {% set fromMember = memberLookup[referral.from_id] | default({}) %} {% set toMember = memberLookup[referral.to_id] | default({}) %} <tr> <td>{{ fromMember.fname }} {{ fromMember.lname }}</td> <td>{{ toMember.fname }} {{ toMember.lname }}</td> <td>{{ referral.amount | price }}</td> </tr>{% endfor %}Performance Note: keyBy is essential for avoiding the N+1 query problem. Instead of fetching related objects inside a loop (which causes many individual lookups), load all related objects once and use keyBy to create a lookup table.
groupBy(array $collection, string $property): array
Section titled “groupBy(array $collection, string $property): array”Groups items by a property value, returning an associative array where keys are property values and values are arrays of items.
{# Basic usage - group posts by category #}{% set postsByCategory = cms.collection.objects('blog') | groupBy('category') %}{# Result: {news: [...], tutorials: [...], reviews: [...]} #}
{# Display grouped content #}{% for category, posts in postsByCategory %} <h2>{{ category | titleize }}</h2> <ul> {% for post in posts %} <li>{{ post.title }}</li> {% endfor %} </ul>{% endfor %}
{# Group products by brand #}{% set productsByBrand = cms.collection.objects('products') | groupBy('brand') %}{% for brand, products in productsByBrand %} <section class="brand-section"> <h3>{{ brand }}</h3> <p>{{ products | length }} products</p> {% for product in products %} <div class="product">{{ product.name }}</div> {% endfor %} </section>{% endfor %}
{# Group events by month #}{% set events = cms.collection.objects('events') %}{% set eventsByMonth = events | groupBy('month') %}
{# Group orders by status #}{% set ordersByStatus = cms.collection.objects('orders') | groupBy('status') %}<div class="order-stats"> <p>Pending: {{ ordersByStatus.pending | length | default(0) }}</p> <p>Completed: {{ ordersByStatus.completed | length | default(0) }}</p> <p>Cancelled: {{ ordersByStatus.cancelled | length | default(0) }}</p></div>
{# Group team members by department #}{% set teamByDept = cms.collection.objects('team') | groupBy('department') %}{% for dept, members in teamByDept %} <div class="department"> <h3>{{ dept }}</h3> {% for member in members %} <div class="member">{{ member.name }} - {{ member.title }}</div> {% endfor %} </div>{% endfor %}Note: Items with empty or missing property values are grouped under the key _ungrouped.
countBy(array $collection, string $property): array
Section titled “countBy(array $collection, string $property): array”Counts items grouped by a property value. Like groupBy, but returns counts instead of the items themselves.
{# Basic usage - count posts per category #}{% set postCounts = cms.collection.objects('blog') | countBy('category') %}{# Result: {news: 5, tutorials: 12, reviews: 3} #}
{# Display category counts #}<ul class="category-list"> {% for category, count in postCounts %} <li>{{ category | titleize }}: {{ count }} posts</li> {% endfor %}</ul>
{# Count orders by status #}{% set statusCounts = cms.collection.objects('orders') | countBy('status') %}<div class="dashboard"> <div class="stat"> <span class="number">{{ statusCounts.pending | default(0) }}</span> <span class="label">Pending</span> </div> <div class="stat"> <span class="number">{{ statusCounts.completed | default(0) }}</span> <span class="label">Completed</span> </div></div>
{# Count products by brand #}{% set brandCounts = cms.collection.objects('products') | countBy('brand') %}{% for brand, count in brandCounts | ksort %} <option value="{{ brand }}">{{ brand }} ({{ count }})</option>{% endfor %}
{# Count members by membership type #}{% set membershipCounts = cms.collection.objects('members') | countBy('membership_type') %}<table> <tr><th>Membership</th><th>Count</th></tr> {% for type, count in membershipCounts %} <tr> <td>{{ type | titleize }}</td> <td>{{ count }}</td> </tr> {% endfor %}</table>
{# Combine with other filters for insights #}{% set activeMembers = cms.collection.objects('members') | filterCollection([{property: 'active', operator: 'eq', value: true}]) %}{% set byCity = activeMembers | countBy('city') %}<h3>Active Members by City</h3>{% for city, count in byCity | ksort %} <p>{{ city }}: {{ count }}</p>{% endfor %}Collection Filter Chaining Examples
Section titled “Collection Filter Chaining Examples”These filters can be chained together for powerful data analysis:
{# Get statistics for active products #}{% set activeProducts = cms.collection.objects('products') | filterCollection([{property: 'status', operator: 'eq', value: 'active'}]) %}
<div class="product-stats"> <p>Total products: {{ activeProducts | length }}</p> <p>Total inventory value: ${{ activeProducts | sum('price') | number_format(2) }}</p> <p>Average price: ${{ activeProducts | avg('price') | number_format(2) }}</p> <p>Price range: ${{ activeProducts | min('price') }} - ${{ activeProducts | max('price') }}</p></div>
{# Dashboard with grouped statistics #}{% set orders = cms.collection.objects('orders') %}{% set byStatus = orders | groupBy('status') %}
<div class="order-dashboard"> {% for status, statusOrders in byStatus %} <div class="status-card"> <h4>{{ status | titleize }}</h4> <p>Count: {{ statusOrders | length }}</p> <p>Total: ${{ statusOrders | sum('total') | number_format(2) }}</p> <p>Average: ${{ statusOrders | avg('total') | number_format(2) }}</p> </div> {% endfor %}</div>
{# Create a leaderboard #}{% set members = cms.collection.objects('members') %}{% set memberLookup = members | keyBy %}{% set referrals = cms.collection.objects('referrals') | countBy('from_id') %}
<h2>Top Referrers</h2><ol> {% for memberId, count in referrals | sort | reverse | slice(0, 10) %} {% set member = memberLookup[memberId] | default({}) %} <li>{{ member.fname }} {{ member.lname }}: {{ count }} referrals</li> {% endfor %}</ol>Developer Filters
Section titled “Developer Filters”Type Conversion
Section titled “Type Conversion”typeof(mixed $variable): string
Section titled “typeof(mixed $variable): string”Returns variable type.
{{ post.date | typeof }} {# string #}{{ gallery.images | typeof }} {# array #}
{# Debug templates #}{% if app.debug %} <pre>{{ dump(variable) }} ({{ variable | typeof }})</pre>{% endif %}string(mixed $variable): string
Section titled “string(mixed $variable): string”Converts to string.
{{ post.id | string }}{{ user.age | string }}int(mixed $variable): int
Section titled “int(mixed $variable): int”Converts to integer.
{% set page = get.page | int | default(1) %}{% set limit = get.limit | int | default(10) %}float(mixed $variable): float
Section titled “float(mixed $variable): float”Converts to float.
{% set price = product.price | float %}<span class="price">${{ price | number_format(2) }}</span>bool(mixed $variable): bool
Section titled “bool(mixed $variable): bool”Converts to boolean.
{% set featured = post.featured | bool %}{% if featured %} <span class="badge">Featured</span>{% endif %}array(mixed $variable): array
Section titled “array(mixed $variable): array”Converts to array.
{% set tags = post.tags | array %}{% for tag in tags %} <span class="tag">{{ tag }}</span>{% endfor %}Debugging
Section titled “Debugging”json_decode(mixed $variable): array
Section titled “json_decode(mixed $variable): array”Decodes JSON string to array.
{% set config = post.metadata | json_decode %}{% for key, value in config %} <meta name="{{ key }}" content="{{ value }}">{% endfor %}print_r(mixed $variable): string
Section titled “print_r(mixed $variable): string”Pretty-prints variable for debugging.
{% if app.debug %} <pre>{{ post | print_r }}</pre>{% endif %}var_dump(mixed $variable): string
Section titled “var_dump(mixed $variable): string”Detailed variable dump for debugging.
{% if app.debug %} <pre>{{ complex_object | var_dump }}</pre>{% endif %}Date and Time Filters
Section titled “Date and Time Filters”Total CMS includes powerful date manipulation filters powered by CakePHP Chronos. These filters support natural language date strings like “tomorrow”, “next monday”, “+1 week”, making date handling intuitive and flexible.
Date Formatting
Section titled “Date Formatting”dateFormat(mixed $date, string $format = 'Y-m-d H:i:s'): string
Section titled “dateFormat(mixed $date, string $format = 'Y-m-d H:i:s'): string”Formats dates with custom format strings.
{{ post.created_at | dateFormat }}{# Output: 2024-06-15 14:30:00 #}
{{ post.created_at | dateFormat('F j, Y') }}{# Output: June 15, 2024 #}
{{ post.created_at | dateFormat('l, F d, Y g:i A') }}{# Output: Saturday, June 15, 2024 2:30 PM #}
{# Works with smart date strings #}{{ "tomorrow" | dateFormat('Y-m-d') }}{{ "+1 week" | dateFormat('F j, Y') }}dateRelative(mixed $date): string
Section titled “dateRelative(mixed $date): string”Returns human-readable relative date strings.
{{ post.updated_at | dateRelative }}{# Output: 2 days ago #}
{{ event.date | dateRelative }}{# Output: in 3 weeks #}
{# Perfect for social media style timestamps #}{% for comment in post.comments %} <time>{{ comment.created | dateRelative }}</time>{% endfor %}Date Manipulation
Section titled “Date Manipulation”dateAdd(mixed $date, string $interval): string
Section titled “dateAdd(mixed $date, string $interval): string”Adds time intervals to dates.
{{ "now" | dateAdd('+1 day') | dateFormat('Y-m-d') }}{{ event.date | dateAdd('+2 weeks') | dateFormat('F j, Y') }}{{ deadline | dateAdd('+3 hours') | dateFormat('g:i A') }}
{# Chain multiple additions #}{{ "now" | dateAdd('+1 month') | dateAdd('+5 days') | dateFormat('Y-m-d') }}
{# Calculate future dates #}{% set nextPayment = subscription.date | dateAdd('+1 month') %}dateSubtract(mixed $date, string $interval): string
Section titled “dateSubtract(mixed $date, string $interval): string”Subtracts time intervals from dates.
{{ "now" | dateSubtract('1 day') | dateFormat('Y-m-d') }}{{ event.date | dateSubtract('2 weeks') | dateFormat('F j, Y') }}
{# Calculate past dates #}{% set lastWeek = "now" | dateSubtract('7 days') %}{% set lastMonth = "now" | dateSubtract('1 month') %}dateDiff(mixed $date1, mixed $date2): string
Section titled “dateDiff(mixed $date1, mixed $date2): string”Returns human-readable difference between two dates.
{{ start_date | dateDiff(end_date) }}{# Output: 2 weeks before #}
{{ "now" | dateDiff(deadline) }}{# Output: in 3 days #}
{# Project duration #}<p>Project duration: {{ project.start | dateDiff(project.end) }}</p>Date Period Operations
Section titled “Date Period Operations”dateStartOf(mixed $date, string $unit = 'day'): string
Section titled “dateStartOf(mixed $date, string $unit = 'day'): string”Returns the start of a period (day, week, month, year).
{{ "now" | dateStartOf('day') | dateFormat('Y-m-d H:i:s') }}{# Output: 2024-06-15 00:00:00 #}
{{ "now" | dateStartOf('month') | dateFormat('Y-m-d') }}{# Output: 2024-06-01 #}
{{ "now" | dateStartOf('year') | dateFormat('Y-m-d') }}{# Output: 2024-01-01 #}
{# Get this week's start #}{% set weekStart = "now" | dateStartOf('week') %}dateEndOf(mixed $date, string $unit = 'day'): string
Section titled “dateEndOf(mixed $date, string $unit = 'day'): string”Returns the end of a period (day, week, month, year).
{{ "now" | dateEndOf('day') | dateFormat('Y-m-d H:i:s') }}{# Output: 2024-06-15 23:59:59 #}
{{ "now" | dateEndOf('month') | dateFormat('Y-m-d') }}{# Output: 2024-06-30 #}
{# Get month range #}{% set monthStart = "now" | dateStartOf('month') %}{% set monthEnd = "now" | dateEndOf('month') %}Date Validation
Section titled “Date Validation”dateIsWeekend(mixed $date): bool
Section titled “dateIsWeekend(mixed $date): bool”Checks if a date falls on a weekend.
{% if event.date | dateIsWeekend %} <span class="badge">Weekend Event</span>{% endif %}
{# Business hours check #}{% if "now" | dateIsWeekend %} <p>Our office is closed on weekends</p>{% endif %}dateIsWeekday(mixed $date): bool
Section titled “dateIsWeekday(mixed $date): bool”Checks if a date is a weekday (Monday-Friday).
{% if meeting.date | dateIsWeekday %} <p>Regular business hours apply</p>{% endif %}dateIsPast(mixed $date): bool
Section titled “dateIsPast(mixed $date): bool”Checks if a date is in the past.
{% if event.date | dateIsPast %} <span class="badge">Past Event</span>{% else %} <a href="/register">Register Now</a>{% endif %}
{# Deadline checking #}{% if task.deadline | dateIsPast %} <div class="alert alert-danger">Overdue!</div>{% endif %}dateIsFuture(mixed $date): bool
Section titled “dateIsFuture(mixed $date): bool”Checks if a date is in the future.
{% if product.launch_date | dateIsFuture %} <span class="badge">Coming Soon</span>{% else %} <button>Buy Now</button>{% endif %}dateIsToday(mixed $date): bool
Section titled “dateIsToday(mixed $date): bool”Checks if a date is today.
{% if event.date | dateIsToday %} <div class="alert alert-info">Event is TODAY!</div>{% endif %}
{# Birthday check #}{% if user.birthday | dateFormat('m-d') == "now" | dateFormat('m-d') %} <p>🎉 Happy Birthday!</p>{% endif %}Recurring Date Operations
Section titled “Recurring Date Operations”recurringMonthDate(mixed $date, mixed $targetDate = null): string
Section titled “recurringMonthDate(mixed $date, mixed $targetDate = null): string”Gets the recurring date for a target month. Useful for subscription billing dates - automatically handles end-of-month clamping (e.g., Jan 31st becomes Feb 28th).
{# Get this month's billing date based on subscription start #}{{ subscription.startDate | recurringMonthDate | date('M j, Y') }}
{# Get billing date for a specific month #}{{ subscription.startDate | recurringMonthDate('2026-03-01') | date('M j, Y') }}
{# Calculate next payment date #}{% set nextPayment = membership.startDate | recurringMonthDate %}<p>Your next payment is on {{ nextPayment | date('F j, Y') }}</p>
{# Show payment schedule #}{% set months = ['2026-01-01', '2026-02-01', '2026-03-01'] %}<ul>{% for month in months %} <li>{{ subscription.startDate | recurringMonthDate(month) | date('F j, Y') }}</li>{% endfor %}</ul>End-of-month clamping examples:
- January 31st → February 28th (or 29th in leap year)
- January 31st → March 31st (no clamping needed)
- January 30th → February 28th (clamped)
- January 15th → February 15th (no clamping needed)
dateIsRecurringDate(mixed $date, mixed $compareDate = null): bool
Section titled “dateIsRecurringDate(mixed $date, mixed $compareDate = null): bool”Checks if a comparison date falls on the recurring day of the original date. Useful for determining if today is a billing day for a subscription.
{# Check if today is the billing day #}{% if subscription.startDate | dateIsRecurringDate %} <div class="alert alert-warning">Payment due today!</div>{% endif %}
{# Check against a specific date #}{% if subscription.startDate | dateIsRecurringDate(checkDate) %} <p>This is a billing day for this subscription.</p>{% endif %}
{# Billing reminder logic #}{% set tomorrow = "now" | dateAdd('+1 day') %}{% if subscription.startDate | dateIsRecurringDate(tomorrow) %} <div class="notice">Payment due tomorrow!</div>{% endif %}
{# Process payments for today #}{% for member in members %} {% if member.billingDate | dateIsRecurringDate %} <div class="payment-due">{{ member.name }} - Payment due today</div> {% endif %}{% endfor %}Real-World Example - Subscription Management:
{% set subscription = cms.collection.object('subscriptions', user.id) %}
<div class="subscription-info"> <h3>{{ subscription.plan }} Plan</h3> <p>Started: {{ subscription.startDate | date('F j, Y') }}</p> <p>Next billing: {{ subscription.startDate | recurringMonthDate | date('F j, Y') }}</p>
{% if subscription.startDate | dateIsRecurringDate %} <div class="alert alert-info"> Your payment is being processed today. </div> {% endif %}
{# Show upcoming billing dates #} <h4>Upcoming Payments</h4> <ul> {% for i in 1..3 %} {% set futureMonth = "now" | dateAdd('+' ~ i ~ ' months') %} <li>{{ subscription.startDate | recurringMonthDate(futureMonth) | date('F j, Y') }}</li> {% endfor %} </ul></div>Smart Date Strings
Section titled “Smart Date Strings”The date filters support natural language strings powered by Chronos:
{# Relative dates #}{{ "now" | dateFormat('Y-m-d H:i:s') }}{{ "today" | dateFormat('Y-m-d') }}{{ "tomorrow" | dateFormat('Y-m-d') }}{{ "yesterday" | dateFormat('Y-m-d') }}
{# Relative intervals #}{{ "+1 day" | dateFormat('Y-m-d') }}{{ "-1 week" | dateFormat('Y-m-d') }}{{ "+2 months" | dateFormat('Y-m-d') }}{{ "-1 year" | dateFormat('Y-m-d') }}
{# Natural language #}{{ "next monday" | dateFormat('l, F j') }}{{ "last friday" | dateFormat('Y-m-d') }}{{ "first day of this month" | dateFormat('Y-m-d') }}{{ "last day of this month" | dateFormat('Y-m-d') }}{{ "first day of next month" | dateFormat('Y-m-d') }}Real-World Date Examples
Section titled “Real-World Date Examples”Event Management
Section titled “Event Management”{% set event = cms.collection.object('events', 'summer-conference') %}
<div class="event-card"> <h3>{{ event.title }}</h3>
{# Display formatted date #} <p>📅 {{ event.date | dateFormat('l, F j, Y \\a\\t g:i A') }}</p>
{# Show relative time #} <p>{{ event.date | dateRelative }}</p>
{# Status badges #} {% if event.date | dateIsToday %} <span class="badge badge-primary">Today!</span> {% elseif event.date | dateIsPast %} <span class="badge badge-secondary">Past Event</span> {% elseif event.date | dateIsFuture %} <span class="badge badge-success">Upcoming</span> {% endif %}
{# Registration deadline #} {% set deadline = event.date | dateSubtract('1 week') %} {% if deadline | dateIsFuture %} <p>Registration closes {{ deadline | dateRelative }}</p> {% else %} <p>Registration closed</p> {% endif %}</div>Blog Post Scheduling
Section titled “Blog Post Scheduling”{% for post in cms.collection.objects('blog') %} <article> <h2>{{ post.title }}</h2>
{# Publication status #} {% if post.publish_date | dateIsFuture %} <div class="scheduled"> ⏰ Scheduled for {{ post.publish_date | dateFormat('F j, Y') }} ({{ post.publish_date | dateRelative }}) </div> {% else %} <time>Published {{ post.publish_date | dateRelative }}</time> {% endif %}
{# Show content only if published #} {% if post.publish_date | dateIsPast or post.publish_date | dateIsToday %} <p>{{ post.excerpt }}</p> {% endif %} </article>{% endfor %}Task Management
Section titled “Task Management”{% set tasks = cms.collection.objects('tasks') %}
{% for task in tasks %} <div class="task {% if task.due_date | dateIsPast %}overdue{% endif %}"> <h4>{{ task.title }}</h4>
{# Due date with smart formatting #} {% if task.due_date | dateIsToday %} <span class="due-today">Due today!</span> {% elseif task.due_date | dateFormat('Y-m-d') == "now" | dateAdd('+1 day') | dateFormat('Y-m-d') %} <span class="due-tomorrow">Due tomorrow</span> {% else %} <span>Due {{ task.due_date | dateRelative }}</span> {% endif %}
{# Days remaining/overdue #} {% set daysUntil = "now" | dateDiff(task.due_date) %} <small>{{ daysUntil }}</small> </div>{% endfor %}Business Hours
Section titled “Business Hours”{% set now = "now" %}{% set openTime = now | dateStartOf('day') | dateAdd('+9 hours') %}{% set closeTime = now | dateStartOf('day') | dateAdd('+17 hours') %}
<div class="business-hours"> <h3>Store Hours</h3>
{% if now | dateIsWeekend %} <p class="closed">🚫 Closed on weekends</p> {% elseif now >= openTime and now <= closeTime %} <p class="open">✅ Open until {{ closeTime | dateFormat('g:i A') }}</p> {% elseif now < openTime %} <p class="closed">🚫 Opens at {{ openTime | dateFormat('g:i A') }}</p> {% else %} <p class="closed">🚫 Closed - Opens tomorrow at 9:00 AM</p> {% endif %}</div>Collection Filtering and Sorting
Section titled “Collection Filtering and Sorting”📚 Full Documentation: For a complete reference of all 40+ filtering operators, including detailed examples and best practices, see Collection Filtering and Sorting Guide.
Advanced Collection Filtering
Section titled “Advanced Collection Filtering”{# Filter blog posts by image size and status #}{% set posts = cms.collection.objects('blog') | filterCollection([ { property: "image.size", operator: "gt", value: 1000000 {# Greater than 1MB #} }, { property: "status", operator: "eq", value: "published" }]) %}
{# Filter by date range #}{% set recentPosts = cms.collection.objects('blog') | filterCollection([ { property: "date", operator: "gte", value: "now -30 days" | date('Y-m-d') }]) %}
{# Filter with user input #}{% set filteredProducts = cms.collection.objects('products') | filterCollection([ { property: "price", operator: "between", value: [get.min_price | default(0), get.max_price | default(1000)] }, { property: "category", operator: "in", value: get.categories | default([]) }]) %}Array Rule Logic: OR vs AND
Section titled “Array Rule Logic: OR vs AND”When filtering with an array of values, you can control whether items must match ANY value (OR logic) or ALL values (AND logic) using the logic parameter.
OR Logic (Default)
Section titled “OR Logic (Default)”Returns items that match ANY of the values in the array:
{# Posts tagged with 'php' OR 'javascript' OR 'web' #}{% set posts = cms.collection.objects('blog') | filterCollection([ { property: "tags", operator: "contains", value: ["php", "javascript", "web"], logic: "or" {# Default - can be omitted #} }]) %}
{# Products in category 'electronics' OR 'computers' #}{% set products = cms.collection.objects('products') | filterCollection([ { property: "category", operator: "equal", value: ["electronics", "computers"] {# logic: "or" is the default #} }]) %}AND Logic
Section titled “AND Logic”Returns items that match ALL of the values in the array:
{# Posts that contain ALL tags: 'php' AND 'framework' AND 'tutorial' #}{% set advancedPosts = cms.collection.objects('blog') | filterCollection([ { property: "tags", operator: "contains", value: ["php", "framework", "tutorial"], logic: "and" }]) %}
{# Events on weekends AND evening time #}{% set weekendEvenings = cms.collection.objects('events') | filterCollection([ { property: "day_of_week", operator: "equal", value: ["saturday", "sunday"], logic: "and" {# Must be both saturday AND sunday - unlikely but demonstrates concept #} }]) %}
{# Products with ALL specified features #}{% set premiumProducts = cms.collection.objects('products') | filterCollection([ { property: "features", operator: "contains", value: ["waterproof", "wireless", "fast-charging"], logic: "and" {# Must have ALL three features #} }]) %}Real-World AND Logic Examples
Section titled “Real-World AND Logic Examples”Multi-tag content filtering:
{# Find blog posts that cover ALL specified topics #}{% set comprehensivePosts = cms.collection.objects('blog') | filterCollection([ { property: "tags", operator: "contains", value: ["security", "performance", "scalability"], logic: "and" }]) %}
<h2>Comprehensive Guides</h2><p>Posts covering security, performance, and scalability:</p>{% for post in comprehensivePosts %} <article>{{ post.title }}</article>{% endfor %}Product feature requirements:
{# Products that have ALL required features #}{% set requiredFeatures = ["bluetooth", "waterproof", "long-battery"] %}{% set suitableProducts = cms.collection.objects('products') | filterCollection([ { property: "features", operator: "contains", value: requiredFeatures, logic: "and" }]) %}
<h2>Products with ALL Required Features</h2>{% if suitableProducts | length > 0 %} {% for product in suitableProducts %} <div class="product">{{ product.name }}</div> {% endfor %}{% else %} <p>No products match all requirements</p>{% endif %}Event availability filtering:
{# Events available on ALL specified days #}{% set availableDays = ["monday", "wednesday", "friday"] %}{% set consistentEvents = cms.collection.objects('events') | filterCollection([ { property: "available_days", operator: "contains", value: availableDays, logic: "and" }]) %}Logic Parameter Summary
Section titled “Logic Parameter Summary”| Logic | Behavior | Use Case |
|---|---|---|
"or" (default) | Match ANY value | Broad filtering, multiple categories |
"and" | Match ALL values | Strict requirements, feature completeness |
Performance Note: AND logic applies filters sequentially, making it more restrictive and potentially faster for large collections since it narrows results with each filter.
Collection Sorting
Section titled “Collection Sorting”{# Sort by multiple criteria #}{% set sortedPosts = cms.collection.objects('blog') | sortCollection([ { property: "featured", reverse: true {# Featured first #} }, { property: "date", reverse: true {# Then by date descending #} }, { property: "title", natural: true {# Natural string sorting #} }]) %}
{# Random shuffle #}{% set randomProducts = cms.collection.objects('products') | sortCollection([ { property: "title", shuffle: true }]) %}
{# Sort by custom property #}{% set sortedGallery = cms.collection.objects('gallery') | sortCollection([ { property: "order", reverse: false }]) %}Real-World Examples
Section titled “Real-World Examples”Blog Post Listing with Filters
Section titled “Blog Post Listing with Filters”{% set posts = cms.collection.objects('blog') | filterCollection([ {property: "status", operator: "eq", value: "published"}, {property: "date", operator: "lte", value: "now" | date('Y-m-d')} ]) | sortCollection([ {property: "featured", reverse: true}, {property: "date", reverse: true} ]) %}
<div class="blog-posts"> {% for post in posts %} <article class="post {{ post.featured | bool ? 'featured' : '' }}"> <h2>{{ post.title }}</h2> <div class="meta"> <time>{{ post.date | date('F j, Y') }}</time> <span>{{ post.content | readtime }} min read</span> <span>{{ post.content | wordcount }} words</span> </div> <p>{{ post.excerpt | truncate(150, true) }}</p>
{% if post.tags | count > 0 %} <div class="tags"> {% for tag in post.tags %} <span class="tag">{{ tag | titleize }}</span> {% endfor %} </div> {% endif %} </article> {% endfor %}</div>Dynamic Color Theme
Section titled “Dynamic Color Theme”{% set theme = cms.collection.objects('theme', 'colors') %}{% set primary = theme.primary | hexToColor %}
<style> :root { --primary: {{ primary | hex }}; --primary-light: {{ primary | lightness('+20') | hex }}; --primary-dark: {{ primary | lightness('-20') | hex }}; --primary-rgb: {{ primary | rgb(100, false) }}; --primary-hsl: {{ primary | hsl(100, false) }}; }
.theme-preview { background: linear-gradient( 45deg, {{ primary | hex }}, {{ primary | hue('+60') | hex }} ); }</style>File Size Formatting
Section titled “File Size Formatting”filesize(mixed $bytes, int $decimals = 1): string
Section titled “filesize(mixed $bytes, int $decimals = 1): string”Formats byte values into human-readable file sizes using decimal units (1000 bytes = 1 KB), matching Mac Finder and browser conventions.
{# Basic usage #}{{ 500 | filesize }}{# Output: 500 B #}
{{ 1000 | filesize }}{# Output: 1 KB #}
{{ 1500 | filesize }}{# Output: 2 KB #}
{{ 1000000 | filesize }}{# Output: 1.0 MB #}
{{ 1500000 | filesize }}{# Output: 1.5 MB #}
{{ 1000000000 | filesize }}{# Output: 1.0 GB #}
{# Custom decimal places (only applies to MB and larger) #}{{ 1500000 | filesize(2) }}{# Output: 1.50 MB #}
{{ 1500000 | filesize(0) }}{# Output: 2 MB #}Behavior:
Section titled “Behavior:”- Uses decimal units (1000) to match Mac Finder and browser display
- Bytes (B) and Kilobytes (KB): Always shown as whole numbers (no decimals)
- Megabytes (MB) and larger: Shown with decimals (default: 1 decimal place)
- Supports units: B, KB, MB, GB, TB, PB
- Returns “0 B” for invalid or negative input
Real-World Examples:
Section titled “Real-World Examples:”{# Display image file size #}{% set image = cms.data('image', 'hero-image', 'image') %}<p>File size: {{ image.size | filesize }}</p>
{# File upload listing #}{% for file in cms.collection.objects('depot', 'downloads').files %} <div class="file"> <span class="name">{{ file.name }}</span> <span class="size">{{ file.size | filesize }}</span> </div>{% endfor %}
{# Gallery with file info #}{% set gallery = cms.render.gallery('portfolio') %}{% for item in gallery %} <figure> <img src="{{ cms.media.galleryPath(gallery, item.name) }}" alt="{{ item.alt }}"> <figcaption> {{ item.name }} ({{ item.size | filesize }}, {{ item.width }}x{{ item.height }}) </figcaption> </figure>{% endfor %}
{# Storage usage display #}{% set totalSize = files | map(f => f.size) | sum %}<div class="storage-info"> <p>Total storage used: {{ totalSize | filesize }}</p></div>Price Formatting
Section titled “Price Formatting”price(mixed $price, string $currency = '$', string $format = 'prepend'): string
Section titled “price(mixed $price, string $currency = '$', string $format = 'prepend'): string”Formats price values with currency symbols.
{# Basic usage #}{{ 19.99 | price }}{# Output: $19.99 #}
{{ 19.99 | price('€') }}{# Output: €19.99 #}
{# Different formats #}{{ 19.99 | price('USD', 'prepend') }}{# Output: USD19.99 #}
{{ 19.99 | price('USD', 'append') }}{# Output: 19.99 USD #}
{{ 19.99 | price('', 'none') }}{# Output: 19.99 #}Format Options:
Section titled “Format Options:”prepend(default): Places currency before the number ($19.99)append: Places currency after the number with a space (19.99 USD)none: Shows only the formatted number (19.99)
Real-World Examples:
Section titled “Real-World Examples:”{# Product listing #}{% for product in cms.collection.objects('products') %} <div class="product"> <h3>{{ product.name }}</h3> <span class="price">{{ product.price | price }}</span>
{# Sale price with comparison #} {% if product.sale_price %} <span class="sale">{{ product.sale_price | price }}</span> <span class="original">{{ product.price | price }}</span> {% endif %} </div>{% endfor %}
{# International pricing #}{% set currency = get.currency | default('USD') %}{% for product in products %} <span class="price"> {{ product.price | price(currency, 'append') }} </span>{% endfor %}
{# Price ranges #}{% set minPrice = products | map(p => p.price) | min %}{% set maxPrice = products | map(p => p.price) | max %}<p>Prices from {{ minPrice | price }} to {{ maxPrice | price }}</p>
{# Shopping cart totals #}{% set subtotal = cart.items | map(item => item.price * item.quantity) | sum %}{% set tax = subtotal * 0.08 %}{% set total = subtotal + tax %}
<div class="cart-totals"> <div>Subtotal: {{ subtotal | price }}</div> <div>Tax: {{ tax | price }}</div> <div class="total">Total: {{ total | price }}</div></div>Remember: These filters make Twig templates more powerful and help you process data without complex PHP logic in your templates!