Developer Notes & Integration Guide

HomeDocumentationDeveloper Notes & Integration Guide

Developer Notes & Integration Guide

Overview: Stolik Menu and Stolik Menu PRO expose several public-facing workflows that may be used alongside custom themes, caching layers, multilingual plugins, payment integrations, and other WordPress extensions. This guide details the architectural contracts and state rules developers should preserve when extending or integrating with Stolik.

💡
Integration Philosophy: Stolik treats QR identity, business domain, content channel, and transactional capability as strictly separate architectural concepts. Custom integrations should preserve those boundaries rather than inferring state from individual URL parameters, numeric IDs, or browser storage.

Public Context Model

Stolik uses a multidimensional context model to determine what kind of menu experience a guest is experiencing. These dimensions describe distinct operational aspects and must not be collapsed into a single value:

Business domain: restaurant | hotel
Entity: none | table | location
Service mode: base | universal | dedicated
Content channel: food | hotel_services

Dimension Definitions

  • Business Domain (restaurant | hotel): Identifies the overarching operational venue context.
  • Entity (none | table | location): Identifies the physical or logical anchor of the session (e.g., Base Menu has none, Dedicated Table 5 has table, and Room 102 has location).
  • Service Mode (base | universal | dedicated): Describes how the QR/service workflow identifies the guest’s coordinates.
ℹ️
Rule: The same service mode (e.g., dedicated) participates in different business domains. Never infer the business domain from the service mode alone.

Business Domain and Content Channel Are Different Concepts

This is one of the most critical integration rules in Stolik:

  • The Business Domain answers: Where is the guest using Stolik?
  • The Content Channel answers: What kind of content is being displayed or ordered?

For example, a hotel guest ordering breakfast has domain = hotel and channel = food. A hotel guest requesting extra towels has domain = hotel and channel = hotel_services.

Both requests belong to the Hotel domain, but operate across different content channels. This architecture allows a single Hotel Custom Location to support both In-Room Dining and Hotel Services without fragmenting the guest session.

👨‍💻
Developer Tip: Never write logic assuming hotel context = hotel services. Hotel context may contain food-only content, hotel services content, or both depending on the active edition and location setup.

Do Not Infer Hotel Context from table_id

Some QR and service flows expose a numeric transport parameter named table_id for legacy backwards-compatibility. Developers must treat this strictly as an opaque transport field.

⚠️
Contract: table_id must not be treated as proof of Restaurant or Hotel identity.

Restaurant Table 2 and Hotel Custom Location #2 may both carry an internal numeric index of 2, but they represent completely different operational entities. The correct mental model is:

// Restaurant Table
domain = "restaurant"; entity.type = "table";

// Hotel Room / Area
domain = "hotel"; entity.type = "location";

Opaque Short QR Identities

Stolik Menu PRO 1.6+ uses compact, permanent QR identifiers such as service_qr_id=68d98f3d49. This identifier represents a server-resolved QR identity, eliminating the need to expose long signed tokens in the public browser URL.

Integration Rules for Short QR IDs

  • Treat service_qr_id as an opaque string.
  • Do not decode it, alter it, or derive semantic meaning from its characters.
  • Do not generate IDs manually or assume a fixed character length.
  • Never infer table, room, or domain identity by parsing the ID string.
👨‍💻
Developer Tip: Avoid client-side assertions like if (serviceQrId.length === 10). Length and format are not part of the public contract and may be adjusted in future releases.

Signed Transactional Context

Ordering, payments, service calls, and Charge to Room capabilities are never unlocked simply because a URL contains recognized query parameters like context=hotel or table_id=5.

Transactional capabilities require an authenticated, server-side cryptographic token handshake. This prevents intentional or accidental URL tampering by patrons. Custom integrations must not use raw URL parameters as proof of authorization for privileged service actions.

Fresh QR Scan Precedence

Scanning a physical QR code represents an explicit, authoritative guest action. Therefore:

📌
Rule: A fresh QR scan always takes absolute precedence over stale client storage (e.g., localStorage, sessionStorage, cookies, or cached runtime data).

Scenario:

  1. Guest scans Hotel Room 102 QR in the morning.
  2. Guest visits the hotel restaurant in the afternoon and scans Restaurant Table 5.
  3. Restaurant Table 5 immediately becomes authoritative. Stale hotel state must not leak into the restaurant view.

If developing custom JavaScript wrappers around Stolik, never restore prior location state over a freshly initialized QR payload.

Locale Must Not Change Business Identity

Stolik supports multilingual routing and dynamic locale switching. A language transition affects labels, dish translations, currency formatting, and localized URL paths. It must never alter the guest’s operational identity.

If a guest at Restaurant Table 3 switches from English to Polish, the session must remain Restaurant Table 3 (Polish). It must never mutate into Hotel Location 3 or reveal Hotel Services tabs due to translation fallback logic. Treat locale strictly as a presentation dimension.

Cache Guidance & Rules

Stolik contains both cache-friendly presentation assets and session-sensitive transactional endpoints. Configure your caching layer (Varnish, LiteSpeed, WP Rocket, Cloudflare) according to the table below:

Resource TypeExamplesCaching Strategy
Static AssetsCSS, JS, WebP/JPG images, QR previewsCache Aggressively (Browser & CDN)
Base MenusStatic restaurant catalog pagesStandard Page Cache
Transactional EndpointsVirtual Tray, Active Orders, Waiter Calls, Live DashboardBypass Cache Completely
Dynamic QR LinksURLs carrying service_qr_id or service parametersDo Not Cache HTML
🔍
Debugging Tip: When troubleshooting state synchronization or missing ordering buttons, temporarily purge and disable page caching, object caching, and CDN proxy layers before inspecting plugin logic.

Restaurant and Hotel Context Isolation

Restaurant and Hotel workflows are isolated operational domains. Transitions between them must remain clean:

Restaurant Dedicated Table → Fresh Hotel QR scan → Clean Hotel Context
Hotel Custom Location → Fresh Restaurant QR scan → Clean Restaurant Context

Never write integration logic assuming dedicated = restaurant or table_id present = restaurant. Hotel Custom Locations also utilize dedicated-style service flows.

Content Channels & Mixed Orders

Stolik currently manages two primary content channels:

  • food: Food and beverage items (Restaurant menus, In-Room Dining catalogs).
  • hotel_services: Hospitality workflows (housekeeping, extra amenities, SPA bookings, airport transfers).

In PRO Custom Locations, an active order may contain items from both channels simultaneously (a Mixed Order). Custom integrations and webhook listeners should preserve item-level channel metadata rather than flattening all items into a single generic list.

Charge to Room Is a Capability, Not a Domain Default

Being in a Hotel context does not automatically enable Charge to Room. Charge to Room is a capability gate requiring three distinct preconditions:

Valid Hotel Context + Valid Custom Location + Charge to Room Enabled (Admin) = Capability Active

A Restaurant context must never gain this capability merely because the PRO plugin is active on the WordPress instance.

QR Identity and Visual Styling

QR identity and QR visual presentation are entirely decoupled. Altering colors, corner rounding, quiet zone margins, or embedded center logos affects only the rendered SVG/PNG canvas. It will never mutate the underlying table ID, room token, or domain binding.

If building custom export pipelines, always consume Stolik’s canonical QR destination string rather than attempting to reconstruct payload URLs from front-end input values.

Public Mode Semantics

ModeDomainEntity TypeBehavioral Contract
BaserestaurantnoneView-only menu. No table binding; ordering actions disabled.
Universalrestauranttable (guest-supplied)Shared QR. Guest manually selects their table number.
Dedicatedrestauranttable (encoded)Permanent table binding. Table is resolved automatically.
Custom Locationhotellocation (encoded)Permanent room/area binding. Opens hotel channels.

Stable Interfaces vs Internal Implementation

Stolik evolves rapidly. To maintain long-term upgrade compatibility, developers must distinguish between public extension points and internal implementation details:

⚠️
Internal Details (Subject to change between minor releases): Private PHP classes/methods, undocumented REST payload properties, internal WordPress hook names, JS globals, DOM structure/nesting, transient keys, and database option names.

Recommended Integration Practices

  • Prefer: Standard WordPress action/filter hooks, documented shortcodes, public URL query contracts, and CSS styling hooks.
  • Avoid: Reading plugin database options directly via get_option(), modifying encrypted payload tokens, scraping internal DOM nodes, or overriding internal JavaScript globals.

DOM and CSS Customization

Target documented root classes (such as .stolik-menu-wrapper, .stolik-mobile-mockup) when customizing menu presentation. Avoid selectors that depend strictly on element order (e.g., div > div:nth-child(3)) as DOM layouts adapt between templates.

💡
Rule: Use CSS for visual presentation only. Never use CSS/JS to force-display hidden transaction buttons (e.g., payment triggers), as the server will reject unauthorized payload actions.

REST and Transactional Requests

Stolik’s internal REST endpoints require validated session context, nonce verification, and active capability checks. Never attempt to replay captured transactional requests across different tables, rooms, or domains, as server validation will drop the request.

Multilingual Integrations

When using multilingual plugins (e.g., Polylang, WPML), ensure translated menu pages preserve the original query parameters. A redirect that modifies /menu/ to /pl/menu/ must preserve query parameters like service_qr_id to maintain the guest’s table or room authorization.

Testing Recommendations for Integrations

Before deploying custom integrations to production, verify the following workflows in staging:

  • Restaurant Base vs Dedicated Table QR scan.
  • Hotel Custom Location scan (verify In-Room Dining + Hotel Services tabs).
  • Context switching: scan Hotel QR immediately followed by Restaurant QR.
  • Locale switching after QR initialization (verify table/room number is retained).
  • Placing a new order, appending items, and verifying staff receipt in Live Dashboard.
  • Charge to Room flow with feature toggled ON vs OFF.

Compatibility Guidance & Issue Reporting

Always keep Stolik Menu (Free) and Stolik Menu PRO synchronized on identical version releases (e.g., both on v1.6.0).

When submitting a technical integration ticket to support@brightforce.pl, please include:

  • Plugin versions (Free & PRO) + WordPress and PHP versions.
  • Active caching, CDN, and multilingual plugins.
  • Configured QR Mode (Base, Universal, Dedicated, or Custom Location).
  • Browser console logs and network response status codes.
🔒
Security Notice: Never share live secret license keys, Stripe payment credentials, full cryptographic tokens, or guest order data in public support threads.