Skip to content

Display Groups

Overview

Display Groups are the visual organizational units within a menu that group items into sections as they appear to customers. While categories serve as a backend classification system, display groups control the actual layout and presentation of items on customer-facing channels (kiosk, online ordering, QR ordering). Each display group belongs to a menu, contains ordered item references, and has per-channel visibility controls.

Display groups are stored in the menus MongoDB collection with model type display_group and support soft deletion. They hold multilingual details, a content image reference, channel visibility settings, external IDs for third-party integrations, and an ordered array of item/variant group references.

Purpose

This page lets you create, edit, and manage display groups that organize menu items into visual sections on kiosks, online ordering, and other customer-facing channels, controlling exactly which items appear together and in what order.

Key Concepts

  • Display Group: A named container of menu items that defines a visual section on the customer-facing menu. Each display group has multilingual details (with a default key containing name and description), a content_id referencing an optional image, an ordered item_ids array, menu_ids for menu associations, visibility for channel control, a location_id, a pos_name for POS integration, and external_ids/external_data for third-party systems. Stored in the menus collection with SOFT_DELETE = true.
  • Visibility: An array of ChannelOptions enum values that controls where the display group appears. Valid channels are: Kiosk, POS, Online Ordering, Table Qr Ordering, Uber Eats, Takeaway, and Shopify. A display group is only rendered on channels listed in its visibility array. Items within the group are further filtered by their own platform settings.
  • Item Ordering: Items within a display group are displayed in the order they appear in the item_ids array. This ordering is preserved when rendering menus on kiosk (kioskSerialize) and online ordering (onlineOrderingSerialize). The array can contain both regular item IDs and variant group IDs, which are resolved at render time.
  • Menu Association: Display groups are linked to menus via a bidirectional relationship. The display group stores menu_ids and the menu stores display_group_ids. When a display group is created, the syncRelations method adds its ID to the specified menu's display_group_ids array and syncs the menu reference on the display group.
  • Label Consistency: All items within a single display group must share the same label (e.g., all "Regular" items or all items with a specific external integration label). The validateItems method checks every item's label against the first item's label and throws an exception with a descriptive message naming the group if labels are mixed.

Route

  • Backoffice Route: /menus (Menu Builder), /menus/display-groups (dedicated page)
  • Backend Controller: app/Http/Controllers/Api/DisplayGroupController.php
  • Orchestrator: app/Services/Orchestrators/BackOffice/DisplayGroupOrchestrator.php
  • Service: app/Services/BackOffice/DisplayGroupService.php
  • Model: app/RawModels/DisplayGroup.php
  • Repository: app/Repositories/DisplayGroupRepository.php
  • Request Validators: app/Http/Requests/BackOffice/DisplayGroup/StoreDisplayGroupRequest.php, app/Http/Requests/BackOffice/DisplayGroup/UpdateDisplayGroupRequest.php
  • Resources: app/Http/Resources/BackOffice/Menu/DisplayGroupResource.php, app/Http/Resources/BackOffice/Menu/ShowDisplayGroupResource.php
  • Vue Components: src/views/menus/dialogs/DisplayGroupDialog.vue, src/views/menus/components/MenuDisplayGroups.vue, src/components/dialogs/DisplayGroupListDialog.vue
  • Store Module: src/store/modules/displayGroup.ts

Actions

List Display Groups

Retrieve all display groups for the current vendor, filtered by location. The service first fetches all menus for the vendor, then queries display groups where menu_ids contains any of those menu IDs. Additional filter parameters from the LocationScopedRequest are applied. Returns a collection of DisplayGroupResource objects.

  • Endpoint: GET /api/back-office/display-groups?location_id={locationId}
  • Response: JSON array of display group resources with id, details, content, visibility, and other fields

Create Display Group

