Website Menus

8 Aufrufe Markdown

The seven endpoints that build, order and edit the trees of five menu groups.

Overview

Website menus live in five separate groups: the header, the footer, the client panel, mobile and the sidebar. Each group is its own tree, and items do not move between groups.

An item either points at a page or carries a link written by hand. One pointing at a page follows that page when its address changes, while a hand-written link stays as it is.

The title, description, badge and mega-menu content are kept per language. The order and the nesting are written through an endpoint of their own, in one call.

Reference

Reading the Menu Tree

get/api/v1/admin/website/menus
Website/GetMenus admin

Returns a whole menu group as a nested tree.

Query 1
groupstringWhich menu: header, footer, clientArea, mobile, sidebar. The header menu by default.
Response fields data[] — 11 + meta — 2
idintThe item id.
parentintThe parent item. Zero says it sits at the top level.
typestringThe menu group it belongs to.
iconstringThe item icon.
rankintWhere it sits among its siblings.
targetboolWhether the link opens in a new tab.
statusstringWhether the item is live.
pagestringThe page it points at. Empty means the link was written by hand.
only_client_areaboolWhether the item shows in the client panel alone.
languagesobjectThe title, link, description, badge and mega-menu content per language.
childrenarrayThe items beneath it. Same shape, nesting further down.
groupstringThe menu group asked for. It comes back under meta.
countintHow many items sit at the top level.
Errors 2
invalid_group422The menu group is not recognised.
insufficient_scope403The key lacks the required scope.
Request
curl 'https://panel.example.com/api/v1/admin/website/menus?group=header' \
  -H "Authorization: Bearer $API_KEY"
const url = new URL('https://panel.example.com/api/v1/admin/website/menus');
url.searchParams.set('group', 'header');

const res  = await fetch(url, {
  headers: { Authorization: `Bearer ${apiKey}` },
});
const body = await res.json();
$ch = curl_init('https://panel.example.com/api/v1/admin/website/menus?' . http_build_query(['group' => 'header']));
curl_setopt_array($ch, [
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_HTTPHEADER     => ['Authorization: Bearer ' . $apiKey],
]);

$body = json_decode(curl_exec($ch), true);
curl_close($ch);
// Each group is a SEPARATE tree; seeing them all takes five calls.
$header = Api::Website()->GetMenus([], ['group' => 'header'])['data'];
$footer = Api::Website()->GetMenus([], ['group' => 'footer'])['data'];

Reading the Page Options

get/api/v1/admin/website/menus/page-options
Website/GetMenuPageOptions admin

Returns the pages a menu item can point at.

Response fields data
dataarrayThe list of pages you can point at. The keys for the page field come from here.
Errors 1
insufficient_scope403The key lacks the required scope.
Request
curl 'https://panel.example.com/api/v1/admin/website/menus/page-options' \
  -H "Authorization: Bearer $API_KEY"
const res  = await fetch('https://panel.example.com/api/v1/admin/website/menus/page-options', {
  headers: { Authorization: `Bearer ${apiKey}` },
});
const body = await res.json();
$ch = curl_init('https://panel.example.com/api/v1/admin/website/menus/page-options');
curl_setopt_array($ch, [
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_HTTPHEADER     => ['Authorization: Bearer ' . $apiKey],
]);

$body = json_decode(curl_exec($ch), true);
curl_close($ch);
// Do not write the keys into your code: the list follows the installation's own pages.
$options = Api::Website()->GetMenuPageOptions()['data'];

Reordering the Menu

put/api/v1/admin/website/menus/reorder
Website/ReorderMenus admin order and parent together

Writes the order and the nesting of menu items in one call.

Body 1
ordersarrayreqThe new arrangement. Each entry carries an id, a position and a parent, and children nest through their own list.
Response fields data — 1
reorderedintHow many items were written. The nested ones count too.
Errors 2
orders_required422No item was sent.
insufficient_scope403The key lacks the required scope.
Request
curl -X PUT 'https://panel.example.com/api/v1/admin/website/menus/reorder' \
  -H "Authorization: Bearer $API_KEY" \
  -H 'Content-Type: application/json' \
  -d '{"orders":[{"id":10,"position":0,"parentId":0,"submenuOrder":[{"id":11,"position":0,"parentId":10}]}]}'
const res = await fetch('https://panel.example.com/api/v1/admin/website/menus/reorder', {
  method: 'PUT',
  headers: {
    Authorization: `Bearer ${apiKey}`,
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
    orders: [
      {
        id: 10,
        position: 0,
        parentId: 0,
        submenuOrder: [{ id: 11, position: 0, parentId: 10 }],
      },
    ],
  }),
});

