ByteWave
Custom software · WordPress · WooCommerce

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.

Challenge

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.

01

Discovery and pricing document analysis

3 weeks

Workshops 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).

02

UX/UI design + interactive prototype

4 weeks

Design 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.

03

Core development: 3 configurators + calculator

8 weeks

Implementation 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.

04

Integrations: Paynow, WooCommerce, calendar, emails

4 weeks

Paynow 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.

05

GDPR, admin panel, testing, deployment

3 weeks

GDPR 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.

Solution

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.

01

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%.

02

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.

03

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.

04

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.

05

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.

06

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.

07

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.

08

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.

09

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.

10

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.

11

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.

12

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.

WordPress 6.x
CMS base with existing M15 site
WooCommerce HPOS
High Performance Order Storage — latest order architecture
PHP 8.x
Plugin backend, validation, pricing logic, Paynow integration
JavaScript ES6+
Configurator frontend, real-time calculator, state manager
FullCalendar.js 6.1.11
Availability calendar in admin panel
flatpickr
Client-side date picker with disabled dates
Paynow API
PBL payment gateway (10% deposit or full payment)
WP Mail SMTP
Reliable email sending from noreply@m15.sopot.pl
LiteSpeed Cache
Excludes for catering page (disable JS/CSS combine/UCSS)
localStorage API
Customer selection persistence across refreshes
Custom WooCommerce hooks/filters
Integration without disrupting shop operation

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.

Have a project idea?

Let's talk about how we can make it happen.

Get in touch