Create a new display group with the required fields. The flow:

  1. Validates the request via StoreDisplayGroupRequest
  2. Checks name uniqueness within the target menu using isFieldValueUsed on the DisplayGroupRepository
  3. Wraps the name/description in a details.default structure for multi-language support
  4. If an image is provided, uploads it via handleMediaUpload under the display-groups directory and stores the resulting content_id
  5. Saves the display group document via the repository
  6. Calls syncRelations to link items and add the display group to the specified menu
  7. Dispatches a DisplayGroupCreated guided setup event with the vendor database, location ID, service path (self-service), and setup category (build_menu)
  • Endpoint: POST /api/back-office/display-groups
  • Response: JSON DisplayGroupResource of the created display group

View Display Group Details

Retrieve the full details of a specific display group by ID, including its items, visibility settings, menu associations, and content image. Returns a ShowDisplayGroupResource with expanded item data.

  • Endpoint: GET /api/back-office/display-groups/{id}
  • Response: JSON ShowDisplayGroupResource

Update Display Group

Modify a display group's name, description, image, POS name, or visibility settings. The flow:

  1. Validates the request via UpdateDisplayGroupRequest
  2. Retrieves the existing display group
  3. Checks name uniqueness against other display groups in the same menu (excluding the current one by ID)
  4. Merges new details into the existing details structure under the default key
  5. If a new image is provided, uploads it and updates content_id; otherwise sets content_id to null
  6. Saves the updated document
  7. Dispatches a ReloadMenu event for the affected location to refresh cached menus
  • Endpoint: PUT /api/back-office/display-groups/{id}
  • Response: JSON DisplayGroupResource of the updated display group

Delete Display Group

Permanently remove a display group (soft delete). Dispatches a ReloadMenu event to refresh cached menus for the affected location. The deleteByMenuId method allows bulk deletion of all display groups associated with a given menu ID, dispatching ReloadMenu events for each affected location.

  • Endpoint: DELETE /api/back-office/display-groups/{id}
  • Response: Success response

Fields

FieldIDTypeRequiredValidation
Namedetails.nameStringYesrequired|string -- must be unique within the same menu
Descriptiondetails.descriptionStringNonullable|string
POS Namepos_nameStringNonullable|string -- unique within connection via custom rule
Image Sourceimage.sourceEnumNoOne of: direct_upload, existing, url, photo_studio, external, square, suggestions_api
Image Fileimage.fileFileNonullable|max:5000 (5 MB maximum)
VisibilityvisibilityArrayYesrequired|array -- at least one channel required
Visibility Channelvisibility.*EnumYesOne of: Kiosk, POS, Online Ordering, Table Qr Ordering, Uber Eats, Takeaway, Shopify
Location IDlocation_idStringYesrequired|string|exists:locations,_id
Menu IDmenu_idStringYes (create)required|string -- must exist in menus collection; not required on update

