Skip to content

Navigation

Control how resources appear in the menu and how users navigate between screens.

Set the group, sort order, and label on your resource:

php
class CustomerResource extends Resource
{
    protected static ?string $navigationGroup = 'Sales';   // Menu tab
    protected static int $navigationSort = 1;              // Position within tab
    protected static ?string $navigationLabel = 'Customers'; // Defaults to $label
    protected static bool $showInNavigation = true;        // false to hide from menu
}

Tab order

Resources are grouped into menu tabs by $navigationGroup. Control the tab sequence in config/twowee.php:

php
'menu' => [
    'default_tab' => 'Home',
    'tab_order' => ['Home', 'Sales', 'Purchasing', 'Finance'],
],

Tabs not listed appear at the end alphabetically.

Example

php
class CustomerResource extends Resource {
    protected static ?string $navigationGroup = 'Sales';
    protected static int $navigationSort = 1;
}

class ItemResource extends Resource {
    protected static ?string $navigationGroup = 'Sales';
    protected static int $navigationSort = 2;
}

class SalesOrderResource extends Resource {
    protected static ?string $navigationGroup = 'Sales';
    protected static int $navigationSort = 3;
    protected static bool $navigationSeparatorBefore = true; // divider above
}

class VendorResource extends Resource {
    protected static ?string $navigationGroup = 'Purchasing';
    protected static int $navigationSort = 1;
}

class CustomerLedgerEntryResource extends Resource {
    protected static bool $showInNavigation = false; // only via drill-down
}

This produces:

  • Sales: Customers, Items, ─── (separator), Sales Orders
  • Purchasing: Vendors

Group related destinations into a floating sub-list. Resources with the same $navigationPopup value (within the same group) appear together under one label:

php
class PostedInvoiceResource extends Resource {
    protected static ?string $navigationGroup = 'Sales';
    protected static ?string $navigationPopup = 'Posted';
    protected static int $navigationSort = 10;
}

class PostedCreditMemoResource extends Resource {
    protected static ?string $navigationGroup = 'Sales';
    protected static ?string $navigationPopup = 'Posted';
    protected static int $navigationSort = 11;
}

The user sees "Posted ▸" in the Sales tab. Enter opens a floating list: Posted Invoices, Posted Credit Memos.

Separators

Add a visual divider above an item to break a long tab into logical groups:

php
class SalesOrderResource extends Resource {
    protected static bool $navigationSeparatorBefore = true;
}

The separator is a blank line — not selectable, navigation skips it.

Every screen has a parent — where Escape goes when there's no navigation history. The plugin sets this automatically:

  • Card / HeaderLines → the resource's list screen
  • List / Grid/menu/main

For resources under a sub-menu, override it:

php
class PostedInvoiceResource extends Resource {
    protected static ?string $navigationParent = 'menu/sales';
}

The Escape chain then builds automatically:

Posted Invoice Card → Escape → Posted Invoices List → Escape → Sales Sub-Menu → Escape → Main Menu

Most resources don't need this — the default is correct when resources live directly under the main menu.

Custom menu items

Add placeholders, sub-menus, or other non-resource items via config:

php
// config/twowee.php
'menu' => [
    'items' => [
        ['label' => 'Reports', 'group' => 'Finance', 'sort' => 99,
         'action' => ['type' => 'message', 'text' => 'Coming soon.']],

        ['label' => 'Setup', 'group' => 'Admin', 'sort' => 1,
         'action' => ['type' => 'open_menu', 'url' => '/terminal/menu/setup']],
    ],
],
Action typeBehavior
open_screenNavigate to a screen URL
open_menuOpen a sub-menu
popupFloating list of destinations
messageShow text in the status bar
separatorVisual divider
open_urlOpen URL in system browser