Documentation

QRMenu Pro v4.4

Smart Restaurant QR Menu & Ordering System — Complete Installation, Configuration, and Usage Guide

PHP 7.4+ MySQL / MariaDB No coding required Stripe & PayPal WhatsApp Ordering Built-in POS 80mm Thermal Printing Real-time orders Loyalty & Coupons AI Descriptions
🆕
What's new in v4.4 — PWA, Photo Galleries & Custom Design
  • Multiple photos per item — upload a swipeable gallery on each menu item; perfect for pastry, drinks, and detail shots.
  • Long descriptions + ingredients chips + nutrition — tell the story of each dish, list ingredients as chips, optionally show protein/carbs/fat/sugar.
  • Progressive Web App — installable to the home screen with a service worker, offline fallback page, and "Add to Home Screen" prompt.
  • Custom backgrounds — solid, gradient, full-bleed image, or one of 5 built-in patterns; tinted with your accent color.
  • 17 Google Fonts — pick separate display and body fonts (Playfair, Inter, Poppins, Lora, Bebas, Dancing Script…).
  • Existing installs: open Admin → Upgrade DB after replacing files — adds 1 table, 6 columns, 10 settings (idempotent & non-destructive).
Previous release notes (v4.2)
What was new in v4.2 — Thermal Receipt Printer
  • 80 mm & 58 mm ESC/POS thermal receipts with kitchen-ticket variant (no prices, large fonts).
  • Four print modes — Browser, RawBT (Android), Network TCP/9100, or downloadable .bin file.
  • Auto-cut, drawer kick, QR code, monochrome logo, header/footer text, charset selector.
Previous release notes (v4.1)
What was new in v4.1
  • POS Terminal — touch-friendly point-of-sale for counter / phone / dine-in orders.
  • WhatsApp Ordering — customers send their cart to your WhatsApp via wa.me.
  • Order source tagging — every order tagged qr / pos / whatsapp.

📋 Overview

QRMenu Pro v4 is a complete, self-hosted QR code restaurant menu and ordering system. Customers scan a QR code at their table, browse your menu, add items to a cart, and place orders — all from their phone. Staff manage everything from a polished admin panel.

📱

Digital QR Menu

Responsive mobile menu customers scan with any phone — no app download needed.

🛒

Live Ordering

Full cart, modifiers, special notes, dine-in / takeaway / delivery order types.

🍳

Kitchen Display

Dedicated kitchen screen auto-refreshes every 15 seconds. Never miss an order.

💳

Online Payments

Accept cash, Stripe (card), and PayPal. All configurable from the admin.

🎁

Loyalty Program

Customers earn points per order and redeem them for discounts on future orders.

🤖

AI Descriptions

Generate compelling menu item descriptions using built-in AI assistant.

📊

Analytics

Revenue charts, popular items, order trends, and detailed daily statistics.

🏷

Promotions

Coupon codes, percentage or fixed discounts, usage limits, date ranges.

⚙️ Server Requirements

RequirementMinimumRecommended
PHP7.48.1 or 8.2
DatabaseMySQL 5.7 / MariaDB 10.3MySQL 8+ / MariaDB 10.6+
Web ServerApache 2.4 / NginxNginx with PHP-FPM
PHP ExtensionsPDO, PDO_MySQL, cURL, JSON, OpenSSL+ GD or Imagick
Disk Space50 MB (core files)500 MB+ (with media uploads)
PHP Memory64 MB256 MB
ℹ️
GD or Imagick is optional but recommended for image processing (thumbnails, QR code generation). The system works without it — QR codes are generated via an external library.

Folder Permissions

The following directories must be writable by the web server:

chmod 755 assets/uploads/
chmod 755 assets/uploads/restaurant/
chmod 755 assets/uploads/items/
chmod 755 assets/uploads/categories/

🚀 Installation

1

Upload Files

Extract the zip and upload all files to your web server's public directory (e.g., public_html/, /var/www/html/, or a subdirectory like public_html/menu/).

2

Create a MySQL Database

Create a new database and user via your hosting control panel (cPanel, Plesk) or run:

CREATE DATABASE qrmenu_db CHARACTER SET utf8mb4;
CREATE USER 'qrmenu'@'localhost' IDENTIFIED BY 'your_password';
GRANT ALL PRIVILEGES ON qrmenu_db.* TO 'qrmenu'@'localhost';
FLUSH PRIVILEGES;
3

Set Folder Permissions

Make the uploads directory writable:

chmod -R 755 assets/uploads/
4

Run the Web Installer

Open your browser and go to: https://yourdomain.com/menu/install/

The installer guides you through 5 steps: Requirements check → Database → Restaurant details → Admin account → Complete.

5

Secure the Install Directory

After successful installation, delete or restrict the /install/ folder:

rm -rf /path/to/menu/install/

Or add an .htaccess in the install folder: Deny from all

After installation the installer creates config.php automatically and drops a lock file at assets/uploads/.installed to prevent re-running. If you need to re-install, delete the lock file and visit /install/?force=1.

Manual Installation (Alternative)

If the web installer does not work, you can install manually:

  1. Import install/schema.sql into your database via phpMyAdmin or mysql -u user -p dbname < schema.sql
  2. Edit config.php with your database credentials and base URL
  3. Insert an admin user manually:
    INSERT INTO staff (name, email, password, role)
    VALUES ('Admin', 'admin@example.com', '$2y$...bcrypt_hash...', 'admin');

