Appearance
Menu Categories
Overview
Categories organize menu items into logical groups. They determine how items are displayed and navigated in Online Ordering and Kiosk.
Key Purpose: Organize menu items for easy customer navigation.
Purpose
This page lets you create, edit, and organize menu categories that group items into sections customers browse on online ordering and kiosk channels.
Key Concepts
- Category: A named grouping of menu items with an optional description, an optional parent category, and an optional image. Items reference a category through their own
category_id. - Parent Category: A category can optionally be nested under a parent category via
parent_id, giving one level of nesting (subcategories). Only root (top-level) categories can be chosen as parents. - Multi-language Details: Category name and description are stored in a
detailsmap keyed by language, withdefaultas the primary language entry.
Actions
Create Category
Add a new category with a name, optional description, optional parent category, and an optional image. The category is saved and synced to all active third-party integrations (Square, MplusKassa, etc.).
Edit Category
Update a category's name, description, parent category, or image. After saving, the cache for every item in the category is cleared so changes are reflected immediately, and the change is synced to active integrations.
Delete Category
Remove a category permanently. Deletion is blocked if the category still contains items -- all items must be reassigned or removed first.
Location
- Backoffice Route:
/menus/categories - Backend Controller:
app/Http/Controllers/Api/BackOffice/CategoryController.php - Page:
src/pages/menus/categories/index.vue→ View:src/views/reporting-categories/ReportingCategories.vue - Form:
src/components/forms/items/CategoryForm.vue
Fields
Category Name
| Property | Value |
|---|---|
| Field ID | details.name |
| Label | Category Name |
| Type | Text |
| Required | Yes |
| Validation | Required string (no max length enforced) |
Description: Name of the category shown to customers as a menu section header or navigation tab.
Best Practices:
- Keep names short (1-3 words)
- Use familiar terms customers expect
- Be consistent with industry standards
Customer Impact:
- Online Ordering: Tab/section header in menu
- Kiosk: Large category buttons
Examples:
- "Starters"
- "Main Courses"
- "Pizzas"
- "Burgers"
- "Drinks"
- "Desserts"
- "Sides"
- "Kids Menu"
Category Description
| Property | Value |
|---|---|
| Field ID | details.description |
| Label | Description |
| Type | Textarea |
| Required | No |
| Validation | Optional string (no max length enforced) |
Description: Optional description shown below category name.
Customer Impact:
- Online Ordering: Shown as subtitle under category name
- Kiosk: May be displayed on category selection screen
Examples:
- "Start your meal with our delicious appetizers"
- "Hand-stretched, wood-fired pizzas"
- "Freshly made desserts"
Category Image
| Property | Value |
|---|---|
| Field ID | image |
| Label | Category Image |
| Type | Image Upload |
| Required | No |
| Validation | JPG, PNG, SVG, WebP; max 10MB |
Description: Image representing the category. Used in visual menu layouts.
Customer Impact:
- Online Ordering: Category thumbnail (if visual menu enabled)
- Kiosk: Large category image on selection screen
Best Practices:
- Use appetizing food photos
- Show representative items from category
- Consistent style across categories
Parent Category
| Property | Value |
|---|---|
| Field ID | parent_id |
| Label | Parent Category |
| Type | Select |
| Required | No |
Description: Optional parent category to nest this category underneath, creating a subcategory. The dropdown lists only root (top-level) categories and excludes the category being edited, so the hierarchy is limited to one level of nesting and a category can never be its own parent.
Business Logic:
- No parent selected → Root (top-level) category
- Parent selected → Subcategory nested under that parent
Customer Impact
Online Ordering
- Navigation: Categories as tabs or sidebar sections
- Scrolling: Scroll to category section
- Filtering: Click category to filter items
- Visual: Category images (if enabled)
Kiosk
- Home Screen: Large category buttons
- Selection: Tap category to see items
- Navigation: Back to categories button
- Visual: Category images prominent
Receipt
- Items grouped by category (optional)
- Category name may appear as section header
Relations
Depends On
- Parent Category: A subcategory references a parent category via
parent_id(one level of nesting).
Affects
- Menu Items: Items reference a category through their own
category_id. - Order Capacity: Category-specific limits reference categories.
- Reports: Sales by category.
Related Features
Business Rules
- A category cannot be deleted if it still contains items; the system returns a 400 error with "Delete failed since the category is currently being used."
- Category images are processed through media upload and stored as content entities; the resulting
content_idis saved on the category record. - When a category is updated, the item cache for every item in that category is cleared to ensure ordering channels display the latest data.
- Category creation, update, and deletion are synced to all active third-party integrations (Square, MplusKassa, etc.) using the category model type and the corresponding event constant.
- Categories synced one-way from a POS are protected: Kassanet-synced categories cannot be modified or deleted locally, and read-only inbound POS systems (e.g. ShopCaisse) cannot create or delete categories from the back office.
- The
detailsfield merges existing language translations with the new update, preserving translations for languages not included in the current request.
FAQs
How do I create a subcategory? When creating or editing a category, choose a Parent Category to nest it underneath. Only root (top-level) categories can be selected as parents, so the hierarchy is limited to one level of nesting.
Is there a limit to how many categories I can create? There is no hard limit in the system, but keeping the number manageable is recommended for a good customer browsing experience.
What happens if I try to delete a category that still has items? Deletion is blocked. You must reassign or remove every item first, otherwise the system returns "Delete failed since the category is currently being used."
"What fields can I actually set when creating a category?" A category has four editable fields: Category Name (required), Description (optional), Parent Category (optional), and an image. There's no menu picker, visibility toggle, availability schedule, or tax-rate field on the category form.
"How do I create a subcategory / nest categories?" When creating or editing a category, choose a Parent Category to nest it underneath. The list then shows the hierarchy as an expandable tree, and only root (top-level) categories can be selected as parents.
"Why can't I pick a parent category that is itself a subcategory?" The parent dropdown only lists root categories and excludes the category you're editing, so the hierarchy is limited to one level of nesting and a category can never be its own parent.
"What image formats and size are allowed for a category image?" Category images accept JPG, PNG, SVG, and WebP up to 10 MB.
"Why does a category show a higher item count than the items directly inside it?" Each category in the tree shows both its direct item count and an aggregate count that adds up the items in all of its subcategories, so a parent reflects everything beneath it.
"Why can't I delete a category?" Deletion is blocked while the category still has items assigned. Reassign or remove every item first, otherwise you get "Delete failed since the category is currently being used."
"I added a translation but my edit didn't wipe the other languages — is that expected?" Yes. Category name and description are stored per language, and saving merges your update with existing translations, so languages you didn't touch are preserved.
"Why is the Name (or Parent) field greyed out on some categories?" Categories synced from a POS are locked: Kassanet and Lightspeed K-Series categories lock Name and Parent, and MplusKassa categories lock Name and Description, because those fields are owned by the POS and would be overwritten on the next sync.
"I edited a category but nothing changed for customers — why?" After saving, the system clears the cache for every item in that category so ordering channels pick up the change. If you still don't see it, confirm the save succeeded and that the items belong to that category.
"Do my categories get pushed to my connected POS / Square?" Yes. Creating, updating, or deleting a category triggers a sync to all active integrations (Square, MplusKassa, etc.); read-only inbound POS systems like Kassanet and ShopCaisse are protected and can't be created/edited/deleted from the back office.
"I can't find the Create Category button — why?" It only appears if you have the create-category permission and the location's POS allows catalog creation; a read-only inbound POS hides it.
Troubleshooting
Problem: Category not showing in menu
Causes:
- Category has no items
- All items in category unavailable
Solutions:
- Add items to category
- Enable item availability
Problem: Items in wrong category
Causes:
- Item assigned to wrong category
- Category names confusing
Solutions:
- Edit item → Change category
- Rename categories for clarity
Problem: Edited category but nothing changed for customers
Causes:
- Item cache not yet reflected
- Items not actually assigned to this category
Solutions:
- Confirm the save succeeded (the system clears the cache for every item in the category on save)
- Verify the items belong to that category
Examples
Single Category (create payload)
The store/update endpoint accepts a details object (with name and optional description), an optional parent_id, and an optional image:
json
{
"details": {
"name": "Starters",
"description": "Start your meal with our delicious appetizers"
},
"parent_id": null
}Standard Restaurant Categories
json
{
"categories": [
{ "details": { "name": "Starters" } },
{ "details": { "name": "Salads" } },
{ "details": { "name": "Main Courses" } },
{ "details": { "name": "Sides" } },
{ "details": { "name": "Desserts" } },
{ "details": { "name": "Drinks" } }
]
}Pizza Restaurant
json
{
"categories": [
{ "details": { "name": "Classic Pizzas", "description": "Our traditional favorites" } },
{ "details": { "name": "Specialty Pizzas", "description": "Chef's special creations" } },
{ "details": { "name": "Build Your Own", "description": "Create your perfect pizza" } },
{ "details": { "name": "Pasta" } },
{ "details": { "name": "Salads" } },
{ "details": { "name": "Sides & Extras" } },
{ "details": { "name": "Desserts" } },
{ "details": { "name": "Drinks" } }
]
}Subcategories (one level of nesting)
A child category references its parent via parent_id:
json
{
"categories": [
{ "details": { "name": "Drinks" } },
{ "details": { "name": "Hot Drinks" }, "parent_id": "<drinks_category_id>" },
{ "details": { "name": "Cold Drinks" }, "parent_id": "<drinks_category_id>" }
]
}