Business Rules

  • Display group names must be unique within the same menu. The isFieldValueUsed method queries the DisplayGroupRepository with the name value and an optional moreFilter of menu_ids to scope the uniqueness check. A 400 error with "Name should be unique" is returned for duplicates.
  • All items within a display group must have the same label. The validateItems method iterates through all item IDs, retrieves each item (or variant group), checks its label, and throws an exception with "Group {name}: All items must have the same label" if any mismatch is found.
  • Display groups use soft delete (SOFT_DELETE = true), meaning deleted records are marked with a deletion timestamp rather than physically removed from the menus MongoDB collection.
  • When a display group is created or updated with an image, the image is uploaded to Cloudflare Images under the display-groups directory path via the ContentTrait.handleMediaUpload method. If no image is provided on update, content_id is set to null.
  • Deleting a menu automatically deletes all associated display groups via the deleteByMenuId method, which iterates through all display groups with the matching menu_ids filter and calls delete on each, dispatching ReloadMenu events per affected location.
  • The syncRelations method handles both item assignment (syncing item_ids on the display group) and menu linkage (adding the display group ID to the menu's display_group_ids array). It also calls syncMenu on the repository to update the menu-to-display-group mapping.
  • Display group content images use the kioskgroup variant by default when resolving URLs via getContentUrl, ensuring optimized image sizes for kiosk display.
  • Items within a display group are further filtered at render time by status (Active only) and platform visibility, so even if an item is in the group's item_ids, it will not appear on a channel if it is inactive or lacks the channel in its platforms list.

Customer Impact

  • Kiosk: Display groups define the main navigation sections on the kiosk screen. Customers browse items by tapping on display group tabs or scrolling through sections. Only display groups with Kiosk in their visibility array appear. Items within each group are rendered in item_ids order, filtered to Active status and Kiosk platform.
  • Online Ordering: Display groups structure the online menu into browsable sections. Each display group renders as a section header with its multilingual name, optional description, and image (via getContentUrl), followed by the items it contains. Only groups with Online Ordering visibility appear.
  • QR Ordering: Display groups with Table Qr Ordering visibility appear on the table QR ordering menu, organizing items for dine-in customers scanning a QR code at their table.
  • Third-Party Integrations: Display groups with Uber Eats, Takeaway, or Shopify visibility are synced to those external platforms, with external_ids and external_data tracking the mapping.

FAQs

What is the difference between a display group and a category?

Categories are a backend classification system for items (used for tax rates, reporting, and organization). Display groups control the visual layout of items on customer-facing menus. An item belongs to one category but can appear in multiple display groups across different menus.

Can an item appear in multiple display groups?

Yes. An item can be added to multiple display groups, even within the same menu. The item will appear in each section where it is included, and its order within each group is independent.

How do I control the order of items within a display group?

Items are displayed in the order they appear in the item_ids array. You can reorder items by dragging them in the Menu Builder interface, which updates the array order. The backend preserves this order when serializing for kiosk and online ordering.

Can I assign a display group to multiple menus?

A display group tracks menu_ids as an array and can technically be associated with multiple menus, but the standard creation flow assigns it to a single menu via the required menu_id field. The bidirectional relationship is managed through both the display group's menu_ids and the menu's display_group_ids.

What happens to items when I delete a display group?

Deleting a display group does not delete the items within it. The items remain in the system and can be assigned to other display groups. Only the grouping container is removed.

What are the supported image sources for display groups?

Display group images can come from: direct_upload (file upload), existing (existing content), url (external URL), photo_studio (Photo Studio library), external (external import), square (Square integration), or suggestions_api (AI suggestions).

How does soft delete work for display groups?

Display groups use soft delete (SOFT_DELETE = true), meaning they are marked with a deletion timestamp rather than physically removed from the MongoDB menus collection. This allows for potential recovery and ensures referential integrity with other documents that may reference the display group.

Can I translate display group names?

Yes. Display group names and descriptions are stored in a multilingual details structure. The default key holds the primary language text, and additional language keys can be added through the translations system. The TranslationEntities enum includes a reference for display groups.

Troubleshooting

Display group does not appear on the kiosk or online ordering

Check the display group's visibility array -- it must include the specific channel (Kiosk, Online Ordering, etc.) to appear on that platform. Also verify the parent menu is assigned and active for the relevant location. Check that items within the group are set to Active status and have the matching platform in their platforms list.

"Name should be unique" error when creating a display group

Another display group with the same name already exists within the target menu. Use a different name or rename the existing display group first. The uniqueness check is scoped to the menu, so the same name can be used across different menus.

"All items must have the same label" error

This occurs when items with different labels (e.g., mixing "Regular" items with externally imported items from a different integration) are assigned to the same display group. Ensure all items in the group share the same label classification. The error message includes the display group name for identification.

Display group image is not showing

Verify the image was uploaded successfully by checking the content_id field on the display group document. Ensure Cloudflare Images is configured and the referenced Content document exists with valid cloudflare_image_id. The image file must be under 5 MB per the validation rule (max:5000).

Changes to display group are not reflected on kiosk/ordering

Display group updates trigger a ReloadMenu event, but cached menus may take a moment to refresh. Check that the menu cache has been cleared for the affected location. If the issue persists, try making a minor edit to the parent menu to force a complete cache refresh.

Items appear in wrong order in the display group

Item order is determined by the item_ids array sequence. If items appear in an unexpected order, check the array contents in the database. In the Menu Builder, you can drag items to reorder them, which updates the item_ids array through the syncRelations method.

Technical Details

Serialization for Customer Channels

Display groups are serialized differently depending on the target channel:

  • Online Ordering (onlineOrderingSerialize): Returns id, details (multilingual), image_url, and items. Items are filtered by visibility matching the online ordering channel and status: Active. Each item is serialized using its onlineOrderingSerialize method with the location context.
  • Kiosk (kioskSerialize): Returns id, details, image_url, and items. Items are filtered by platforms: Kiosk and status: Active. Each item is serialized using its kioskSerialize method. The image URL uses the kioskgroup variant from Cloudflare Images.

Variant Group Handling

The item_ids array can contain both regular item IDs and variant group IDs. The getItems method resolves both types by querying both the ItemRepository and VariantGroupRepository. When withVariantGroup is true, variant groups are returned as-is; when false, variant groups are expanded into their individual items. In production, variant groups are always expanded for kiosk rendering (as the kiosk app does not yet fully support variant groups).

External Integration Data

Display groups carry external_ids and external_data fields for third-party platform synchronization. These fields store mapping information for platforms like Uber Eats, Deliveroo, Takeaway, Shopify, and Square. The toSnapshot method includes these fields when creating a point-in-time snapshot for offers, but only for display groups with non-regular labels.

Multi-Language Support

Display group details are stored in a nested structure with a default key containing the primary language name and description. When a display group is updated, the new details are merged under the default key while preserving other language entries. The translation system references display groups via the TranslationEntities enum.

Import and Sync Mechanisms

Display groups can be imported from external sources through two mechanisms:

  • Kassanet Import: The ImportKassanetDisplayGroupsJob imports display groups from the Kassanet POS system, creating display group documents with external IDs and data mapping.
  • Third-Party Integrations: The AbstractThirdPartyIntegrationService and its implementations (UberEatsService, DeliverooService, ShopifyIntegrationService, SquareUpService) handle bidirectional syncing of display groups with external platforms, mapping between Upvendo's display group structure and each platform's category/section format.

Assistant Guidance

When users ask about display groups, clarify the distinction from categories -- display groups control visual layout on customer channels, while categories are for backend organization and tax rate assignment. Guide users to create display groups within the Menu Builder interface by selecting a menu first. If users want items to appear on specific channels only, explain the visibility array and how to configure it per channel. When troubleshooting missing items on kiosk or online ordering, check three things: (1) the display group's visibility array includes the target channel, (2) the individual item's platform settings include the target channel, and (3) the item's status is Active. For multi-language setups, explain that display group names and descriptions are stored under the details.default key and can have translations added per language.

Relations

Depends On

  • Menus: Display groups must belong to at least one menu. The menu must exist before a display group can be created within it, enforced by the menu_id validation rule.
  • Items: Display groups reference items (and variant groups) via item_ids. Items must exist before being added to a display group.
  • Locations: Display groups are scoped to a location via location_id, which must reference a valid location document.
  • Content Service: Images for display groups are stored as Content entities via Cloudflare Images, referenced by content_id.
  • Variant Groups: Display groups can contain variant group IDs in their item_ids array, which are resolved to individual items at render time.

Affects

  • Kiosk App: Display groups define the navigation structure and item grouping on kiosk screens via kioskSerialize.
  • Online Ordering: Display groups structure the online menu layout for customers via onlineOrderingSerialize.
  • QR Ordering: Display groups organize the table QR ordering menu for dine-in customers.
  • Menu Cache: Creating, updating, or deleting display groups triggers ReloadMenu events to refresh cached menus for the affected location.
  • Guided Setup: Creating a display group dispatches a DisplayGroupCreated event to update guided setup progress for the build_menu task.
  • Third-Party Integrations: Display groups with external platform visibility are synced to Uber Eats, Takeaway, and Shopify via their respective integration services.
  • Translations: Display group names and descriptions can be translated via the translation system, with entries keyed by TranslationEntities enum.