config.php Reference

<?php
define('DB_HOST', 'localhost');       // Database host
define('DB_NAME', 'qrmenu_db');       // Database name
define('DB_USER', 'qrmenu');          // Database username
define('DB_PASS', 'your_password');   // Database password
define('DB_PORT', '3306');            // Database port (default 3306)
define('BASE_URL', 'https://yourdomain.com/menu'); // No trailing slash
define('APP_VERSION', '4.0.0');
define('APP_KEY', 'auto_generated_64_char_key');   // Auto-set by installer

🎯 First Steps After Installation

1

Log in to the Admin Panel

Visit https://yourdomain.com/menu/admin/ and log in with the admin email and password you set during installation.

2

Update Restaurant Info & Upload Logo

Go to Settings → General. Add your restaurant name, tagline, address, phone, and upload your logo and a cover photo.

3

Edit Menu Categories

Go to Categories. The installer creates 4 sample categories (Starters, Main Course, Desserts, Drinks). Edit, delete, or add new ones with icons and colors.

4

Add Your Menu Items

Go to Items. Fill in name, description, price, category, dietary tags (vegan, vegetarian, gluten-free, spicy), allergens, calories, and upload a photo.

5

Set Up Tables & Generate QR Codes

Go to Tables. Add your tables with names (Table 1, VIP Room, etc.) and capacity. Then go to QR Codes and download/print QR codes for each table.

6

Test the Customer Menu

Scan a QR code with your phone or visit https://yourdomain.com/menu/?table=1. Browse, add items, and place a test order to verify everything works.


📊 Dashboard

The dashboard is your control center, accessible at /admin/. It shows:

  • Today's Orders — total count of orders placed today
  • Today's Revenue — sum of completed orders (excludes cancelled)
  • Pending Orders — highlighted in red when orders need attention
  • Month Revenue — rolling monthly revenue total
  • 7-Day Revenue Chart — bar chart of the last 7 days (powered by Chart.js)
  • Top 5 Items (30 days) — most ordered items with quantities and revenue
  • Recent Orders — last 8 orders with status, table, and total
  • Quick Actions — one-click shortcuts to common tasks
🔄
The dashboard auto-refreshes pending order counts every 30 seconds without a full page reload.

📋 Orders & Kitchen

Orders Page

Manage all orders at Admin → Orders. Features include:

  • Filter by status: Pending, Confirmed, Preparing, Ready, Delivered, Cancelled
  • View full order details — items, modifiers, customer name, notes, total breakdown
  • Update order status with one click
  • Set estimated preparation time (shown to customer on order tracking page)
  • Export order data

Order Statuses

StatusMeaning
PendingCustomer placed the order, awaiting confirmation
ConfirmedStaff confirmed the order
PreparingKitchen is preparing the order
ReadyOrder is ready for pickup or service
DeliveredOrder has been delivered / completed
CancelledOrder was cancelled (excluded from revenue)

Kitchen Display

Open Admin → Kitchen on a tablet or screen in the kitchen. The kitchen view:

  • Shows only Pending and Confirmed orders as cards
  • Auto-refreshes every 15 seconds — no page reload needed
  • Displays order number, table, items with quantities, and special notes
  • One-click "Mark as Preparing" and "Mark as Ready" buttons
  • Color-coded urgency (older orders highlighted)
⚠️
Keep the kitchen screen open in a dedicated browser tab. Use browser full-screen mode (F11) for the best experience. The page auto-polls the server — no extra setup required.

🧾 POS Terminal

QRMenu Pro v4.1 ships with a built-in Point of Sale for in-person counter and table-side ordering. Staff use it to ring up walk-ins, take phone orders, or settle dine-in bills — alongside QR ordering and WhatsApp ordering, all into the same Orders/Kitchen pipeline.

Accessing the POS

  • Open Admin → POS Terminal (sidebar). Direct URL: /admin/pos.php
  • Available to admin, manager, and waiter roles.
  • Can be toggled on/off at Settings → POS → Enable POS Module.

Workflow

  1. Pick a category, tap items to add to the cart. Items with modifiers open a quick-pick sheet.
  2. Adjust quantities with the +/- buttons. Tap the pencil icon to edit modifiers/notes on a line.
  3. (Optional) Set order type (Dine In / Takeaway / Delivery), assign a table, set customer name.
  4. (Optional) Look up a loyalty customer by phone to earn / redeem points.
  5. (Optional) Apply a manual discount (% or fixed).
  6. Tap Checkout → choose payment method (Cash / Card / Other).
  7. For cash: enter cash tendered → change due is calculated automatically. Quick-amount buttons ($5, $10, $20…) speed this up.
  8. Tap Complete Sale. The order is saved (and optionally auto-marked delivered + paid), and a receipt opens for printing.

Receipts & Printing

  • Receipts use the browser's native print (Ctrl/⌘ + P) so they work with any printer — including standard 80mm thermal ESC/POS printers when set as the system default.
  • The receipt shows restaurant name, order number, cashier, items with modifiers, totals, payment method, cash tendered + change, and a configurable footer note.
  • Toggle Settings → POS → Auto-print Receipt to open the print dialog automatically on checkout.

