Custom Twig Block
The Custom Twig Block is the most flexible block in the page builder. It lets you create completely custom layouts by defining your own variables and writing HTML with Twig templating.
How It Works
Add the block - In the page builder, add a "Custom Twig Block"
Define variables - Create the data you need (text, images, products, etc.)
Write your template - Use HTML and Twig syntax to display your variables
Save and preview - See your custom layout on the page
Creating Variables
Click "Add Variable" to create each piece of data you need. Each variable has:
Variable Name - The name you'll use in your template (e.g.,
headline,products,show_banner)Type - What kind of data it holds
Value - The actual content
Variable Naming Rules
Use letters and numbers only (no spaces or special characters)
Names are case-sensitive (
Titleandtitleare different)Keep names short and descriptive
Examples:
headline,button_text,featured_products,show_prices
Variable Types
Text
A single line of text.
Use for: Headlines, button text, short labels
In your template:
Text Area
Multiple lines of text.
Use for: Descriptions, paragraphs, longer content
In your template:
Number
A numeric value.
Use for: Counts, prices, quantities, percentages
In your template:
Boolean (Yes/No)
A true or false toggle.
Use for: Showing/hiding sections, enabling features
In your template:
Color
A colour picker that outputs a hex code.
Use for: Custom styling, backgrounds, text colours
In your template:
Date & Time
A date and time picker.
Use for: Event dates, deadlines, announcements, scheduled times
In your template:
URL
A web address.
Use for: Links, buttons, external resources
In your template:
Image
An image uploader.
Use for: Hero images, logos, backgrounds, icons
In your template:
Gallery
Upload up to 20 images with drag-and-drop reordering.
Use for: Image galleries, winner photos, team members, portfolios
Gallery Item Fields:
url
Full URL to the image
"https://..."
name
Image file name
"photo1.jpg"
In your template:
Custom Fields
Define named key-value pairs for flexible data.
Use for: Contact details, metadata, configuration options, simple structured data
In your template:
JSON
Custom structured data for advanced use cases.
Use for: Lists of items, social links, feature lists, any repeating data
Example JSON:
In your template:
Products
Pull competitions directly from your database with powerful filtering.
Selection Modes:
Use Filters - Automatically select products based on criteria
Select Specific - Manually choose exact products
Filter Options (when using filters):
Status
Active Only, or Inactive Only
Categories
Select one or more categories to filter by
Sliders Only
Only show products marked as featured/slider
Sort By
How to order the results (see below)
Limit
Maximum number of products to show
Sort Options:
Ending Soon First
Ending Last First
Draw Date (Soonest)
Draw Date (Latest)
Price (Low to High)
Price (High to Low)
Title (A-Z)
Title (Z-A)
Newest First
Manual Sort Order
Product Fields Available:
id
Product ID
123
title
Product name
"Win a BMW M3"
subtitle
Product subtitle
"Competition of the Month"
url
Link to product page
"/product/win-a-bmw-m3"
image_url
Featured product image
Full URL to image
slider_image_url
Slider/hero image
Full URL to image
portrait_image_url
Portrait/vertical image
Full URL to image
featured_video_url
Featured video URL (if uploaded)
Full URL or null
video_embed_url
Player address for the competition's Video URL (null if none)
"https://www.youtube-nocookie.com/embed/..."
video_embed_type
"iframe" for YouTube or Vimeo, "video" for a video file
"iframe"
video_embed_mime_type
File type for a video file (null for YouTube or Vimeo)
"video/mp4"
video_embed_orientation
"portrait" for YouTube Shorts, otherwise "landscape"
"landscape"
price
Current price (formatted)
"£1.99"
price_display
Pretty current price ("Free", "50p")
"£1.99"
price_raw
Current price as a number
1.99
original_price
Original price if on sale (formatted)
"£2.99"
original_price_raw
Original price as a number
2.99
is_on_sale
Whether product is on sale
true/false
is_free
Whether the product is free to enter
true/false
cash_alt
Cash alternative (formatted)
"£50,000"
cash_alt_raw
Cash alternative as a number
50000
draw_date
Human readable draw date
"Draw On Mon Jan 5th 7:00pm"
end_date
Human readable end date
"Today 7:00pm"
draw_date_raw
ISO draw date
"2026-01-05 19:00:00"
end_date_raw
ISO end date
"2026-01-05 19:00:00"
start_date_raw
ISO start date
"2026-01-01 09:00:00"
start_date
Human readable start date
"Tomorrow 9:00am"
start_date_seconds
Seconds until the competition opens (0 once open)
7200
has_started
Whether the start date has passed
true/false
end_date_seconds
Seconds until end (for countdown)
3600
draw_date_seconds
Seconds until draw
86400
max_tickets
Total tickets available
5000
sold_tickets
Tickets sold
3421
tickets_remaining
Tickets left to sell
1579
percent_sold
Percentage of tickets sold
68.4
max_per_user
Max tickets per user (0 means no limit)
50
instant_wins
Number of instant wins
5
instant_wins_remaining
Remaining instant wins not yet won
3
game_type
Type of game
"standard"
has_ended
Whether competition ended
true/false
is_sold_out
Whether the product is sold out
true/false
is_active
Whether the product is active
true/false
is_featured
Whether the product is in the slider
true/false
winner_qty
Number of winners
1
auto_draw
Whether the draw happens automatically
true/false
leaderboard_enabled
Whether the product has a leaderboard
true/false
has_question
Whether the product has an entry question
true/false
question
The entry question text (if any)
"What colour is the sky?"
category
First category name
"Cars"
categories
All category names (array)
["Cars", "Featured"]
description
Product description
"Win this amazing..."
gallery
Array of gallery image URLs
["https://...", "https://..."]
Video with Image Fallback:
Video URL Embed:
When a competition has a Video URL set in its Optional Extras, the video_embed_* fields give you everything needed to show it. YouTube and Vimeo links play in an iframe, while a direct video file plays in a video tag.
Scheduled Competitions (Coming Soon):
A competition with a future Start Date (Scheduler) has has_started set to false. Filtered product lists only include competitions that have started, so this is mainly useful when you pick specific competitions in a Products variable. Use start_date_seconds to count down to the opening time.
In your template:
Winners
Display recent winners from your site.
Options:
Number of Recent Winners - How many winners to fetch (default: 5)
Winner Fields Available:
name
Winner's display name
"John S."
prize
What they won
"BMW M3"
product_title
Competition name
"Win a BMW M3"
product_url
Link to competition
"/product/win-a-bmw-m3"
product_image
Competition image
Full URL to image
date
Win date
"Jan 5, 2025"
date_ago
Time since win
"2 days ago"
In your template:
Instant Winners
Display recent instant win winners from your site.
Options:
Number of Winners
How many instant winners to fetch (default: 5, max: 20)
Minimum Value
Only show instant wins with prizes above this value (optional)
Note: Only fetches instant wins from the last 30 days.
Instant Winner Fields Available:
winner_name
Winner's display name
"JohnS"
prize
Prize name/description
"£10 Site Credit"
prize_value
Prize value (formatted)
"10.00"
prize_value_raw
Prize value (number)
10.00
is_site_credit
Whether prize is site credit
true/false
product_title
Related competition name
"Win a BMW M3"
product_url
Link to competition
"/product/win-a-bmw-m3"
product_image
Competition image URL
Full URL to image
date
Win date
"Jan 5, 2025"
date_ago
Time since win
"2 hours ago"
In your template:
User (Current Logged In)
The current visitor's account information. Returns guest data if not logged in.
User Fields Available:
id
User ID (null if guest)
123
name
First name
"John"
last_name
Last name
"Smith"
full_name
Full name
"John Smith"
display_name
Display name (or "Guest")
"JohnS"
is_logged_in
Whether logged in
true/false
balance
Site credit balance (formatted)
"£25.00"
balance_raw
Site credit balance (number, 0 for guests)
25.00
cash_balance
Cash wallet balance (formatted, null for guests)
"£10.00"
cash_balance_raw
Cash wallet balance (number, 0 for guests)
10.00
total_balance
Site credit plus cash wallet (formatted, null for guests)
"£35.00"
total_balance_raw
Site credit plus cash wallet (number, 0 for guests)
35.00
In your template:
Filters Reference
Transform your data using filters:
upper
{{ name|upper }}
JOHN
lower
{{ name|lower }}
john
default
{{ subtitle|default('None') }}
Fallback if empty
length
{{ products|length }}
Number of items
first
{{ products|first }}
First item
last
{{ products|last }}
Last item
join
{{ tags|join(', ') }}
Comma-separated
slice
{{ products|slice(0, 3) }}
First 3 items
trim
{{ text|trim }}
Remove whitespace
round
{{ 3.7|round }}
4
number_format
{{ 1234.5|number_format(2) }}
1,234.50
date
{{ my_date|date('M j, Y') }}
Jan 5, 2025
Complete Examples
Hero Section with Products
Variables needed:
headline(Text): "This Week's Top Prizes"subheadline(Text): "Don't miss out on these amazing competitions"background_color(Color): #1a1a2etext_color(Color): #fffffffeatured_products(Products): Filter by Featured, Limit 3
Template:
Winners Carousel
Variables needed:
title(Text): "Recent Winners"show_title(Boolean): Yesrecent_winners(Winners): 6 winners
Template:
Promotional Banner
Variables needed:
show_banner(Boolean): Yesbanner_headline(Text): "Flash Sale!"banner_text(Text): "50% off all entries for the next 24 hours"banner_color(Color): #dc2626banner_link(URL): /competitions
Template:
Social Links Bar
Variables needed:
social_links(JSON):
Template:
Dynamic Components
Custom Twig templates have access to reusable Alpine.js components for interactive elements like countdown timers and progress bars.
Countdown Timer
Display a live countdown to the competition end time.
Note: Use
end_date_seconds(notend_date_raw) to avoid timezone issues. The seconds are calculated server-side.
With ended state handling:
Available properties:
time.days
Days remaining
time.hours
Hours remaining (0-23)
time.minutes
Minutes remaining (0-59)
time.seconds
Seconds remaining (0-59)
hasEnded
Boolean, true when countdown reaches zero
pad(num)
Function to zero-pad numbers (e.g., "05")
Progress Bar
Display ticket sales progress with visual feedback.
Available properties:
percent
The percentage value (0-100)
width
Display width (minimum 3% for visibility when nearly empty)
Quick Add to Cart
Add a working "add to basket" control to a product card, with a quantity selector and loading/success/error states. The component handles adding tickets to the basket and updating the cart count for you.
Configuration (passed in when you create the component):
productId
The competition to add (product.id)
price
The ticket price as a number (product.price_raw), used to pick a sensible default quantity
maxTickets
The most tickets the buttons allow (defaults to 100)
hasQuestion
If the competition has an entry question, quick add is disabled (the customer must use the full product page)
hasEnded
If the competition has ended, quick add is disabled
Available properties and actions:
tickets
The currently selected quantity
increment()
Add one ticket (up to maxTickets)
decrement()
Remove one ticket (down to 1)
addToCart()
Add the selected tickets to the basket
loading
True while the add is in progress
added
True briefly after a successful add
error
True if the add failed
errorMessage
The message to show when there is an error
canAdd
True when the control is ready to add (not loading, not ended, no question, quantity in range)
Cart Count (Headless)
Show a live basket count, typically in a custom header or footer. It updates automatically whenever something is added to the cart (including via Quick Add above), without making extra requests.
Available properties:
count
The current number of items in the basket
hasItems
True when there is at least one item
Complete Card with Dynamic Components
Variables needed:
products(Products): Filter by Active, Limit 6
Template:
Tips
Start simple - Begin with a few variables and expand as needed
Use meaningful names -
hero_headlineis clearer thantext1Test with real data - Make sure your products/winners display correctly
Use conditionals - Hide empty sections with
{% if variable %}...{% endif %}Use the default filter - Handle empty values gracefully:
{{ subtitle|default('') }}
Need Help?
Copy this documentation along with your question and share it with an AI assistant (like ChatGPT or Claude). The AI can help you write templates, troubleshoot issues, and create custom layouts.
AI Context
For AI Assistants: This documents the RaffleX Custom Twig Block for page builder. Help users create custom HTML layouts.
Block Capabilities:
User defines variables via admin repeater
User writes HTML + Twig in code editor
Output renders on frontend
Variable Types: text, textarea, number, boolean, color, date & time, url, image, gallery, key_value (custom fields), json, products, winners, instant_winners, user
Products Variable:
Filter mode: status (active/inactive), categories (multi-select), featured toggle, sort options, limit
Specific mode: manually select products by ID
Returns array with: id, title, subtitle, slug, url, image_url, featured_video_url, video_embed_url, video_embed_type, video_embed_mime_type, video_embed_orientation, slider_image_url, portrait_image_url, price, price_raw, price_display, original_price, original_price_raw, is_on_sale, is_free, has_question, question, cash_alt, cash_alt_raw, draw_date, end_date, start_date, start_date_raw, start_date_seconds, has_started, draw_date_raw, end_date_raw, end_date_seconds, draw_date_seconds, max_tickets, sold_tickets, tickets_remaining, percent_sold, max_per_user, instant_wins, instant_wins_remaining, game_type, has_ended, is_sold_out, is_active, is_featured, auto_draw, leaderboard_enabled, simple_max_ticket, winner_qty, category, categories, description, gallery
Winners Variable:
Set count of recent winners to fetch
Returns array with: name, prize, product_title, product_url, product_image, date, date_ago
Instant Winners Variable:
Set count of recent instant winners to fetch (default: 5, max: 20)
Optional minimum value filter
Only fetches wins from last 30 days
Returns array with: winner_name, prize, prize_value, prize_value_raw, is_site_credit, product_title, product_url, product_image, date, date_ago
User Variable:
Returns current logged-in user data, or guest data if not authenticated
Returns object with: id, name, last_name, full_name, display_name, email, is_logged_in, balance, balance_raw (site credit), cash_balance, cash_balance_raw, total_balance, total_balance_raw (site credit plus cash wallet)
Gallery Variable:
Up to 20 images with reordering
Returns array with: url, name
Available Twig Tags: if, for, set
Available Filters: upper, lower, date, number_format, default, length, first, last, join, slice, round, trim, escape
Dynamic Alpine Components:
raffleCountdown(seconds)- Live countdown timer. Passend_date_seconds(server-calculated). Properties:time.days,time.hours,time.minutes,time.seconds,hasEnded,pad(num)raffleProgress(percent)- Progress bar. Properties:percent,width(min 3% for visibility)raffleQuickAdd(config)- Add-to-basket control with quantity selector. Config:productId,price(useprice_raw),maxTickets(default 100),hasQuestion,hasEnded. Properties/actions:tickets,increment(),decrement(),addToCart(),loading,added,error,errorMessage,canAdd. Disabled when the competition has an entry question or has ended.raffleBasket(config)- Headless live cart count for custom headers/footers. Config:initialCount(usecart_count, available in the header/footer Layout Twig context, not the page builder block). Properties:count,hasItems. Updates automatically on cart changes, no extra requests.Usage:
<div x-data="raffleCountdown({{ product.end_date_seconds }})">
Key notes:
Prices are pre-formatted with currency symbols (e.g., "£1.99")
Dates like draw_date and end_date are human-readable strings
Use
|default()for optional fieldsHTML is auto-escaped for security
Use a
<style>block before HTML for styling (can include Twig variables for dynamic colours)FontAwesome icons are available (e.g.,
fab fa-facebook)Use
end_date_secondsfor countdown timers (server-calculated seconds),end_datefor displayFiltered product lists only include competitions that have started. Use
has_startedandstart_date_secondsto show a coming soon countdown for specifically selected competitions
Copyable Template Starter:
See also:
Settings Variables for the global settings available in all Twig templates
Custom Twig Product Grid for building custom competition cards
Custom Twig Slider for building a custom hero section
Last updated