This document shows how to build a custom FooEvents ticket theme by starting with the Canvas Ticket Theme. Canvas is a starter template designed as a foundation for custom ticket designs. It outputs all FooEvents ticket data in a simple, clean format with basic HTML and a little PHP, which makes it ideal for extending and branding.
We’ll cover the folder layout, where themes live, how the config works, how to assign your theme to a product, and the key places to customize markup safely for both HTML email and PDF output.
Prerequisites
- A WooCommerce site with FooEvents installed and activated.
- FTP/SFTP access (or equivalent) to upload files.
- A code editor (VS Code, Sublime, PhpStorm, etc.).
- A test product configured as a FooEvents event so you can send ticket previews and resends.
1) Download the Canvas Ticket Theme
Download and unzip the free Canvas Ticket Theme to your local computer.
2) Theme files
These are the key files you will edit when working on your custom ticket theme:
├─ config.json ← Declares name and compatibility (HTML/PDF/POS)
├─ header.php ← Email/PDF head + opening body markup and CSS
├─ ticket.php ← Main body; executes once per ticket
├─ footer.php ← Closing body/html tags, footer CSS overrides
├─ images/ ← Image assets (including preview thumbnail)
├─ readme.txt ← Theme metadata (human-facing)
└─ License/ ← GPL
└─ preview.jpg ← Thumbnail shown in the Ticket Themes screen.
The main files you will be working on are the following template files:
header.php
will typically include a strict XHTML email doctype, resets, Outlook/Apple Mail tweaks, and a$font_family
placeholder that Canvas already wires up.ticket.php
renders the ticket content; it’s executed for each ticket in the email.footer.php
closes out the HTML/PDF document.
3) Update the name of the ticket theme
Create a working copy of the Canvas Ticket Theme so you can modify it without touching the original.
Folder Name: #
Rename the unzipped folder to a unique slug, for example, change ‘canvas_custom_theme’ to something like ‘myticket_theme’. Give your theme a distinct name and declare which outputs it supports. Use lowercase and underscores only (no spaces). This folder name becomes your theme’s handle.
config.json (Canvas default): #
{
"name": "Canvas Ticket Theme",
"supports-html": "true",
"supports-pdf": "true",
"supports-pos": "false"
}
In the config.json file you can also decide whether this custom theme will also support PDF tickets. If you intend to design only for HTML email, set:
"supports-pdf": "false"
If you’ll support both HTML and PDF, keep it "true"
and test both outputs separately.
Note: These values are strings "true"/"false"
in Canvas; keep that format for compatibility.
readme.txt #
Update the “Ticket Theme Name” and description to reflect your custom theme. This file is informational but helps when scanning many custom themes.
preview.jpg #
Update the preview.jpg image thumbnail so that your ticket theme is easy to identify.
4) Uploading Your Ticket Theme to Your Site
FooEvents ticket themes are located in a FooEvents theme folder on your site. FooEvents automatically discovers themes in this directory. Using FTP/SFTP, upload your new ticket theme folder to the following location on you site:
/wp-content/uploads/fooevents/themes/
5) Assign the custom theme to a product
In order to test and use a ticket theme, you will need to assign it to a product. Open a WooCommerce product that has been configured as a FooEvents event, and set the ticket theme settings to use this ticket theme so you can send actual test tickets while you iterate.
In WordPress, edit your event product and open Product data → Ticket Settings. Set the HTML ticket theme to MyTicket Theme, then save.
If you’re also using FooEvents PDF Tickets, you can either disable it while you are testing, or if you have decided to make your ticket theme PDF-compatible, be sure to select your new theme under the PDF Ticket Theme setting.
6) Canvas header and footer (email-safe boilerplate)
Use Canvas’s email header and footer as a foundation for HTML email compatibility (and reasonable PDF output). The header includes conditional CSS for Outlook (MSO), resets that prevent Gmail/Apple Mail reformatting, and conservative defaults that keep layouts stable across clients and PDF rendering.
7) The ticket.php
loop: structure and key patterns
Understand how the ticket themes render data so you can safely move/skin elements.
Canvas executes ticket.php
once per ticket. The file typically contains two conceptual parts:
- A “header” area that only renders once (for the first ticket in the batch email or when previewing).
- A repeated block that renders for every ticket.
“First ticket only” guard #
You’ll see logic like this at the top:
<?php if ( ( ! empty( $ticket['ticketNumber'] ) && 1 === $ticket['ticketNumber'] ) || ( __( 'Preview Event', 'woocommerce-events' ) === $ticket['name'] ) ) : ?>
<!-- Header area that should output once -->
<?php endif; ?>
When resending to the purchaser and multiple tickets are included in one email, this ensures the header area prints only once.
HTML vs PDF example #
Canvas commonly distinguishes output based on the ticket type. This is done to ensure compatibility with the DOMPDF library which is used to render PDF files:
<?php if ( ! empty( $ticket['type'] ) && 'PDF' === $ticket['type'] ) : ?>
<p><strong>PDF Version</strong></p>
<?php else : ?>
<p><strong>HTML Version</strong></p>
<?php endif; ?>
Use this to apply small format-specific differences if your design needs it. Keep changes minimal; it’s easy to introduce divergence between HTML and PDF.
Logos / header images #
Canvas prints the logo and header image if provided in Product → Ticket Settings:
<?php if ( ! empty( $ticket['WooCommerceEventsTicketLogo'] ) ) : ?>
<p><img src="<?php echo esc_attr( $ticket['WooCommerceEventsTicketLogo'] ); ?>" alt="<?php echo esc_attr( $ticket['name'] ); ?>" style="max-width:100%;"/></p>
<?php endif; ?>
<?php if ( ! empty( $ticket['WooCommerceEventsTicketHeaderImage'] ) ) : ?>
<p><img src="<?php echo esc_attr( $ticket['WooCommerceEventsTicketHeaderImage'] ); ?>" alt="<?php echo esc_attr( $ticket['name'] ); ?>" style="max-width:800px"/></p>
<?php endif; ?>
Page breaks (for print/PDF) #
Canvas uses modulo logic on the ticket number to insert page breaks:
<?php if ( 0 !== $ticket['ticketNumber'] % 2 ) : ?>
<div style="page-break-before: always;"></div>
<?php endif; ?>
This example inserts a page break after every odd-numbered ticket. Adjust the modulo logic for your layout (e.g., break every 1, 2, or 3 tickets).
Common dynamic fields you’ll see #
- Event name:
<?php echo esc_attr( $ticket['name'] ); ?>
- Dates/times (varies by event type):
WooCommerceEventsDate
,WooCommerceEventsEndDate
,WooCommerceEventsHour
,WooCommerceEventsMinutes
,WooCommerceEventsPeriod
,WooCommerceEventsTimeZone
, etc. - Add to Calendar:
fooevents_ics
AJAX endpoint withevent
andticket
params. - Add to Wallet:
fooevents_wallet_pass
AJAX endpoint withticket
ID. - Barcode/QR:
<?php echo esc_attr( $barcodeURL ); ?>
- Variations: iterate
WooCommerceEventsVariationsFromID
- Bookings:
WooCommerceEventsBookingSlot
,WooCommerceEventsBookingDate
- Seating:
fooevents_seating_options_array
- Attendee fields:
WooCommerceEventsAttendeeName
,WooCommerceEventsAttendeeLastName
,WooCommerceEventsAttendeeTelephone
,WooCommerceEventsAttendeeCompany
, etc. - Custom attendee fields:
fooevents_custom_attendee_fields_options_array
- Zoom:
WooCommerceEventsZoomText
(if enabled)
Security: Canvas uses escaping (esc_attr
, wp_kses_post
, esc_attr_e
) consistently. Preserve these when moving fields around.
Difference Between Single and Multiple PDF Ticket Theme Templates #
If you are using the “Single” template and a customer purchases multiple tickets, then each ticket will appear on its own page in the same PDF file. Each ticket will have its own header image, logo and event details. If you are using the “Multiple” template then the event logo and details will appear at the top of the page followed by 3 tickets and then again the event details followed by 3 tickets etc. The idea is that the event details and 3 tickets fit on one page, but if you are displaying a lot of information then these tickets might run over onto the next page. To change this you can either display less information or override the template to remove some of the padding or reduce the font size.
8) Referencing theme images
Load images from your theme’s images/
folder with a reliable path.
Depending on the base, Canvas provides variables you can concatenate. You’ll commonly see one of these patterns:
<img src="<?php echo $theme_packs_url . $theme_name; ?>/images/myimage.png" alt="..." />
or
<img src="<?php echo $themePacksURL . 'theme/images/'; ?>myimage.png" alt="..." />
Inspect header.php
in Canvas to confirm the variables in your copy. Always resolve to an absolute URL for email.
9) HTML/CSS guidelines for email and PDF
Keep markup conservative so it renders consistently across clients and in PDFs.
- Use table-based layout or minimal
<div>
s; no complex flex/grid. - Inline critical styles (especially fonts, colors, spacing).
- Avoid web fonts in PDFs or provide robust fallbacks.
- Minimize nested elements and floats.
- Use
page-break-before/after
for PDF pagination, but test with your final content. - Keep images responsive with
max-width:100%; height:auto;
and absolute URLs. - Test HTML and PDF outputs separately after changes.
10) Assign, preview, and iterate
Validate the theme with realistic data.
- In
Product data → Ticket Settings
, confirm HTML Ticket Theme (and PDF Ticket Theme if applicable) is set to your custom theme. - Create a test order or resend an existing ticket to your own inbox.
- If tickets are emailed to the purchaser and an order contains multiple tickets, the email will include multiple ticket blocks—verify spacing and headings still look right.
Repeat: edit, upload changed files and resend.
11) Common tweaks & patterns
Conditional rendering by output type
<?php if ( ! empty( $ticket['type'] ) && 'PDF' === $ticket['type'] ) : ?>
<!-- PDF-specific tweak -->
<?php else : ?>
<!-- HTML-specific tweak -->
<?php endif; ?>
Only show a section once for the first ticket
<?php if ( ! empty( $ticket['ticketNumber'] ) && 1 === (int) $ticket['ticketNumber'] ) : ?>
<!-- One-time header content -->
<?php endif; ?>
Modulo-based page breaks
<?php if ( 0 === $ticket['ticketNumber'] % 3 && 0 !== $ticket['ticketNumber'] ) : ?>
<div style="page-break-before: always;"></div>
<?php endif; ?>
Safe output
<h2><?php echo esc_attr( $ticket['name'] ); ?></h2>
<p><?php echo wp_kses_post( $ticket['WooCommerceEventsTicketText'] ); ?></p>
12) Testing checklist
- Preview + resend tests for HTML and PDF (if supported).
- Multi-ticket email to purchaser renders multiple ticket blocks neatly.
- Images resolve (no broken links; absolute URLs).
- Major email clients: Gmail (web/mobile), Apple Mail, Outlook desktop/web.
- If PDFs are enabled: print to PDF or generate official PDF tickets and confirm pagination, margins, and fonts.
13) Troubleshooting
- Theme not showing in dropdown: Confirm folder path and
config.json
"name"
is unique; clear caches and reload the product edit screen. - Images not loading in email: Ensure absolute URLs; avoid protocol-relative URLs; confirm asset permissions.
- Weird spacing in Outlook: Reduce nested elements, rely on tables, and simplify CSS.
- PDF layout issues: Use simpler structures, add explicit page breaks, avoid floats and complex positioning.
Other Themes
The same process can be applied to any FooEvents Ticket theme. They follow the same underlying structure and approach. Find a theme that is similar to your design, and use it as a starting point.
Summary
Start with Canvas, give it a unique name in config.json
, place it in /wp-content/uploads/fooevents/themes/
, and assign it to a test product. Customize the markup in header.php
, ticket.php
, and footer.php
, keeping the HTML conservative and styles inline. Use the first-ticket guard for single-run elements, conditionally tweak HTML vs PDF output if needed, and rely on page breaks for PDF pagination. Test previews, resend real tickets, and validate multi-ticket emails before going live.