Settings (Settings → POS)

  • Enable POS Module — show/hide the POS link in the sidebar.
  • Default Payment Method — Cash / Card / Other.
  • Auto-complete Orders — mark POS orders as delivered + paid immediately. Turn off if you want to fire orders to the kitchen and settle later.
  • Auto-print Receipt — opens the print dialog after each sale.
  • Show Loyalty Lookup — show the phone lookup field above the cart.
  • "Open Drawer" Button — log a $0 cancelled order tagged pos_drawer. Useful as an audit log of when staff popped the till.
  • Receipt Footer Note — appears at the bottom of every printed receipt (e.g. Thank you for your visit!, opening hours, return policy).

Orders Created by POS

POS orders are stored in the same orders table as QR orders, with source='pos' (or 'pos_drawer' for open-drawer logs). The Orders list shows a green POS badge next to the order number, and you can filter by source. The Kitchen Display includes them automatically.

💬 WhatsApp Ordering

QRMenu Pro v4.1 includes two independent WhatsApp flows — choose whichever fits your restaurant (or use both at once):

① Simple Floating Button (recommended for small/casual restaurants)

A green WhatsApp button sits permanently on the menu page. Customer taps it → WhatsApp opens with a short greeting → customer types their order naturally in the chat. No cart, no complexity — exactly how phone-style ordering already works at thousands of small restaurants.

  • Always visible at the bottom-left of the menu page (auto-moves above the cart bar when the cart has items).
  • On mobile: opens the WhatsApp app. On desktop: opens WhatsApp Web.
  • Configure label, greeting, and visibility at Settings → WhatsApp → Floating WhatsApp Button.

② Cart-aware Order Button (full e-menu flow)

For restaurants that want the full digital menu experience but accept payment over WhatsApp instead of card. Customer fills the cart, chooses items, then taps Order via WhatsApp on checkout — WhatsApp opens with all items, quantities, modifiers, totals already formatted in the message.

  1. Customer fills the cart on the QR menu and opens checkout.
  2. They tap the green Order via WhatsApp button.
  3. Their device opens WhatsApp with a pre-filled message: items, quantities, modifiers, order type, table, totals.
  4. Customer hits Send → message lands in your WhatsApp business inbox.
  5. You confirm price/timing and arrange payment (cash on delivery, bank transfer, etc.) directly in the chat.

