Skip to content

Voxel Events Changelog

Release notes for every Voxel Events release, newest first. The current release is 1.2.0.

Updates install through the normal WordPress updates screen once your license is active.

Back up before updating a production site

Voxel Events writes ticket, order, and inventory data. Update on staging first where you can.

1.2.0

New Features

  • Oversold events are now visible — When an order completes for more tickets than a date had left, the sale is recorded and listed under Event Tickets → Oversold. Previously the only trace was a line in the PHP error log and a key in the order item, so an event could go over capacity without anyone finding out until the guests arrived. The screen shows which date and ticket type went over, by how many, who bought them and which order they came from. Site admins see every event; event authors see only their own.

  • Notification when an event sells beyond capacity — A new "Tickets Oversold" app event notifies the event author and the site admin, in-app and by email, as soon as an order pushes a date past its capacity. Recipients, channels and wording are configured with every other notification under Voxel → App Events. The notification can be switched off entirely in Voxel Events → Settings → Capacity Conflicts, which leaves the record on the Oversold screen without sending anything.

Improvements

  • Oversold records now name the date and ticket type — The stored details previously held only internal IDs. They now carry the ticket type name and the date label as well, which also reach the voxel_events_tickets_oversold hook.

  • One notification per purchase — The record is keyed on the order item, so a payment webhook and the customer's return arriving together produce a single record and a single notification rather than one of each.

Upgrade Notes

  • This release includes a database migration (db version 1.9) that adds the capacity conflicts table. It runs automatically on upgrade. Overselling that happened before this release is not backfilled, since the information was never recorded.

  • Behaviour on an oversell is unchanged: the tickets are still issued, because the customer has already paid. This release makes the oversell visible; it does not hold or refund the order. Holding a conflicted order for the organiser to accept or reject is coming in a later release.

1.1.4

Bug Fixes

  • Removing tickets from the cart now releases the held seats — Cart reservations were only released for logged-in shoppers, and only for events using the older single-date ticket format. Guests removing tickets released nothing, and on events with multiple dates per cart item the release matched nothing and did nothing. In both cases the seats stayed unavailable to other shoppers until the hold expired, making events look more sold out than they were. Removal now reads the guest cart as well as the logged-in cart, and handles both the multi-date and legacy single-date formats.

  • Cart empty and remove now register for logged-out visitors — The two handlers were registered only on the logged-in AJAX hooks. They were still reached through Voxel's own request routing, so this was not visible in normal use, but the missing registrations are now in place to match the add-to-cart handlers.

1.1.3

Bug Fixes

  • Fixed overselling under concurrent purchases — Ticket capacity was checked and updated without any locking, so two shoppers acting at the same moment could both be sold the last seat. Capacity checks and the sold counter are now serialized per event + date + ticket type using a database lock, and the sold counter is incremented by the database itself rather than read, modified and written back by PHP (which silently discarded one of two simultaneous sales).

  • Reservations are now checked before they are written — Adding tickets to the cart previously created the reservation first and validated capacity afterwards, so the reservation was never actually acting as a gate. Capacity is now verified inside the lock before the hold is written. This also fixes holds being left behind when validation failed, which made events look sold out to other shoppers until the hold expired.

  • Duplicate reservation rows are no longer possible — The reservations table had no unique constraint, so two simultaneous requests from the same shopper could each create a row for the same event, date and ticket type. A unique index now covers this and reservations are written as a single atomic upsert. Existing duplicates are merged on upgrade, preserving the total quantity held, and expired holds are cleared.

  • Orders are no longer processed twice — When a payment webhook and the customer's return to the site arrived together, both could pass the "already processed" check, reducing inventory twice and issuing two sets of ticket codes and two confirmation emails for one purchase. Order items are now claimed under a lock and the processed flag is re-read from the database inside it.

  • Capacity is now re-checked when an order completes — Previously the last capacity check happened when tickets were added to the cart, with nothing verifying availability at completion. Orders that would exceed capacity are still fulfilled, since the customer has already paid, but are recorded on the order item and logged. Developers can hook voxel_events_tickets_oversold to refund, notify the organiser, or flag the order for review.

  • Sold counts no longer go stale after a cache refresh — Refreshing an event's capacity cache deleted the stored counts with a direct query without clearing WordPress's meta cache, so the old numbers could continue to be served for the rest of the request.

Upgrade Notes

  • This release includes a database migration (db version 1.8) that adds an owner key and a unique index to the reservations table. It runs automatically on upgrade. Duplicate holds are merged rather than discarded, so no shopper loses tickets they are currently holding.

  • If you sell events with limited capacity, check Voxel Events → Settings → Reservation Duration. When set to "Disabled" (the default), nothing holds a seat between adding to the cart and completing payment, so two shoppers can still both reach checkout for the same seat. 15 minutes is recommended.

1.1.2

