Theater website development using 1C-Bitrix

Our company is engaged in the development, support and maintenance of Bitrix and Bitrix24 solutions of any complexity. From simple one-page sites to complex online stores, CRM systems with 1C and telephony integration. The experience of developers is confirmed by certificates from the vendor.
Our competencies:
Development stages
Latest works
  • image_website-b2b-advance_0.png
    B2B ADVANCE company website development
    1175
  • image_bitrix-bitrix-24-1c_fixper_448_0.png
    Website development for FIXPER company
    811
  • image_bitrix-bitrix-24-1c_development_of_an_online_appointment_booking_widget_for_a_medical_center_594_0.webp
    Development based on Bitrix, Bitrix24, 1C for the company Development of an Online Appointment Booking Widget for a Medical Center
    564
  • image_bitrix-bitrix-24-1c_mirsanbel_458_0.webp
    Development based on 1C Enterprise for MIRSANBEL
    747
  • image_crm_dolbimby_434_0.webp
    Website development on CRM Bitrix24 for DOLBIMBY
    655
  • image_crm_technotorgcomplex_453_0.webp
    Development based on Bitrix24 for the company TECHNOTORGKOMPLEKS
    976

Theatre Website Development on 1C-Bitrix

A theatre website faces a challenge that no template solution can solve: the repertoire grid. A single production plays on three different venues, with varying casts, different dates, and different prices. Customers want to select their exact seat, see the view from their row, and complete a ticket purchase in 40 seconds. If any part of this process lags, they'll move to Afisha or Radareo, where the theatre pays commission on every ticket.

On 1C-Bitrix, such a website is built from a combination of infoblock modules for content and the sale module for ticketing. The main technical challenge is the SVG-based seating chart with real-time seat blocking.

Repertoire and Schedule: Two Infoblock Instead of One

A common mistake is storing productions and performances in a single infoblock. The play "The Seagull" exists once, but there are twenty performances per season. If you duplicate the card with description, photos, and cast for each performance, you end up with content chaos and filtering becomes impossible.

Repertoire infoblock — production card:

  • PROPERTY_GENRE — genre (drama, comedy, musical, ballet, opera — reference book)
  • PROPERTY_AGE_RATING — age restriction (0+, 6+, 12+, 16+, 18+)
  • PROPERTY_DURATION — running time with and without intermissions (two numeric fields)
  • PROPERTY_PREMIERE_DATE — premiere date
  • PROPERTY_DIRECTOR — director (link to Staff infoblock)
  • PROPERTY_CAST — main cast (multiple links to Staff)
  • PROPERTY_SCENE — venue (Main, Small, Chamber — link to Venues)
  • PROPERTY_TRAILER — video trailer (YouTube / Vimeo)
  • PROPERTY_GALLERY — photo gallery (multiple files)
  • PROPERTY_PRESS — reviews (multiple HTML with source and quote)
  • PROPERTY_IN_REPERTOIRE — checkbox (removed performances stay in archive for SEO)

Schedule infoblock — specific performances:

Field Type Description
PROPERTY_SHOW_ID Link Production from Repertoire
PROPERTY_VENUE_ID Link Hall from Venues
PROPERTY_DATETIME Date/time Performance start
PROPERTY_STATUS List On sale / Few seats left / Sold out / Cancelled
PROPERTY_CAST_OVERRIDE Multiple links Cast for specific date (if different from main)
PROPERTY_PRICE_SCHEME Link Pricing scheme from HL-block PriceSchemes

The "one production — many performances" structure enables listing all upcoming dates on a production page and showing all performances with filtering by date, genre, and venue in the event calendar. A bitrix:news.list component with filter >=PROPERTY_DATETIME by current date and sorted by date works perfectly for the homepage. Past performances automatically disappear from the schedule, but the production page with photos and reviews remains live.

Cast substitutions for specific performances are a separate consideration. If the main cast plays Thursday and a guest star performs Saturday, PROPERTY_CAST_OVERRIDE overrides the main cast on that specific date's page. Viewers know exactly who's performing the evening they're buying tickets for.

SVG Seating Chart and Ticket Sales

The technically heaviest component. It requires frontend (interactive seat map), backend (blocking, atomic transactions), and infrastructure (Redis for temporary blocks).

SVG hall file. Each hall is a separate SVG where every seat is an element with data-attributes:

<circle
  data-row="7"
  data-seat="14"
  data-zone="parter"
  data-category="A"
  cx="312" cy="285" r="6"
  class="seat seat--available"
/>