Uses the official WhatsApp Click-to-Chat URL format (https://wa.me/<number>?text=<message>) — no API integration, no business account fees, works with personal or business WhatsApp.

Configuration (Settings → WhatsApp)

  • Enable WhatsApp Ordering — master switch. Required for both flows.
  • WhatsApp Number — international format (e.g. +44 7700 900123). Spaces, dashes, and "+" are stripped automatically.
  • Ordering Mode (controls the cart-aware checkout button only):
    • Both (default) — show WhatsApp button alongside the normal Confirm Order button. Customers choose.
    • WhatsApp only — replace the normal Confirm Order button. Use this if you don't take card/cash through the site at all.
  • Greeting Message — first line of the formatted cart message.
  • Save WhatsApp Orders to Database — when on (recommended), cart-aware orders are also created in Orders with payment_method='whatsapp', source='whatsapp', status pending. You'll see them in the Orders list with a green WA badge.
  • Show Floating WhatsApp Button — toggle the simple floating button. Can be turned off independently from the cart-aware flow.
  • Button Label — text shown next to the WhatsApp icon on the floating button (e.g. "Order on WhatsApp", "Chat with us").
  • Floating Greeting — the message pre-filled into the chat when the floating button is tapped.

Number format

WhatsApp's click-to-chat requires the international format without the leading "+" or any separators. The app normalises this automatically — e.g. typing +1 (555) 123-4567 becomes 15551234567. Test the link by visiting https://wa.me/<your-number> in a browser; if it opens your WhatsApp chat, you're good.

⚠️
WhatsApp's Click-to-Chat URL has no character limit in the spec, but very long carts may be truncated on some Android devices. Practical limit: ~30 line items per message. Above that, recommend the QR ordering flow instead.

📲 PWA, Photo Galleries & Custom Design v4.4

QRMenu Pro v4.4 turns your menu into a richer, more "app-like" experience: customers can install it to their home screen, swipe through multiple photos per item, read longer descriptions with ingredient chips and nutrition info — and you can fully customize the background, fonts, and accent color.

1. Multiple photos per item (gallery)

Each menu item can have a main cover photo plus an unlimited gallery of additional photos. Customers see a horizontally-swipeable carousel on the item detail page, with arrow buttons on desktop and dot indicators.

  • Go to Admin → Menu Items, click any item, and use the Photo Gallery panel to upload extras.
  • Upload multiple files at once (JPG/PNG/GIF/WebP, max 8 MB each).
  • Photos are stored in assets/uploads/items/ and tracked in the item_images table.
  • Hover any thumbnail and click ✕ to remove it. The cover photo is unaffected.

2. Long descriptions, ingredients & nutrition

The item editor now has three new content fields:

  • Short Description — 1-2 lines, shown on the menu card preview (existing field).
  • Long Description — multi-paragraph story, origin, recipe details. Line breaks are preserved.
  • Ingredients — comma-separated list rendered as chips on the item page.
  • Nutrition — optional protein / carbs / fat / sugar (in grams) + calories, shown as a clean 5-column grid.

3. Progressive Web App (PWA)

Customers can install your menu to their phone's home screen — no app store required. Once installed it launches in standalone mode (no browser chrome), and a service worker caches the menu so it still loads when offline (the customer sees a "you're offline" page if they're cold).

  • Auto-enabled. Toggle at Settings → Appearance → Progressive Web App.
  • The install prompt banner appears 4 seconds after page load on supported browsers (Chrome/Edge Android, Safari iOS via Share → Add to Home Screen).
  • Set a custom App Short Name (max 12 chars) for the home-screen label.
  • Manifest: /manifest.php (dynamic — uses your logo, theme color, restaurant name).
  • Service worker: /sw.js (network-first for API, cache-first for assets, offline fallback for navigations).

4. Custom backgrounds

The menu background has five modes — pick whatever fits your brand:

  • Default — clean off-white in light mode, deep brown in dark mode.
  • Solid — a single color (Color 1).
  • Gradient — diagonal blend from Color 1 to Color 2.
  • Image — full-bleed cover photo, automatically dim-overlayed (25%) for text readability.
  • Pattern — Dots, Grid, Diagonal Lines, Circuit, or Subtle Noise — tinted with Color 1.

Configure at Settings → Appearance → Menu Background.

5. Custom fonts

Pick from 17 Google Fonts for headings (display) and body text independently. Includes serif classics (Playfair Display, Lora, Merriweather, Cormorant Garamond), modern sans (Inter, Poppins, DM Sans, Nunito), bold display (Bebas Neue), and handwritten (Caveat, Dancing Script).

Configure at Settings → Appearance → Typography.

💡
Galleries, long descriptions, nutrition, custom backgrounds, fonts, and PWA are all optional. Existing menus look the same after upgrade — only the new fields appear when you fill them in.

🖨️ Thermal Receipt Printer v4.2

QRMenu Pro v4.2 ships with full 80 mm and 58 mm ESC/POS thermal-printer support. Every order — whether placed through QR, POS, or WhatsApp — can be printed as a customer receipt and a separate kitchen ticket.

Quick start

  1. Open Admin → Settings → Printer.
  2. Pick your Paper Width (80 mm is the standard receipt size).
  3. Pick a Print Mode that matches your hardware (see below).
  4. Hit Save Settings & then Send a Test Print. The test panel has one button per mode.

Choosing a Print Mode

The same receipt can be delivered to your thermal printer in four ways. Pick whichever matches your setup:

ModeHow it worksBest for
Browser print Opens a properly-sized HTML receipt that auto-fires window.print(). The OS sends it to whatever printer you choose in the print dialog. Windows / macOS POS PCs where your thermal printer is already installed with a driver. Easiest, works with literally any printer.
RawBT (Android) Generates a rawbt:base64,… URL. The free RawBT Print Service app on Android intercepts it and sends raw ESC/POS bytes to your printer over Bluetooth, USB or WiFi. Android tablet POS setups with a paired Bluetooth/USB thermal printer. No driver needed, direct raw printing.
Network IP QRMenu sends raw bytes via TCP to printer_ip:9100. Silent, instant, no dialog. Most Epson / Star / Xprinter / Bixolon thermal printers listen on port 9100 out of the box. Shop counters with a WiFi or Ethernet thermal printer. Best UX — single click, ticket prints, no popups.
Download .bin Downloads the raw ESC/POS bytes as a .bin file you can copy to a shared printer queue or send via lp / copy /B. Power users and integrators wiring print to custom scripts.

Settings reference

  • Enable Thermal Receipt Printing — master switch. Adds Print Receipt + Kitchen Ticket buttons across POS, Orders, and the Kitchen Display.
  • Paper Width — 80 mm (48 columns, standard receipts) or 58 mm (32 columns, compact mobile printers).
  • Print Mode — see table above.
  • Printer IP & Port — only required for Network mode. Find your printer's IP by running its self-test (usually hold the FEED button while powering on).
  • Character SetCP437 (default, safest international), CP850 (Western European accents), or CP1252 (Windows Western). Affects raw-byte modes; browser mode uses your system fonts directly.
  • Extra Header Text — extra centred lines under the restaurant name (VAT number, opening hours, etc.).
  • Footer Message — the closing message on every receipt.
  • Auto-cut paper — sends GS V cut after each receipt. Disable if your printer doesn't have a cutter.
  • Open cash drawer — sends ESC p drawer-kick pulse on every customer receipt.
  • Print logo — adds the restaurant logo (monochromed) to the top of browser-mode receipts.
  • Print QR code — adds a QR at the bottom (links to your menu or whatever URL you specify) — great for reviews / loyalty signup.
  • Also print kitchen ticket — after auto-print fires the customer receipt, automatically print a second ticket optimised for the kitchen.

Where the print buttons appear

  • POS Terminal — after saving an order, the receipt modal has Print Receipt and Kitchen Ticket buttons. If Auto-print Receipt is on in POS settings, both print automatically.
  • Orders → Detail view — every order has Print Receipt and Print Kitchen Ticket buttons in the sidebar.
  • Kitchen Display — each new order card has a small print icon to fire the kitchen ticket without leaving the screen.
  • Direct URLs/admin/receipt.php?id=ORDER_ID (customer) · /admin/receipt.php?id=ORDER_ID&kitchen=1 (kitchen) · add &size=58 to override the width.

Supported printers

QRMenu uses the standard ESC/POS command set — the same protocol Epson invented in 1985, supported by virtually every thermal receipt printer on the market today. Tested compatible families:

  • Epson — TM-T20, TM-T82, TM-T88 (all variants), TM-m30, TM-m50
  • Star Micronics — TSP100, TSP143, TSP650, mPOP, mC-Print3
  • Xprinter — XP-58, XP-80, XP-T80, XP-Q200, XP-T260 (extremely common in budget POS setups)
  • Bixolon — SRP-330, SRP-350, SRP-Q300
  • Generic Chinese 80 mm / 58 mm thermal printers — anything that advertises "ESC/POS compatible"

Troubleshooting

  • Receipt prints garbled characters — try changing Character Set. CP437 is the default and works for plain ASCII. Use CP850 / CP1252 for accented characters.
  • "Connect failed" in Network mode — check the printer's IP (run its self-test print), make sure it's on the same network as your server, and that port 9100 isn't blocked by a firewall.
  • RawBT doesn't open — install the RawBT Print Service from Play Store and pair your printer in its settings before tapping a print button.
  • Browser mode prints with huge margins — in the OS print dialog, set paper size to "Roll Paper 80×297mm" (or "User defined" 80 mm × auto) and set all margins to 0.
  • Paper doesn't auto-cut — your printer may not have a cutter, or it needs the GS V command in a different format. Toggle "Auto-cut paper" off.
ℹ️
The thermal printer feature is off by default on first install of v4.2 — turn it on at Settings → Printer once you've got a printer to test against. The classic window.print() still works for any installer who'd rather use it.

📌 Tables & QR Codes

Tables

Manage at Admin → Tables. Each table record has:

  • Name — e.g., "Table 1", "Bar Seat 3", "Terrace A"
  • Capacity — number of seats
  • Location — section label (Indoor, Outdoor, Terrace, etc.)
  • Active — toggle to hide a table

QR Codes

At Admin → QR Codes you can:

  • Preview the QR code for each table
  • Download individual QR codes as PNG images
  • Print a QR code sheet for all tables

Each QR code encodes the URL: https://yourdomain.com/menu/?table=TABLE_ID

When a customer scans the code, the menu loads pre-filled with their table number, so orders are automatically associated with the correct table.

Waiter Call

Customers can press a "Call Waiter" or "Request Bill" button from the menu. These requests appear in Admin → Tables (Waiter Calls section) and are colour-coded (waiter call vs. bill request). Staff can mark them as handled.

👥 Staff Management

Manage at Admin → Staff. Roles and permissions:

RoleAccess Level
AdminFull access to all features and settings
ManagerAll features except staff management and advanced settings
WaiterOrders, tables, waiter calls, kitchen view
KitchenKitchen display only
  • Accounts are protected with bcrypt password hashing
  • Brute-force protection: accounts lock after too many failed login attempts
  • Last login timestamp tracked per staff member

🏷 Promotions & Coupons

Manage at Admin → Promotions. Create coupons customers enter at checkout.

FieldDescription
NameInternal label for the promotion
Coupon CodeCode customers type at checkout (e.g., WELCOME10)
TypePercentage (e.g., 15%) or Fixed amount (e.g., $5 off)
ValueNumeric discount value
Minimum OrderMinimum subtotal required to use the coupon
Max UsesHow many times the coupon can be used in total (leave blank = unlimited)
Applies ToAll items, a specific category, or a specific item
Date RangeOptional start/end date for time-limited promotions
ActiveEnable/disable the coupon

The used_count field increments automatically every time the coupon is successfully applied to an order.

⭐ Loyalty Program

Enable at Settings → Loyalty. Customers earn points when they order using their phone number as their loyalty ID.

How It Works

  1. Customer enters their phone number at checkout
  2. They automatically earn points based on order total: points = total × points_per_currency_unit
  3. On future orders, they can apply points for a discount: discount = points_used × point_value
  4. Their points balance and total spend is tracked in Admin → Loyalty Customers

Configuration

SettingExampleResult
Points per $1 spent10$20 order → 200 points earned
Point value ($)0.01200 points → $2.00 discount

The live example at the bottom of the loyalty settings screen shows customers exactly what they earn per order.

⭐ Reviews

Customers can leave item ratings (1–5 stars) and comments from the menu. Manage at Admin → Reviews.

  • Enable/disable reviews globally from Settings → Loyalty
  • Optional Require Approval mode: reviews stay hidden until an admin approves them
  • Admins can reply to reviews (reply shown publicly next to the review)
  • Filter by status: Pending, Approved, Rejected
  • Average star rating displayed on each item card in the customer menu

📈 Analytics

View at Admin → Analytics. Reports include:

  • Revenue over time — daily bar chart, selectable date range
  • Order volume — total orders per day
  • Average order value
  • Top selling items — sorted by quantity or revenue
  • Order type breakdown — dine-in vs. takeaway vs. delivery split
  • Payment method breakdown
  • Menu page views tracked in analytics_daily table

🤖 AI Features

Access at Admin → AI or via the AI button on each item edit page.

  • Item Description Generator — type an item name + key ingredients, get a polished marketing description
  • Menu Suggestions — get ideas for new dishes based on your existing categories
  • Results can be copied directly into item description fields
⚠️
AI features require an API key configured in Settings → Advanced. The feature works with OpenAI-compatible APIs.

⚙️ Settings

All settings are at Admin → Settings, organized into 7 tabs:

General Tab

  • Restaurant name, tagline, description, phone, email, address
  • Currency symbol and position (before/after price)
  • Tax rate (%) and whether tax is included in prices or added on top
  • Logo and cover photo upload
  • Opening hours per day of the week with open/closed toggle and from/to times
  • Social media links (Instagram, Facebook)
  • WiFi SSID and password (displayed on the menu for customers)

Ordering Tab

  • Enable Ordering — master switch to turn online ordering on/off (menu still visible)
  • Order Types — choose which of Dine In, Takeaway, Delivery to allow
  • Minimum Order Amount — minimum subtotal required to place an order
  • Delivery Fee — flat fee added to delivery orders
  • Require Customer Name — customers must provide a name at checkout
  • Require Phone Number — optional phone requirement (needed for loyalty)

Payments Tab

Enable one or more payment methods:

MethodSetup Required
CashNo setup — always available
StripeEnter Publishable Key + Secret Key from your Stripe dashboard
PayPalEnter Client ID + Secret from your PayPal developer account
🔐
For Stripe, use test keys (pk_test_... / sk_test_...) during setup and switch to live keys when going live. Never commit live keys to public repositories.

Notifications Tab

  • Email Notifications — toggle email alerts on new orders
  • Admin Email — address that receives order notifications
  • SMTP Settings — optional custom SMTP for reliable email delivery:
FieldExample
SMTP Hostsmtp.gmail.com or your mail provider
SMTP Port587 (TLS) or 465 (SSL)
SMTP Useryour-email@gmail.com
SMTP PasswordApp password (for Gmail, generate at myaccount.google.com)
From EmailThe "From:" address in notification emails

If SMTP is left blank, PHP's native mail() function is used (less reliable on shared hosting).

Appearance Tab

  • Primary Accent Color — hex color used for buttons, prices, highlights. Pick from presets or use the color picker. Live preview updates in real time.
  • Default Theme Mode — Auto (follows customer's OS dark/light preference), Always Light, or Always Dark

Advanced Tab

  • Base URL — read-only here; edit config.php directly to change
  • Custom CSS — inject additional CSS into the customer-facing menu (e.g., font overrides, custom animations)
  • Custom JavaScript — inject JS into the customer menu (e.g., analytics scripts, chat widgets)
  • Maintenance Mode — shows a maintenance message to customers; admin panel remains fully accessible
  • Maintenance Message — custom text shown when maintenance mode is on

📱 Customer Menu Interface

The customer-facing menu is at https://yourdomain.com/menu/ (or ?table=X via QR code). It is fully mobile-first and works in any modern browser.

  • Sticky category tabs for fast navigation
  • Search bar to filter items by name or description
  • Dietary filter badges (Vegan, Vegetarian, Gluten-Free, Spicy)
  • Item photos, prices, ratings, and badges (Popular, New, Featured)
  • Item detail modal: full description, allergens, calories, modifiers
  • Dark / Light mode toggle (or auto-detect from OS)
  • WiFi info displayed in footer (if configured)
  • Social media links in footer
  • Opening hours shown if restaurant is currently closed

🛒 Ordering Flow

1

Browse & Add to Cart

Customer taps an item, selects any required modifiers, adds a note, and taps "Add to Cart". The cart button shows the running total.

2

Cart Review

Customer opens the cart to review items, adjust quantities, or remove items. Cart persists across page reloads (stored in localStorage).

3

Checkout

Customer enters their name (and optionally phone), selects order type (dine-in/takeaway/delivery), enters a coupon code if they have one, applies loyalty points, and chooses payment method.

4

Payment

For Cash: order placed immediately. For Stripe: card form shown inline. For PayPal: PayPal button/redirect. Order is created in database after successful payment confirmation.

5

Order Confirmation

Customer sees a confirmation screen with their order number and a link to the order tracking page. If email is enabled, a confirmation email is sent.

🔍 Order Tracking

Customers can track their order status at:

https://yourdomain.com/menu/order-status.php?order=ORDER_NUMBER

This page shows the current status with a progress indicator, estimated time (if set by staff), and refreshes automatically.


📁 File Structure

menu/ ├── index.php # Customer-facing menu ├── order-status.php # Customer order tracking ├── config.php # Database & app config (edit this) ├── documentation.html # This file │ ├── admin/ # Admin panel │ ├── index.php # Dashboard │ ├── login.php │ ├── logout.php │ ├── items.php # Menu item management │ ├── categories.php │ ├── modifiers.php │ ├── orders.php │ ├── kitchen.php # Kitchen display screen │ ├── pos.php # POS terminal (v4.1) │ ├── receipt.php # 80mm thermal receipt + kitchen ticket (v4.2) │ ├── tables.php │ ├── qrcodes.php │ ├── staff.php │ ├── promotions.php │ ├── loyalty.php │ ├── loyalty_customers.php │ ├── reviews.php │ ├── analytics.php │ ├── customers.php │ ├── ai.php │ ├── settings.php │ ├── upgrade.php │ ├── api/ │ │ ├── orders.php # Admin order AJAX endpoints │ │ ├── pos.php # POS order/drawer endpoints (v4.1) │ │ ├── print.php # ESC/POS raw bytes for thermal printer (v4.2) │ │ └── upload.php # Image upload handler │ └── includes/ │ ├── auth.php # Role-based access control │ ├── header.php # Admin layout header + nav │ └── footer.php # Admin layout footer + scripts │ ├── api/ # Public-facing API (customer menu) │ ├── menu.php # Menu items endpoint │ ├── orders.php # Place / fetch orders │ ├── tables.php # Table lookup │ ├── reviews.php # Submit / fetch reviews │ ├── coupon.php # Coupon validation │ ├── loyalty.php # Loyalty points lookup │ └── waiter.php # Waiter call submissions │ ├── includes/ # Shared PHP helpers │ ├── db.php # PDO connection + helpers │ ├── escpos.php # ESC/POS thermal printer command library (v4.2) │ └── functions.php # formatPrice(), setting(), uploadFile()… │ ├── assets/ │ ├── css/ │ │ └── tailwind.css # Pre-compiled Tailwind CSS │ ├── js/ │ └── uploads/ # All uploaded media (writable) │ ├── restaurant/ # Logo & cover photo │ ├── items/ # Item photos │ ├── categories/ # Category images │ └── .installed # Installer lock file │ ├── install/ # Web installer (delete after install) │ ├── index.php │ └── schema.sql │ └── upgrade/ # Version upgrade tool └── index.php

🗄 Database Schema

All tables use utf8mb4 charset and InnoDB engine. Key tables:

TablePurpose
settingsKey-value store for all application settings
staffAdmin panel user accounts with roles
categoriesMenu categories with icon, color, sort order
itemsMenu items with prices, tags, images, availability times
modifier_groupsCustomization option groups (e.g., "Choose sauce")
modifier_optionsIndividual options within a modifier group
item_modifiersJunction table linking items to modifier groups
tablesRestaurant tables / seats
ordersCustomer orders with status, payment, totals, source (qr/pos/whatsapp), cashier & cash received (POS)
order_itemsLine items within each order (frozen snapshot of item data)
reviewsCustomer item ratings and comments
promotionsCoupon codes and discount rules
loyalty_customersCustomer loyalty accounts (phone-based)
analytics_dailyAggregated daily stats (views, orders, revenue)
waiter_callsWaiter call and bill requests from customers

The full schema SQL is in install/schema.sql and can be re-imported at any time (uses CREATE TABLE IF NOT EXISTS — safe to run again).

🔌 API Endpoints

The customer menu communicates with these JSON endpoints under /api/:

EndpointMethodPurpose
/api/menu.phpGETReturns all active categories and items
/api/orders.phpPOSTPlace a new order
/api/orders.php?id=XGETFetch order status for tracking page
/api/tables.php?id=XGETValidate and return table info
/api/coupon.phpPOSTValidate a coupon code and return discount
/api/loyalty.php?phone=XGETFetch loyalty points balance for a phone number
/api/reviews.phpGET / POSTFetch item reviews or submit a new review
/api/waiter.phpPOSTSubmit a waiter call or bill request
/admin/api/orders.phpPOSTUpdate order status (admin, authenticated)
/admin/api/upload.phpPOSTUpload images (admin, authenticated)

🔒 Security

  • Passwords — hashed with password_hash() using bcrypt (PHP default, cost factor 10+)
  • Brute-force protection — login attempts tracked; account locked on repeated failures with a lockout_until timestamp
  • Session-based auth — all admin pages require a valid session; roles enforced per page via requireRole()
  • SQL injection — all database queries use PDO prepared statements
  • XSS — all output in templates uses htmlspecialchars()
  • CSRF — admin forms are session-authenticated; API endpoints validate content-type
  • File uploads — MIME type validation, extension whitelist, renamed on upload to random filenames
  • Install lock — lock file prevents re-running the installer after setup

Post-Installation Security Checklist

  1. Delete or password-protect the /install/ directory
  2. Set config.php to non-writable: chmod 444 config.php
  3. Ensure assets/uploads/ has no PHP execution (add .htaccess: php_flag engine off)
  4. Use HTTPS — obtain a free SSL certificate via Let's Encrypt
  5. Use a strong, unique admin password (12+ chars, mixed case, numbers, symbols)
  6. Restrict admin panel access by IP if possible (via .htaccess or Nginx)
🚨
Never expose your Stripe secret key or PayPal secret in client-side code or publicly accessible files. These are stored in the database (admin settings) and used only server-side.

🔄 Upgrading

When a new version is available:

  1. Back up your database and the assets/uploads/ folder first
  2. Upload the new files, overwriting all existing PHP files
  3. Do not overwrite config.php — your credentials are in there
  4. Visit /admin/upgrade.php in your browser (login required) — or the standalone /upgrade/ tool — to run any database migrations
  5. Check the admin dashboard to confirm the version number updated

v4.2 → v4.4 (PWA, Galleries & Custom Design release)

The upgrade wizard handles everything — open Admin → Upgrade DB and click Run Upgrade Now. Here's what it does:

  • Creates the item_images table for multi-photo galleries
  • Adds 6 columns to items: long_description, ingredients, protein, carbs, fat, sugar
  • Inserts 10 new settings: pwa_* (3 keys), bg_* (5 keys), theme_font_display, theme_font_body
  • Bumps app_version to 4.3.0
  • Fully idempotent & non-destructive — never overwrites existing data

After the upgrade, customize the look in Settings → Appearance (background type, fonts, PWA toggle) and start adding extra photos to your menu items at Menu Items → Edit.

v4.1 → v4.2 (Thermal Receipt Printer release)

The upgrade wizard handles everything — open Admin → Upgrade DB and click Run Upgrade Now. Here's what it does:

  • Inserts 14 new settings rows: printer_* with safe defaults — printing is enabled but defaults to browser print mode, so nothing changes until you configure it
  • Bumps app_version to 4.2.0
  • No table/column changes needed — the printer feature reuses the existing orders data
  • Existing settings (POS receipt footer, etc.) are never overwritten; the printer's footer falls back to your POS footer if blank
  • Safe to re-run the upgrade — it only adds what's missing

After the upgrade, configure your printer at Settings → Printer and run a test print.

v4.0 → v4.1 (POS + WhatsApp release)

The upgrade wizard handles all of this automatically:

  • Adds columns to orders: source, served_by_staff_id, cash_received, change_due
  • Inserts new settings rows: whatsapp_* (5 keys) and pos_* (7 keys) with safe defaults
  • Existing orders default to source='qr'
⚠️
Always back up before upgrading. The upgrade tool runs ALTER TABLE migrations safely but a backup ensures you can roll back if needed.

🛠 Troubleshooting

Blank White Page / 500 Error

  • Enable PHP error display temporarily: add ini_set('display_errors', 1); at the top of config.php
  • Check server error log: tail -f /var/log/apache2/error.log or /var/log/nginx/error.log
  • Verify config.php has correct database credentials

Database Connection Failed

  • Confirm DB_HOST, DB_NAME, DB_USER, DB_PASS in config.php
  • On some hosts use 127.0.0.1 instead of localhost
  • Verify the MySQL user has SELECT, INSERT, UPDATE, DELETE privileges on the database

Images Not Uploading

  • Check assets/uploads/ is writable: ls -la assets/uploads/
  • Run: chmod -R 755 assets/uploads/
  • Verify PHP upload_max_filesize and post_max_size in php.ini (recommend 10M+)

QR Codes Not Generating

  • Verify BASE_URL in config.php is correct and accessible from the internet
  • Check cURL is installed: php -m | grep curl

Orders Not Appearing in Admin

  • Check that the orders table exists and has data: SELECT COUNT(*) FROM orders;
  • Confirm the API endpoint /api/orders.php is accessible and returns JSON
  • Check browser console for JavaScript errors on the customer menu

Emails Not Sending

  • Configure SMTP in Settings → Notifications instead of relying on PHP's mail()
  • For Gmail: use an App Password (not your main Gmail password) and enable "Less secure app access" or use OAuth
  • Test with port 587 (TLS) — many hosts block port 25

Stripe Payments Failing

  • Ensure you are using the correct key pair (test vs live)
  • Verify the domain is HTTPS (Stripe requires TLS in production)
  • Check the Stripe Dashboard → Logs for detailed error messages

❓ Frequently Asked Questions

Can I use this on shared hosting?

Yes. QRMenu Pro works on any shared hosting plan that supports PHP 7.4+ and MySQL. cPanel-based hosts (SiteGround, Hostinger, Bluehost) work out of the box.

Can customers order without scanning a QR code?

Yes. You can link directly to the menu at /menu/ without a table ID. Customers can select their table at checkout, or you can disable the table requirement in settings.

How do I add multiple restaurants / locations?

The current version supports a single restaurant per installation. For multiple locations, install one copy per location in separate directories or subdomains, each with its own database.

Can I translate the menu into another language?

The menu content (item names, descriptions) is fully multilingual — just type in any language. The admin UI is in English. Interface-level translation requires editing PHP template files.

Is the menu printed or digital only?

Digital only by default. The QR code points to the live web menu. For a printable PDF version of the menu, use your browser's print function on the menu page.

Where are uploaded images stored?

All uploads are stored in assets/uploads/ on your server — no third-party cloud storage is required.

How do I reset the admin password?

Run this SQL query in phpMyAdmin or your MySQL client:

UPDATE staff SET password = '$2y$10$...' WHERE email = 'admin@example.com';

Generate a bcrypt hash with PHP: <?php echo password_hash('new_password', PASSWORD_BCRYPT); ?>

How do I back up the database?

mysqldump -u qrmenu -p qrmenu_db > backup_$(date +%Y%m%d).sql

Can I use a custom domain?

Yes. Point your domain to the folder, update BASE_URL in config.php, and update the same value in Settings → Advanced.


QRMenu Pro v4.4  ·  Documentation  ·  © 2026 QRMenu Pro

For support, please include your PHP version, error messages, and steps to reproduce the issue.