New Features

  • Settings to restore the hidden create-event form sections — The "Time Slots (Optional Overrides)" and "Attendee Information" sections (hidden since 1.1.0) can now be re-enabled without editing any templates. Two new toggles live under Voxel Events → Settings → Create Event Form; both default to off, matching the streamlined 1.1.0 behavior. Re-enabling the Time Slots section also restores access to the per-date "Mark as sold out" toggle introduced in 1.1.0.

  • Filters for the same flags — Developers can override the section visibility in code via the voxel_events_create_form_show_time_slots and voxel_events_create_form_show_attendee_fields filters (each receives the current boolean and should return one). Filters run after the settings, so they take precedence.

1.1.1

New Features

  • Alignment controls for the Ticket Product Form widget — Four new responsive (desktop/tablet/mobile) alignment controls: Section Labels → Alignment aligns the "Select tickets" and other section headings; Ticket Types → Content Alignment aligns the ticket name, description, price and availability text together; Quantity Stepper → Alignment positions the +/- stepper left, center, or right when the ticket row stacks vertically (previously hardcoded to the right on mobile); and Buttons → Width + Alignment lets the add-to-cart button be narrower than full width and aligned within its row.

1.1.0

New Features

  • Mark a date as sold out — The date override editor now has a per-ticket-type "Mark as sold out" toggle. When enabled, that ticket type shows as "Sold Out" for the date and cannot be purchased — it takes precedence over the capacity value (including unlimited). The "0 = unlimited" capacity behavior is unchanged, and no existing data is reinterpreted.

Changes

  • Streamlined create-event ticket form — The "Time Slots (Optional Overrides)" and "Attendee Information" sections are now hidden in the create-event form (controlled by the $show_time_slots / $show_attendee_fields flags in the template). This is a display-only change; any previously saved time slots or attendee fields are preserved.

1.0.8

Bug Fixes

  • Pricing Breakdown now uses the configured currency — On offline-payment orders, the Pricing Breakdown line was always rendered with a hardcoded "£" symbol regardless of the site's actual currency, causing a mismatch with the rest of the order (e.g. subtotal in "$" but breakdown in "£"). The pricing breakdown and the printable receipt now pull the currency from the event's product field (with a fallback to Voxel's global Stripe currency setting) and format amounts accordingly.

  • Same-day events are now purchasable — Tickets for an event happening later the same day were incorrectly flagged as "No tickets available for this event" because slot date/times were being compared without applying the WordPress site's timezone. Slot start times are now parsed in the configured site timezone (wp_timezone), so tickets remain available right up to the event's start.

  • New "Sales Cutoff" setting per event — Event editors can now configure how many minutes before each event start time ticket sales should stop (0 = sell until start). The cutoff is enforced on both the front-end slot picker and the purchase validation.

  • Confirmation email now reliably shows Date and Time — When the upstream slot data was missing or only partially populated (some recurring-date and dynamically-generated slot ID formats), the ticket confirmation email's Date/Time lines came out blank. A safety-net backfill now resolves the slot from the event's product configuration (and from the ticket record in the DB) before the email is rendered.

  • Ticket confirmation email now includes QR codes inline — The default email template was using the simple ticket list (text codes only). It now uses the detailed list, which embeds each ticket's QR code so attendees can scan straight from the email. Customers who have customized their email template can switch to the new tag manually by replacing @tickets(:list) with @tickets(:detailed_list).

  • Clearer Attendee Information guidance for free tickets — The "Attendee Information" help text claimed buyer name and email are always captured from the payment gateway. That isn't true for free tickets, which skip checkout and would otherwise leave attendees anonymous. The text now explains that paid tickets capture name/email at checkout and prompts editors to add a name/email field for free tickets if they need to identify attendees.

  • "Empty Message" control moved to the Content tab — The "No tickets selected yet" empty-state text for the Your Selections panel was registered under the Style tab, away from every other editable string. It now lives in the Content tab next to the panel title (its styling controls remain under Style). Existing saved values are unaffected.

1.0.4

Bug Fixes

  • Check-in now works for custom user roles — Event authors with non-admin roles (e.g. Voxel custom roles) were getting "Connection error" / "Ticket not found" when trying to check in tickets. The API was requiring the WordPress edit_posts capability, which custom roles don't have. Now uses proper author-based authorization.

  • Ticket sales toggle actually disables sales — Turning off the "Enable Tickets" toggle had no effect because the code checked for ticket_types data or tickets_enabled flag. Since ticket_types always has data after setup, the toggle was ignored. Fixed across 14 occurrences in 4 files.

  • Real-time check-in status on customer order page — After a ticket was scanned and checked in, the customer's order page continued showing "Not Checked In" for up to 3+ hours. Added polling that updates the status within seconds of check-in.

  • Form layout fix for All-Day / Multi-Day switchers — The start/end time switcher toggles in the create event form were not clearing to their own line, causing a janky layout. Fixed with proper flex sizing for switcher-label elements.

Built by Code Wattz.