const body = await res.json();
$ch = curl_init('https://panel.example.com/api/v1/admin/website/menus/reorder');
curl_setopt_array($ch, [
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_CUSTOMREQUEST  => 'PUT',
    CURLOPT_HTTPHEADER     => [
        'Authorization: Bearer ' . $apiKey,
        'Content-Type: application/json',
    ],
    CURLOPT_POSTFIELDS => json_encode([
        'orders' => [[
            'id'           => 10,
            'position'     => 0,
            'parentId'     => 0,
            'submenuOrder' => [['id' => 11, 'position' => 0, 'parentId' => 10]],
        ]],
    ]),
]);

$body = json_decode(curl_exec($ch), true);
curl_close($ch);
// An item you leave out STAYS PUT: a partial list can leave the tree half-moved.
$r = Api::Website()->ReorderMenus(['orders' => $tree]);
$written = $r['data']['reordered'];

Reading One Menu Item

get/api/v1/admin/website/menus/{id}
Website/GetMenu admin

Returns one menu item with its languages.

Response fields data — 11
idintThe item id.
parentintThe parent item. Zero says it sits at the top level.
typestringThe menu group it belongs to.
iconstringThe item icon.
rankintWhere it sits among its siblings.
targetboolWhether the link opens in a new tab.
statusstringWhether the item is live.
pagestringThe page it points at. Empty means the link was written by hand.
only_client_areaboolWhether the item shows in the client panel alone.
languagesobjectThe title, link, description, badge and mega-menu content per language.
childrenarrayThe items beneath it. Same shape, nesting further down.
Errors 2
menu_not_found404No such menu item.
insufficient_scope403The key lacks the required scope.
Request
curl 'https://panel.example.com/api/v1/admin/website/menus/10' \
  -H "Authorization: Bearer $API_KEY"
const res  = await fetch(`https://panel.example.com/api/v1/admin/website/menus/${id}`, {
  headers: { Authorization: `Bearer ${apiKey}` },
});
const body = await res.json();
$ch = curl_init('https://panel.example.com/api/v1/admin/website/menus/' . $id);
curl_setopt_array($ch, [
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_HTTPHEADER     => ['Authorization: Bearer ' . $apiKey],
]);

$body = json_decode(curl_exec($ch), true);
curl_close($ch);
// The children list comes back EMPTY here; use the group endpoint to see the tree.
$item = Api::Website()->GetMenu(['id' => $id])['data'];

Adding a Menu Item

post/api/v1/admin/website/menus
Website/CreateMenu admin

Adds a new item to a menu.

Body 7
groupstringreqThe menu the item goes into: header, footer, clientArea, mobile, sidebar.
parentintThe parent item. Left out, the item joins the top level.
pagestringThe page to point at. Left empty, you write the link by hand in the language field.
iconstringThe item icon.
targetintOpens the link in a new tab.
rankintWhere it sits among its siblings.
languagesobjectThe content per language: title, link, description, badge text with its colours, and mega-menu content.
Response fields 201 — data — 11
dataobjectThe menu item created. Same shape as the detail endpoint.
Errors 3
invalid_group422The menu group is not recognised.
create_failed500The item could not be created.
insufficient_scope403The key lacks the required scope.
Request
curl -X POST 'https://panel.example.com/api/v1/admin/website/menus' \
  -H "Authorization: Bearer $API_KEY" \
  -H 'Content-Type: application/json' \
  -d '{"group":"header","page":"home","languages":{"tr":{"title":"Ana Sayfa"}}}'
const res = await fetch('https://panel.example.com/api/v1/admin/website/menus', {
  method: 'POST',
  headers: {
    Authorization: `Bearer ${apiKey}`,
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
    group: 'header',
    page: 'home',
    languages: {
      en: { title: 'Home', description: 'Back to homepage', label: 'New' },
    },
  }),
});

const body = await res.json();
$ch = curl_init('https://panel.example.com/api/v1/admin/website/menus');
curl_setopt_array($ch, [
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_POST           => true,
    CURLOPT_HTTPHEADER     => [
        'Authorization: Bearer ' . $apiKey,
        'Content-Type: application/json',
    ],
    CURLOPT_POSTFIELDS => json_encode([
        'group'     => 'header',
        'page'      => 'home',
        'languages' => ['en' => ['title' => 'Home']],
    ]),
]);

$body = json_decode(curl_exec($ch), true);
curl_close($ch);
// The title is written PER LANGUAGE; a language you leave out shows an empty label.
Api::Website()->CreateMenu([
    'group'     => 'header',
    'page'      => 'home',
    'languages' => ['en' => ['title' => 'Home'], 'tr' => ['title' => 'Ana Sayfa']],
]);

