ArtiGrid
Menu Action tree
This demo shows how to build a hierarchical menu using ArtiGrid's Tree View. Items can be organized into parent and child relationships, reordered using drag and drop, and managed with custom edit and delete actions. The tree data and ordering are handled through separate PHP endpoints.
<?php
$grid = new ArtiGrid();
$grid->table('nav_items')
->formFields([
'parent_id',
'slug',
'title',
'icon',
'active',
'order'
])
->required(false)
->combobox('active', [
'1' => 'Active',
'2' => 'Disabled'
])
->fieldAttr('icon', [
'data-iconpicker' => '1',
'class' => 'icon-picker-input'
])
->validation_required([
'slug',
'title',
'icon',
'active'
])
->fieldType('order', 'hidden')
->colRename('parent_id', 'Padre')
->colRename('slug', 'Slug')
->combobox('parent_id', 'nav_items', 'id', 'title')
->orderby('order', 'asc')
->setActionCondition('delete', [
['id', '!=', 8],
['id', '!=', 12],
['id', '!=', 28],
['id', '!=', 29],
['id', '!=', 1],
['id', '!=', 6],
['id', '!=', 2],
['id', '!=', 3],
])
->fieldCondition(
'title',
'slug',
'in',
['dashboard', 'table-builder', 'builder', 'menu'],
'hide'
)
->fieldCondition(
'slug',
'slug',
'in',
['dashboard', 'table-builder', 'builder', 'menu'],
'hide'
)
->perPage(5)
->columnHide(['id'])
->unset('clone', false)
->unset('view', false)
->treeView([
'treeUrl' => 'tree.php?action=tree',
'orderUrl' => 'save_order.php',
'noDeleteIds' => [8, 12, 28, 29, 1, 6, 2, 3],
'title' => 'Menú',
]);
echo $grid->render('tree');
?>
// tree.php
<?php
require __DIR__ . '/../../artigrid/ArtiGrid.php';
header('Content-Type: application/json');
$action = $_GET['action'] ?? '';
try {
if ($action === 'tree') {
$db = DB::connect();
$rows = $db->query(
"SELECT
id,
parent_id,
slug,
title,
icon,
`order`,
active
FROM nav_items
ORDER BY ISNULL(parent_id) DESC,
parent_id ASC,
`order` ASC"
)->fetchAll(PDO::FETCH_ASSOC);
if (function_exists('user_can')) {
$rows = array_values(
array_filter($rows, function ($row) {
$slug = $row['slug'] ?? '';
return $slug === ''
? true
: user_can($slug);
})
);
}
foreach ($rows as &$row) {
$row['actions'] = [
[
'action' => 'edit',
'id' => $row['id']
],
[
'action' => 'delete',
'id' => $row['id']
]
];
}
unset($row);
echo json_encode($rows);
exit;
}
if ($action === 'save-order') {
$body = json_decode(
file_get_contents('php://input'),
true
);
$items = $body['order'] ?? [];
if (empty($items)) {
echo json_encode([
'success' => false,
'message' => 'No data received'
]);
exit;
}
$pdo = DB::connect();
$stmt = $pdo->prepare(
"UPDATE nav_items
SET parent_id = :pid,
`order` = :ord
WHERE id = :id"
);
$pdo->beginTransaction();
foreach ($items as $item) {
$stmt->execute([
':pid' => !empty($item['parent_id'])
? (int) $item['parent_id']
: null,
':ord' => (int) ($item['order'] ?? 0),
':id' => (int) ($item['id'] ?? 0)
]);
}
$pdo->commit();
echo json_encode([
'success' => true
]);
exit;
}
http_response_code(400);
echo json_encode([
'success' => false,
'message' => 'Invalid action'
]);
} catch (\Throwable $e) {
if (isset($pdo) && $pdo instanceof PDO && $pdo->inTransaction()) {
$pdo->rollBack();
}
http_response_code(500);
echo json_encode([
'success' => false,
'message' => $e->getMessage()
]);
}
?>
// save_order.php
<?php
require __DIR__ . '/../../artigrid/ArtiGrid.php';
header('Content-Type: application/json');
$pdo = null;
try {
$body = json_decode(
file_get_contents('php://input'),
true
);
$items = $body['order'] ?? [];
if (empty($items)) {
echo json_encode([
'success' => false,
'message' => 'No data received'
]);
exit;
}
$pdo = DB::connect();
$stmt = $pdo->prepare(
"UPDATE nav_items
SET parent_id = :pid,
`order` = :ord
WHERE id = :id"
);
$pdo->beginTransaction();
foreach ($items as $item) {
$stmt->execute([
':pid' => !empty($item['parent_id'])
? (int) $item['parent_id']
: null,
':ord' => (int) ($item['order'] ?? 0),
':id' => (int) ($item['id'] ?? 0)
]);
}
$pdo->commit();
echo json_encode([
'success' => true,
'message' => 'Order saved successfully'
]);
} catch (\Throwable $e) {
if ($pdo && $pdo->inTransaction()) {
$pdo->rollBack();
}
http_response_code(500);
echo json_encode([
'success' => false,
'message' => $e->getMessage()
]);
}
exit;
?>