פאנל הניהול הוא אפליקציית עמוד יחיד (SPA) שנבנית מפאנלים: כל פאנל הוא מחלקת PHP אחת שמחזירה HTML, וכל כתובת {admin}/<panel>/<method> מפעילה מתודה אחת שלה. בדף הזה מוסבר איך כתובת הופכת לפאנל, איפה הקוד יושב, מה הטבלאות שמנהלות את התפריט וההרשאות, ומה שייך לליבה ומה לאתר.
{admin} הוא CONFIG::$admin_url, ו-system/ הוא תיקיית הליבה (api/core בריפו).
כתובת האדמין#
CONFIG::$admin_url הוא slug בלי לוכסנים (למשל admin), והוא נכנס כמו שהוא לביטוי רגולרי ב-ROUTER. הוא יחסי ועובד דרך <base href>, ולכן אל תשתמשו בו בכותרת Location או בקישור שיוצא מהאתר. קישור מוחלט בונים מ-CONFIG::$site_url (שמסתיים ב-/).
מיפוי כתובת לפאנל#
ROUTER מזהה כתובות אדמין לפי ארבעה דפוסים ומציב $_GET["module"], $_GET["pname"] ו-$_GET["id"]:
| כתובת | module | pname | id |
|---|---|---|---|
{admin} | ריק (דף הבית) | ריק | |
{admin}/news | news | ריק | |
{admin}/news/1 | news | ריק | 1 (מספר) |
{admin}/news/insert | news | insert | |
{admin}/news/insert/1 | news | insert | 1 |
pname ריק הופך ל-index בהמשך. בדפוס של שלושה קטעים (module/pname/id) ה-id הוא כל מה שאחרי ה-pname, ולא חייב להיות מספר.
אם הוגדרה רשימת מדינות מותרות (admin_countries), גישה מחוץ לה מופנית לעמוד הבית של האתר. הבדיקה מדולגת כשהבקשה מגיעה מאותו שרת (REMOTE_ADDR שווה ל-SERVER_ADDR) ולכתובות של Wizzo.
מה קורה בבקשה: AdminModule::GetPageContent#
AdminModule (system/libraries/AdminModule.php) מריץ את הפאנל לפי הסדר הזה:
- טוען את שורת הפאנל מ-
CRM_adminPanel_panelsואת האפשרויות שלו מ-panels_options. - פאנל של Wizzo Market (מוגדר ב-
system/market_settings.json) מופנה ל-wizzo_market?tool=.... - טוען את קובץ הפאנל (
require_once) ובודק אם המחלקה מגדירהskip_permission_check. - דוחה ל-404 (
ERRORPAGE) כשאין שורה בטבלה או שאין הרשאה, או כש-perm_developer = 1והמשתמש אינו מפתח. פרטים ב-הרשאות. - רושם צפייה בפאנל (
admin_panel_views::record_view), שמזין את "הפאנלים הנצפים ביותר" בבית. - יוצר
new ADMINMODULE_<module>(), קובעpname(ברירת מחדלindex), בודק ש-method_exists, ומחזיר את התוצאה של$mdl->Wrapper($mdl->$pname()).
כל הפאנלים נטענים דרך GetPageContent, וגם דף הבית (home) הוא רק פאנל כזה שלא צריך שורה בטבלה.
מצבי תצוגה: pmode#
פרמטר pmode קובע כמה מהעמוד חוזר:
pmode | תוצאה |
|---|---|
| ריק | עמוד מלא (theme admin_panel, או admin_login כשלא מחוברים) |
inner | רק תוכן הפאנל. adminMovePage טוענת אותו לתוך #mainframe |
empg | "empty page": תגובת JSON או HTML חלקי, למשל שמירת טופס ופעולות של טבלה |
הפאנל שולח לדפדפן מידע דרך כותרות תגובה: breadcrumbs (דרך MISC::breadcrumbs($list)), add_action, scripts ו-scripts_ver, AI-New-ID, AI-Form-Error, AI-Error. הדפדפן מגיב להן ב-funcs.js של ה-theme.
איפה יושב קוד פאנל#
| מיקום | תוכן |
|---|---|
application/admin/<name>.php | פאנל של האתר: class ADMINMODULE_<name> |
system/admin/<name>.php | פאנל מובנה של הליבה (ראו פאנלים מובנים) |
application/admin/includes/ | נטען אוטומטית בכל בקשת אדמין: מקום למחלקות FormInput_* מותאמות ופונקציות עזר |
system/libraries/ | AdminModule, panel_table, forms/ (הטפסים ושדותיהם) |
system/collections/ADMIN.php | התחברות, סשנים והרשאות |
system/themes/admin_panel/ | מעטפת ה-SPA, התפריט ו-funcs.js |
אם קיימים באותו שם קובץ בשתי התיקיות, הקובץ של הליבה (system/admin/) מנצח את זה של application/admin/. אל תקראו לפאנל שלכם בשם של פאנל מובנה.
הטבלאות שמריצות את התפריט#
כל הטבלאות בקידומת CRM_; ה-builder של DB מקבל את השם בלי הקידומת.
| טבלה | תפקיד |
|---|---|
adminPanel_panels_categories | קטגוריות התפריט: id, name, ord |
adminPanel_panels | פאנל בתפריט: id, panel_name, text, module_link, category, deletable, ord, pic, icon, extra_perms, perm_developer, stats_views, view_count |
adminPanel_panels_options | תת-פעולות של פאנל: id, panelId, name, filename, attribute, ord, icon |
adminPanel_admins_groups | קבוצות הרשאה: id, name, perms |
adminPanel_admins | המנהלים (ראו התחברות) |
panel_name שווה לשם הקובץ ב-application/admin/ (בלי .php), ו-module_link ריק לפאנלים שמגובים בקוד. ראו את הסכמה המלאה ב-טבלאות.
הוספת קובץ פאנל לא מספיקה כדי שהוא יופיע: חייבים שורה ב-adminPanel_panels. איך רושמים אותה מפורט ב-בניית פאנל חדש.
הבית: דף הפתיחה#
פאנל home מציג קיצורי דרך ותיבות. אתם יכולים להוסיף אליהם מקוד האתר:
// עד 6 קיצורים, החדש נכנס ראשון
admin_home::push_quick_action([
"label" => "מאמרים",
"icon" => "📰",
"url" => CONFIG::$admin_url . "/articles",
]);
// תיבה בדף הבית; $position מאפשר מיקום מסוים, ברירת מחדל: בסוף
admin_home::push_box([
"label" => "סיכום מכירות",
"content" => function () {
return "<p>תוכן התיבה</p>";
},
]);
המבנה של פריט קיצור (label, icon, url) זהה לברירות המחדל של המחלקה admin_home. הקיצורים מסוננים לפי הרשאה: קיצור לפאנל שאין למנהל גישה אליו לא מוצג.
ליבה מול אתר#
- ליבה (
system/): מתעדכנת ב"עדכון גרסה" ואסור לערוך אותה באתר (ראו עדכונים). כל מה שבה זהה בכל האתרים. - אתר (
application/): הפאנלים, הקונטרולרים והשדות שלכם. עדכון גרסה לא נוגע בהם.
כדי לשנות התנהגות של פאנל מובנה, אל תערכו אותו: צרו פאנל משלכם בשם אחר, או הרחיבו דרך נקודות ההרחבה (application/admin/includes/, admin_home::push_box, admin_home::push_quick_action).
Smarty בפאנלים לא עושה escape אוטומטי, ופאנלים מחזירים מחרוזות HTML. כל ערך שמגיע ממשתמש חייב לעבור htmlspecialchars לפני ההדפסה (ראו CSRF, XSS ו-SQLi).