Updating a Menu Item

patch/api/v1/admin/website/menus/{id}
Website/UpdateMenu admin

Changes the menu item fields you send.

Body 6
iconstringThe item icon.
pagestringThe page to point at.
targetintOpens the link in a new tab.
rankintWhere it sits among its siblings.
parentintThe parent item. Moves the item to another branch.
languagesobjectThe content per language: title, link, description, badge text with its colours, and mega-menu content.
Response fields data — 11
dataobjectThe item as it now stands. Same shape as the detail endpoint.
Errors 2
menu_not_found404No such menu item.
insufficient_scope403The key lacks the required scope.
Request
curl -X PATCH 'https://panel.example.com/api/v1/admin/website/menus/10' \
  -H "Authorization: Bearer $API_KEY" \
  -H 'Content-Type: application/json' \
  -d '{"rank":1,"languages":{"tr":{"title":"Anasayfa"}}}'
const res = await fetch(`https://panel.example.com/api/v1/admin/website/menus/${id}`, {
  method: 'PATCH',
  headers: {
    Authorization: `Bearer ${apiKey}`,
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
    rank: 1,
    languages: { en: { title: 'Homepage' } },
  }),
});

const body = await res.json();
$ch = curl_init('https://panel.example.com/api/v1/admin/website/menus/' . $id);
curl_setopt_array($ch, [
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_CUSTOMREQUEST  => 'PATCH',
    CURLOPT_HTTPHEADER     => [
        'Authorization: Bearer ' . $apiKey,
        'Content-Type: application/json',
    ],
    CURLOPT_POSTFIELDS => json_encode([
        'rank'      => 1,
        'languages' => ['en' => ['title' => 'Homepage']],
    ]),
]);

$body = json_decode(curl_exec($ch), true);
curl_close($ch);
// An item cannot move to another GROUP; the group is given at creation alone.
Api::Website()->UpdateMenu(['id' => $id, 'parent' => $newParent]);

Deleting a Menu Item

delete/api/v1/admin/website/menus/{id}
Website/DeleteMenu admin children go too

Removes a menu item and everything beneath it.

Response fields data — 3
deletedboolWhether the delete ran.
idintThe id of the item removed.
removedarrayEvery id removed. The children appear in this list too.
Errors 2
menu_not_found404No such menu item.
insufficient_scope403The key lacks the required scope.
Request
curl -X DELETE 'https://panel.example.com/api/v1/admin/website/menus/10' \
  -H "Authorization: Bearer $API_KEY"
const res = await fetch(`https://panel.example.com/api/v1/admin/website/menus/${id}`, {
  method: 'DELETE',
  headers: { Authorization: `Bearer ${apiKey}` },
});

const { data } = await res.json();
console.log(data.removed);   // [10, 11]
$ch = curl_init('https://panel.example.com/api/v1/admin/website/menus/' . $id);
curl_setopt_array($ch, [
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_CUSTOMREQUEST  => 'DELETE',
    CURLOPT_HTTPHEADER     => ['Authorization: Bearer ' . $apiKey],
]);

$body = json_decode(curl_exec($ch), true);
curl_close($ch);
// Deleting a parent takes the SUBMENU with it; move the children elsewhere first.
$gone = Api::Website()->DeleteMenu(['id' => $id])['data']['removed'];

Pitfalls

A delete takes the submenu with it

Deleting a menu item also deletes everything beneath it. Removing a top-level heading takes every link under it out of the menu. The removed list in the response tells you what actually went, so move the children under another item first when you want to keep them.

An item cannot change group

The menu group is given at creation alone, and the update does not take it. Moving a header link into the footer means creating it again in the new group and removing the old one. The same holds for the reorder endpoint: it shifts things only within one tree.

The reorder covers only what you send

The reorder endpoint writes only the items in your list, and whatever you leave out stays where it was. Sending part of the tree and skipping the rest can leave the menu half-moved. Read the number written from the response and weigh it against what you expected.

The title is per language

A menu title is written separately in each language. Skip one and the item shows there with an empty label: it does not vanish, it stands nameless. Switch a new language on and none of the existing items carries a title in it, so you have to walk through them all.

A page link and a hand-written link differ

An item pointing at a page follows it by itself when the page address changes. A hand-written link stays as it is and breaks once the page moves. When the target is a page on your own site, use the page field instead of typing an address; the page options endpoint gives you the valid keys.

War das hilfreich?

Vielen Dank für Ihre Rückmeldung!

Brauchen Sie weitere Hilfe?

Unser Support-Team ist rund um die Uhr für Sie da, wenn Sie oben nicht fündig werden.