Siteβ―Builder
Editing:
modules-admin.php
writable 0666
<?php /***************************************************************** * modules-admin.php β Global module manager (v3, sortable) * ------------------------------------------------------------- * Location: /pages/modules/modules-admin.php * JSON file: /pages/modules/modules.json *****************************************************************/ require_once __DIR__.'/../../members/lib/auth.php'; require_login(); if (current_user()['role']!=='admin') forbidden_page(); /* βββββ settings βββββ */ const MOD_ROOT = __DIR__; // /pages/modules const JSON_FILE = MOD_ROOT.'/modules.json'; /* βββββ helpers βββββ */ function load_json(): array { if (!is_file(JSON_FILE)) return []; return json_decode(file_get_contents(JSON_FILE), true) ?: []; } function save_json(array $arr): void { file_put_contents(JSON_FILE, json_encode($arr, JSON_PRETTY_PRINT|JSON_UNESCAPED_SLASHES), LOCK_EX); } function scan_fs(array $list): array { $found=[]; foreach (glob(MOD_ROOT.'/*', GLOB_ONLYDIR) as $dir) { $name = basename($dir); $file="modules-$name.php"; if(!is_file("$dir/$file")) continue; $rel ="$name/$file"; $http="/pages/modules/$rel"; $old =$list[$name] ?? []; $found[$name]=[ 'name'=>$name, 'file'=>$file, 'relative_path'=>$rel, 'http_path'=>$http, 'active'=>$old['active']??false, 'tier' => in_array($old['tier'] ?? '', ['free','premium','admin'], true) ? $old['tier'] : 'free' ]; } /* keep current order unless new ones appended */ $ordered=[]; foreach(array_column($list,'name') as $n) if(isset($found[$n])) $ordered[$n]=$found[$n]; foreach($found as $n=>$row) if(!isset($ordered[$n])) $ordered[$n]=$row; return $ordered; } /* βββββ current state βββββ */ $mods=[]; foreach(load_json() as $row) $mods[$row['name']]=$row; /* βββββ POST βββββ */ if($_SERVER['REQUEST_METHOD']==='POST'){ /* rescan */ if(isset($_POST['rescan'])){ $mods=scan_fs($mods); save_json(array_values($mods)); header('Location: modules-admin.php?msg=scanned'); exit; } /* new order comes as CSV list n1,n2,n3β¦ */ if(isset($_POST['order'])){ $order=explode(',',$_POST['order']); $ordered=[]; foreach($order as $n) if(isset($mods[$n])) $ordered[$n]=$mods[$n]; /* append any forgotten keys (JS disabled) */ foreach($mods as $n=>$row) if(!isset($ordered[$n])) $ordered[$n]=$row; $mods=$ordered; } /* active & tier */ foreach($mods as $n=>&$row){ $row['active']=isset($_POST['act'][$n]); $row['tier']=($_POST['tier'][$n]??'free')==='premium'?'premium':'free'; } save_json(array_values($mods)); header('Location: modules-admin.php?msg=saved'); exit; } /* sync fs silently on every GET */ $mods=scan_fs($mods); save_json(array_values($mods)); ?> <!doctype html> <title>Module Manager βΒ BestDealOn</title> <meta name=viewport content="width=device-width,initial-scale=1"> <style> :root{--brand:#0066ff;--bg:#f6f9ff;--fg:#111;font-family:-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Helvetica,Arial,sans-serif} body{margin:0;background:var(--bg);color:var(--fg)} main{max-width:880px;margin:2.5rem auto;padding:0 1rem} h1{font-size:1.7rem;margin-top:0} table{width:100%;border-collapse:collapse;margin-top:1.4rem;font-size:.92rem} th,td{padding:.55rem .7rem;border-bottom:1px solid #e2e8f3} th{background:#edf3ff;font-weight:600;text-align:left} .drag{cursor:grab;color:#888;text-align:center;width:26px} .center{text-align:center} button{padding:.55rem 1.3rem;border:none;border-radius:6px;font-weight:600;cursor:pointer;margin-right:.6rem} .save{background:var(--brand);color:#fff} .scan{background:#ffb31c;color:#fff} select{padding:.35rem .5rem;border:1px solid #ccd2e2;border-radius:6px;background:#fff} .msg{padding:.8rem 1rem;border-radius:8px;margin-top:.9rem;font-weight:600} .ok{background:#e7f9eb;color:#0b8133} tr.dragging{opacity:.5} @media(prefers-color-scheme:dark){ :root{--bg:#0d1117;--fg:#e6edf3;--brand:#2f81f7} table,th,td{border-color:#30363d} th{background:#1d2b55} select{background:#0d1117;color:var(--fg);border-color:#444c5e} } </style> <main> <h1>Global ModuleΒ Manager</h1> <?php if(isset($_GET['msg'])): ?> <div class="msg ok"> <?= $_GET['msg']==='saved' ?'Changes savedΒ β' :'Rescan completeΒ β new modules added as inactiveΒ β' ?> </div> <?php endif; ?> <form id=frm method=post> <input type=hidden name=order id=orderField> <table id=modTable> <tr> <th class=drag>β‘</th><th>Name</th><th>PHP file</th> <th class=center>Active?</th><th class=center>Tier</th> </tr> <?php foreach($mods as $row): $n=htmlspecialchars($row['name']); ?> <tr data-name="<?= $n ?>"> <td class="drag">β‘</td> <td><?= $n ?></td> <td><code><?= htmlspecialchars($row['relative_path']) ?></code></td> <td class=center> <input type=checkbox name="act[<?= $n ?>]" <?= $row['active']?'checked':'' ?>> </td> <td class=center> <select name="tier[<?= htmlspecialchars($row['name']) ?>]"> <option value="free" <?= $row['tier']==='free' ?'selected':'' ?>>free</option> <option value="premium" <?= $row['tier']==='premium' ?'selected':'' ?>>premium</option> <option value="admin" <?= $row['tier']==='admin' ?'selected':'' ?>>admin</option> </select> </td> </tr> <?php endforeach; ?> </table> <p style="margin-top:1.4rem"> <button class=save>πΎΒ Save changes</button> <button class=scan name=rescan value=1>πΒ Scan for new modules</button> </p> </form> <p style="margin-top:2rem"><a href="/members/dashboard.php">βΒ Back to dashboard</a></p> </main> <script> /* --- drag & drop reorder ----------------------------------- */ const table = document.getElementById('modTable'); let dragging; table.addEventListener('pointerdown', e=>{ const handle = e.target.closest('.drag'); if(!handle) return; dragging = handle.parentElement; dragging.classList.add('dragging'); e.preventDefault(); }); table.addEventListener('pointermove', e=>{ if(!dragging) return; const after = [...table.querySelectorAll('tr[data-name]:not(.dragging)')] .find(row => e.clientY < row.getBoundingClientRect().top + row.offsetHeight/2); table.tBodies[0].insertBefore(dragging, after||null); }); table.addEventListener('pointerup', ()=>{ if(dragging){ dragging.classList.remove('dragging'); dragging=null; } }); /* before submit β write new order csv */ document.getElementById('frm').addEventListener('submit', ()=>{ const names=[...table.querySelectorAll('tr[data-name]')].map(r=>r.dataset.name); document.getElementById('orderField').value = names.join(','); }); </script>
Save changes
Create folder
writable 0777
Create
Cancel