The data-category attribute links the seat to a pricing category. Categories are stored in HL-block SeatCategories: A — orchestra center (best view), B — side sections, C — mezzanine, D — balcony, E — gallery. Each performance has its own pricing grid. A weekday December evening and a Saturday pre-holiday performance have different prices for the same seat.

SVG files are uploaded to the Venues infoblock as property PROPERTY_SVG_MAP. Once prepared, the file is used for all performances in that hall.

Frontend interactivity. When opening the purchase page:

  1. SVG seating chart loads from the infoblock
  2. AJAX request returns an array of occupied and blocked seats for the specific performance
  3. JavaScript applies classes: seat--available, seat--occupied, seat--locked, seat--selected
  4. On hover — tooltip: row, seat, category, price
  5. On click — seat goes to cart, color changes
  6. Pinch-zoom on mobile and scroll-zoom on desktop (using svg-pan-zoom library)

For halls with 800–1200 seats, SVG contains the corresponding number of elements. On weak mobile devices this can lag. The solution is Canvas-based rendering with SVG rasterization: the screen shows a bitmap, and on zoom, the visible area is recalculated with individual seat rendering. For halls up to 500 seats, SVG works without optimization.

Seat blocking — Redis. When a viewer clicks a seat, a temporary lock is set. Redis key: lock:show_{id}:row_{r}:seat_{s} with TTL 600 seconds (10 minutes). Before writing — SETNX: if the key already exists, the seat is blocked by another buyer, frontend gets an error and redraws the seat as occupied.

A countdown timer is visible to the buyer: "Seats reserved for 8:42". When time expires, the lock is automatically released via TTL, without any cron or agents.

Why Redis instead of database records? Because Redis's TTL mechanism guarantees seat release even if the PHP process crashes. If a user closes the tab, the seat becomes available again in 10 minutes. With database records in b_iblock_element_property, you'd need a separate cleanup agent running every minute checking stale locks. Redis does this for free.

Server-side purchase processing:

  1. Availability recheck: Redis lock + HL-block SoldSeats
  2. Order creation in sale — each seat as separate cart item with price by category
  3. Redirect to payment system (ЮKassa, CloudPayments, Sber)
  4. OnSalePayOrder handler marks seats as sold in SoldSeats
  5. PDF ticket generation with QR code (TCPDF + phpqrcode)
  6. Email sending via mail module

The QR code contains URL site.ru/ticket/verify/{hash}, where hash is HMAC-SHA256 of order ID and secret key. Door controller scans QR, system marks ticket as used. Second entry — denied.

Integration with Ticketing Systems

If the theatre already works with Radareo, Ticketland, or Yandex.Afisha — the website connects to their API instead of its own sales system:

System Integration What we get
Radareo REST API v2 Halls, seat schemes, events, availability, order creation
Ticketland SOAP / REST Catalog, booking, payment status
Yandex.Afisha Widget API Sales widget for page embedding
SBIS REST API Ticket accounting, fiscalization via OFD

When working through partner API, SVG seating chart is pulled from the external system, not the infoblock. An adapter converts format to unified internal representation — frontend works identically in both cases. If the theatre decides to leave Radareo for in-house sales, just switch the adapter, interface remains the same.

Subscriptions and Gift Certificates

A subscription is a product in the sale catalog with property "number of visits" and expiration date. On purchase, a record is created in HL-block Subscriptions. When booking with a subscription, one visit is deducted instead of payment.

Gift certificates are realized through internal accounts of the sale module. Customer pays the amount, receives PDF with unique code. Recipient activates code — funds credited to their internal account.

Staff and Archive

Staff infoblock: photo, biography, roles (multiple links to Repertoire). On actor page — list of roles with photos from productions. On production page — cast with avatars.

Removed productions are archived by deactivating PROPERTY_IN_REPERTOIRE. URL doesn't change — SEO is preserved. For a theatre with decades of history, the archive gives hundreds of indexed pages with unique content.

Timeline

Stage Duration
Structure design and UX 2–3 weeks
Design (homepage, schedule, production card, seat selection) 3–4 weeks
Markup and responsiveness 2–3 weeks
Infoblock programming and business logic 3–4 weeks
SVG hall schemes and purchase interactivity 2–3 weeks
Payment / ticketing system integration 2–3 weeks
Content and testing 2 weeks
Total 16–22 weeks

Parallel designer and developer work shortens total timeline by 3–4 weeks. Using existing ticketing API (Radareo) reduces integration stage to 1–2 weeks. Cost is calculated individually after requirements analysis — scope depends on number of halls, external ticketing system presence, and content volume.