M15 Catering — complete catering booking module for WordPress
For M15 Sopot restaurant we built a dedicated catering module for WordPress that handles the full booking cycle — from the customer's first click, through menu selection across 12-16 configurator panels, real-time price calculator with VAT, Paynow integration, automated emails, to date reservation in the availability calendar. Three separate configurators: weddings, family events, corporate events. Live in production at /rezerwacja-cateringu/.
Client and business context
M15 Sopot is a gastro-recreational complex on the Sopot beach that, beyond restaurant and saunas, provides catering services for large events: weddings, birthdays, communions, corporate events, funerals. The client needed an online catering booking system to replace manual quotes via phone and email.
Until now every booking looked like this: customer called, described requirements, M15 employee manually calculated quote in Excel, sent it by email, customer sent corrections, employee recalculated. Cycle took 2-5 days, customer often lost interest or went to competition. M15 wanted a system that lets the customer configure catering themselves in 15-30 minutes online, with instant quote and payment option.
Additionally the system had to integrate with the existing M15 site (WordPress + WooCommerce), handle GDPR compliance, generate orders in WooCommerce for accounting, and block dates with paid bookings in the availability calendar.
The challenge
Catering is not a classical product — it cannot be configured in 3 clicks like in a shop. A wedding requires decisions on menu type (served / platters / buffet), 3 tiers of starters, 3 tiers of soups, cold and hot buffets, 8 types of salads, desserts and chocolate fountain, 6 Open Bar packages × 3 durations, kids menu in 2 age groups, DJ and equipment. Total ~50 decision panels with 100+ fields.
The most serious challenge was the real-time price calculator — every change in any of 50 panels must instantly recalculate the entire quote considering: number of adults, kids 0-3 (free), kids 3-10 (kids menu or 50% adult menu), waiter service 10%, VAT 8%/23% for corporate events, alcohol per bottle vs Open Bar, minimum order 10 000 PLN for weddings.
Third major requirement — GDPR and tax law compliance: 3 required consent checkboxes, audit trail in order meta (IP, User-Agent, timestamp), NIP validation with checksum algorithm for VAT invoices, integration with Polish payment gateway Paynow (only PBL — no BLIK or cards due to amount limits), generating orders as WooCommerce orders for accounting.
Specific requirements
- 3 separate configurators: weddings (12 panels), family events (12 panels with menu type mutual exclusion), corporate events (16 panels with VAT + invoice)
- Real-time price calculator with sticky sidebar — every change recalculates everything
- Children logic: 0-3 free or 170 PLN kids menu, 3-10 with 50% adult menu option (excluding midnight dishes)
- Waiter service 10% — different scope for weddings vs corporate events
- VAT 8%/23% with proportional service distribution for corporate events
- NIP validation with checksum algorithm + auto-formatted postal code
- Availability calendar in admin panel: manual block + auto-block after paid order
- Paynow API integration with force_all_paynow_gateways filter (catering orders only — does not break the shop)
- Manual approval for corporate served lunch (on-hold status)
- Email idempotency — _m15_emails_sent_* meta prevents duplicates on retry
- 3 required GDPR checkboxes with audit trail (IP, User-Agent, timestamp, terms slug)
- Clickable step navigation (forward + backward) with visited steps highlighted
- localStorage state manager — preserves selection across page refreshes
- WooCommerce HPOS (High Performance Order Storage) — latest architecture compliance
5-month implementation process
Project size (~50 panels, 100+ meta fields, 3 order types, calendar, emails, Paynow integration, GDPR) required a systematic approach in 5 phases. The client had specific PDFs with pricing and menu packages, so we started with thorough business analysis.
Discovery and pricing document analysis
3 weeksWorkshops with M15: mapping all event types (weddings, christenings, communions, birthdays, funerals, corporate events), analysis of ~30 PDF pages with package pricing, extraction of pricing rules. Definition of configurators and flow per type. Identification of all edge cases (10 000 PLN minimum, kids 50%, proportional VAT, menu type mutual exclusion).
UX/UI design + interactive prototype
4 weeksDesign of 3 configurators with step navigation bar (clickable both directions), sticky sidebar with price calculator, event type tiles, validation forms. Figma prototype with clickable flow for each of 3 types. Iterations with M15 until UX acceptance.
Core development: 3 configurators + calculator
8 weeksImplementation in PHP 8 + JavaScript ES6+ on WordPress + WooCommerce. localStorage state manager. Price calculator with reactive updates per change in any of 50 panels. Children, service, VAT logic. NIP + postal code validation. 3 configurator types with different flows.
Integrations: Paynow, WooCommerce, calendar, emails
4 weeksPaynow API integration (only PBL through force_all_paynow_gateways filter, to not break the shop with other gateways). Creating WooCommerce orders with _m15_* meta. FullCalendar.js in admin panel with manual block modal + auto-block after paid order. 2-email system (client + restaurant) with hero gradient, idempotency, manual approval banner.
GDPR, admin panel, testing, deployment
3 weeksGDPR audit trail implementation (IP + User-Agent + timestamp). Custom meta box in WC orders panel with hero, key info grid, allergies in red, finance with VAT. Terms page with 16 paragraphs. WP Mail SMTP integration. LiteSpeed Cache excludes. Full E2E tests. Production deployment.
Technical solution
Stack: WordPress + WooCommerce HPOS + custom plugin (PHP 8) + JavaScript ES6+ + FullCalendar.js + flatpickr + Paynow API. Plugin hooks into WooCommerce in a way that does not disrupt the shop — filters are active only for orders with `_m15_catering_type` meta.
Price calculator architecture based on reactive state manager in localStorage — every change in a configurator field updates state that propagates to the sticky sidebar with current price. This allows instant pricing without backend wait, and selection preservation across page refreshes — important with 50 panels where the customer doesn't want to start over.
Hardest element: proportional waiter service 10% distribution for VAT 8%/23% in corporate events. Food has 8% VAT, alcohol 23%. Service 10% calculated on food + bar. Service must be split proportionally to food share (8% VAT) and bar share (23% VAT) in the total. Without this M15 accountant could not accept invoices. Implementation required precise algorithm with E2E tests on real cases.
Why WordPress plugin and not separate application?
M15 already has a site on WordPress + WooCommerce. Separate app would require additional hosting, separate login, order synchronisation. Plugin integrates natively with existing stack — orders go to WC, admin panel is where other orders are, M15 has one place to handle everything.
Why only Paynow PBL, not BLIK and cards?
BLIK and cards have amount limits (typically 5 000-10 000 PLN), insufficient for wedding catering (orders 10 000-50 000 PLN). PBL (bank transfer) has no such limits. Filter active only for catering — the M15 voucher shop still handles BLIK and cards normally.
Why state in localStorage, not server session?
Customer fills 50 panels for 15-30 minutes. Holding this in PHP session would require connection persistence + server load. localStorage works client-side — zero server cost, also works offline (customer can start on the train, continue at home after connection).
Why auto-block date but manual block has priority?
Auto-block after payment prevents duplicate bookings (two customers paying for same date). But sometimes M15 needs to block a day for other reasons (renovation, owners' private event) — then manual block cannot be overwritten by auto-block. Logic: manual block always wins.
Key features
The plugin covers the full catering order lifecycle — from first click to booked date and issued invoice. ~30 main feature categories, ~150 subcategories.
3 dedicated configurators (weddings, family, corporate events)
Weddings: 12 panels with served/platter/buffet menu, kids 0-3 and 3-10, Open Bar 6 packages × 3 durations. Family events: 12 panels with 4 ceremony types and menu mutual exclusion. Corporate events: 16 panels with VAT invoice, multi-select grill, event location, VAT 8/23%.
Real-time price calculator in sticky sidebar
Every change in any of 50 panels instantly recalculates the entire quote. Per-person price: adult, child, plus per-person for salads/buffet/soups/cakes. Average "Per child" in summary. Service 10% shown only in summary.
Children pricing logic
Wedding: 0-3 free or 170 PLN kids menu; 3-10 with 50% adult menu option (no midnight dishes, with dessert and sweet buffet). Corporate events: 2 kids menu options × 170 PLN.
VAT 8%/23% with proportional service
Corporate events with VAT invoice: food 8%, alcohol 23%, service 10% split proportionally. NIP validation with checksum algorithm. Auto-formatted postal code.
Availability calendar (admin + client)
FullCalendar.js in admin panel: hero gradient, click day → note modal, click blocked → unblock modal. Auto-block after paid order with `_m15_catering_type` meta. Manual block priority. Frontend: flatpickr with disabled dates.
Paynow API integration (PBL only)
`force_all_paynow_gateways` filter active only for catering orders — voucher shop unaffected. BLIK and cards disabled (amount limits). 10% deposit or full payment — customer choice.
Manual approval for corporate served lunch
On-hold status for orders requiring confirmation. Banner "[PRELIMINARY — requires confirmation]" in email subject. M15 staff manually verifies availability and confirms.
Email system (client + restaurant)
Email to client immediately + second after payment. Email to `marketing@m15.sopot.pl` with full operational breakdown. Idempotency via `_m15_emails_sent_*` meta. HTML with hero navy gradient + menu sections + allergies + finance with VAT. Full Open Bar package breakdown (not abbreviations). Configurable BCC.
WooCommerce HPOS (High Performance Order Storage)
Compliance with latest WooCommerce architecture — orders in dedicated table instead of wp_posts. Custom meta box in admin panel with hero gradient, key info grid, allergies in red, finance with VAT.
GDPR + audit trail
3 required checkboxes: GDPR consent + terms (link to /regulamin-cateringu/). Audit trail in meta: `_m15_gdpr_consent`, `_m15_terms_consent`, `_m15_consent_at`, `_m15_consent_ip`, `_m15_consent_ua`. Terms page with 16 paragraphs.
Clickable step navigation + localStorage state
Step navigation bar clickable both ways. Visited steps highlighted (`done` class). Click "Summary" → instant recalculation. localStorage state manager preserves selection across refreshes.
Additional services (DJ, tent, transport, furniture)
DJ: none / standard 2500 PLN / +sound system 4000 PLN. Tent: 4 sizes 3×3 / 3×6 / 150 m² / 300 m². Transport (corporate): up to 20 km / 50 km / 100 km. Service: tableware, security, gas heaters. Furniture: 10 items. Per-event-type hiding logic (funeral no DJ, wedding no transport).
Tech stack
Plugin based on proven WordPress + WooCommerce stack with dedicated extensions and integrations.
Results
Plugin deployed to production at m15.sopot.pl/rezerwacja-cateringu/ and handles the full booking flow — from customer's first click to booked payment and reserved date in calendar. M15 client no longer needs manual Excel quotes — system does everything automatically.
From M15 perspective, three effects are most important: (1) booking cycle time reduction from 2-5 days to 15-30 minutes, (2) accounting automation through WooCommerce orders with full meta (allergies, kids, menu, extras, VAT), (3) pricing error elimination — calculator doesn't forget about service, VAT, minimum order like a human with spreadsheet.
Plugin also handles atypical scenarios: funeral (no DJ, no transport, only platters), corporate event with VAT invoice and execution address different from restaurant, wedding with 50 children in 2 age groups. All scenarios were E2E tested before deployment.
What's next
Plugin is actively developed — version v5.53.3 is current production state. Plans include: (1) automatic package suggestion based on event type and guest count, (2) integration with M15 restaurant POS system for product consumption tracking, (3) export of bookings to Google/Outlook calendars of event staff.
Plugin architecture is universal enough to be adapted for other restaurants organising catering. ByteWave is considering releasing a generalised version as a commercial product for HoReCa industry.