סוג תוכן שהפעיל workflow מקבל שלושה דברים: סטטוס לכל רשומה (טיוטה, ממתין לאישור, מתוזמן, מפורסם, מוסתר), טיוטה נפרדת לשינוי ברשומה שכבר באוויר, וסינון אוטומטי בצד האתר, כך שמבקר לא רואה דבר שלא פורסם. הכול מנוהל במחלקה CONTENT_WORKFLOW, ומסכי הניהול מדברים איתה דרך ה-API של content_status. הפיצ'ר זמין מגרסת הליבה 5.0.148 (בדקו ב-system/core/version.txt), ותזמון ותצוגה מקדימה נוספו עליו מגרסה 5.0.155 (תזמון ותצוגה מקדימה).
בעמוד הזה system/ הוא תיקיית הליבה הפרוסה (api/core בקוד המקור), ו-{admin} הוא CONFIG::$admin_url של האתר.
כל צד השרת עובד: העמודות, הטיוטות, הסינון, התזמון ו-API. ברשימות panel_table יש לשוניות סטטוס וכפתורי פרסום והסתרה לשורות שנבחרו. מסכי הניהול המלאים (כפתורי "שמירה כטיוטה" ו"שליחה לאישור" בטופס, מסך הטיוטות והתזמון) יגיעו בגרסה מאוחרת יותר. עד אז אפשר לשלוח את הפעולות לטופס ישירות, כמו בסעיף "מה הטופס מקבל".
מי משתתף#
טבלה משתתפת רק כששלושת התנאים מתקיימים:
- היא רשומה כסוג תוכן עם
workflow = 1, בקריאהCONTENT::register()שהפאנל שלה מבצע. - יש בה העמודה
wz_status. - האתר לא כיבה את הפיצ'ר עם הפרמטר
content_workflowשערכו"0"(ראו פרמטרים ושפות).
כל טבלה אחרת לא משתנה בכלום. כיום Pages (עמודי התוכן) היא הסוג הרשום, והיא נרשמת עם workflow => 1, עם preview_url => "pages/{id}" ועם title_field => "title".
העמודות של CRM_pages מגיעות לאתר בעדכון גרסה (update_db מעתיק מבנה מהמאסטר). טבלה משלכם לא מקבלת אותן לבד. כדי להכניס אותה לתהליך, הוסיפו את העמודות בעצמכם (הגדרות ב"העמודות" למטה) ורשמו אותה עם CONTENT::register("my_table", ["label" => "...", "panel" => "MyPanel", "workflow" => 1, "preview_url" => "my/{id}", "title_field" => "title"]). ההרשמה כותבת ל-CRM_content_types רק כשמשהו השתנה, ולכן אפשר לקרוא לה בכל טעינה של הפאנל.
העמודות#
העמודות נוספות לטבלה הראשית של סוג התוכן (לא לטבלת ה-_content), כלומר סטטוס אחד לרשומה בכל השפות.
| עמודה | טיפוס | ברירת מחדל | משמעות |
|---|---|---|---|
wz_status | varchar(12) | 'published' | draft, review, scheduled, published או hidden |
wz_publish_at | datetime | NULL | מתי רשומה מתוזמנת עולה לאוויר |
wz_unpublish_at | datetime | NULL | מתי רשומה מפורסמת מפסיקה להופיע באתר |
wz_published_at | datetime | NULL | הפעם הראשונה שהרשומה פורסמה |
wz_created_by | int | 0 | מזהה המנהל שיצר את הרשומה |
לטבלה יש גם אינדקס על (wz_status, wz_publish_at). ברירת המחדל published היא כל התאימות לאחור: שורה שהייתה קיימת לפני העמודות, ושורה שקוד של אתר מכניס בלי להכיר אותן, נשארת גלויה.
להוספה ידנית לטבלה משלכם:
ALTER TABLE `CRM_my_table`
ADD COLUMN `wz_status` varchar(12) NOT NULL DEFAULT 'published',
ADD COLUMN `wz_publish_at` datetime NULL DEFAULT NULL,
ADD COLUMN `wz_unpublish_at` datetime NULL DEFAULT NULL,
ADD COLUMN `wz_published_at` datetime NULL DEFAULT NULL,
ADD COLUMN `wz_created_by` int NOT NULL DEFAULT 0,
ADD INDEX `wz_status_publish` (`wz_status`, `wz_publish_at`);
הסטטוסים#
| ערך | תווית בניהול | האתר מציג? |
|---|---|---|
draft | טיוטה | לא |
review | ממתין לאישור | לא |
scheduled | מתוזמן | לא, עד wz_publish_at |
published | מפורסם | כן, כל עוד wz_unpublish_at ריק או בעתיד |
hidden | מוסתר | לא |
רשומה מפורסמת ש-wz_unpublish_at שלה עבר לא מוצגת באתר גם לפני שהמתזמן הספיק לסמן אותה כ-hidden (ראו תזמון ותצוגה מקדימה). הרשימות בניהול מסמנות אותה כ"פג תוקף".
הקבועים CONTENT_WORKFLOW::STATUSES ו-CONTENT_WORKFLOW::LABELS מחזיקים את הרשימה ואת התוויות, ו-CONTENT_WORKFLOW::ACTIONS ממפה את פעולת הטופס לסטטוס.
מי רשאי לעבור בין סטטוסים#
| מעבר | הרשאה |
|---|---|
draft ל-review ובחזרה | edit על הפאנל של סוג התוכן |
| כל מעבר אחר (פרסום, הסתרה, תזמון, פרסום מחדש) | publish על הפאנל |
הרשאת publish נבדקת כאפשרות נוספת של הפאנל (extra_perms ב-CRM_adminPanel_panels). פאנל שלא הגדיר אותה, דורש edit גם לפרסום. ראו הרשאות וקבוצות. הבדיקה עצמה היא CONTENT_WORKFLOW::can_publish(), והפונקציה CONTENT_WORKFLOW::needs($from, $to) אומרת איזו הרשאה מעבר דורש.
טיוטה של רשומה שכבר באוויר#
רשומה חדשה שעוד לא פורסמה היא פשוט שורה עם wz_status = 'draft'. הטבלה CRM_content_drafts נועדה רק לשינוי שממתין על רשומה שפורסמה (או הוסתרה): עד שמפרסמים, הגרסה שבאתר לא משתנה.
| עמודה | משמעות |
|---|---|
id | מזהה הטיוטה |
tbl, row_id, lang_id | הטבלה (בלי CRM_), הרשומה והשפה. שלישייה ייחודית: טיוטה פתוחה אחת לרשומה בכל שפה |
post_data | ה-POST המלא של הטופס, כ-JSON, ועוד הפאנל והמתודה ששמרו. זה מה שהפרסום מריץ מחדש |
overlay | העמודות שהטיוטה הייתה כותבת (main ו-content), מה שהתצוגה המקדימה מציגה |
base_version_id | הגרסה בהיסטוריה שהטיוטה נפתחה ממנה, להתראה על התנגשות (ראו גרסאות תוכן) |
status | draft, review או scheduled |
publish_at | מתי להעלות את הטיוטה, כשהיא מתוזמנת |
admin_id | המנהל ששמר |
updated_at | מתי נשמרה לאחרונה |
הטבלה נוצרת באתר בעדכון גרסה. אתר שעוד לא קיבל אותה ממשיך לשמור כמו קודם (CONTENT_WORKFLOW::ready() מחזיר false).
למה שומרים POST ולא ערכים#
קלט בטופס יכול לעשות יותר מלכתוב עמודה: SEO, גלריות, תגיות, קישורים בין רשומות. הטיוטה לא מריצה את זה. היא שומרת את ה-POST, ובפרסום הליבה מזינה אותו שוב לאותו פאנל ולאותו טופס, ממש כמו שמירה רגילה. לכן כל קלט עושה בדיוק מה שהיה עושה בשמירה חיה, והגרסה שנרשמת בהיסטוריה היא מסוג publish. אותה שיטה משמשת את ה-MCP ואת ייבוא ה-Excel (POST מתוכנת לטופס).
מה הטופס מקבל#
הטופס מצהיר מה הוא רוצה בשדה POST בשם wz_action:
wz_action | משמעות |
|---|---|
draft | שמירה כטיוטה |
review | שליחה לאישור |
schedule | תזמון (דורש גם wz_publish_at, תאריך ושעה) |
publish | פרסום, שמירה חיה |
התנהגות לפי המצב של הרשומה:
| המצב | מה קורה |
|---|---|
רשומה חדשה, בלי wz_action | מי שמורשה לפרסם: נשמרת כ-published, כמו לפני שהפיצ'ר היה קיים. מי שלא מורשה: נשמרת כ-review (ראו למטה) |
רשומה חדשה עם wz_action | נשמרת בסטטוס שהפעולה מבקשת (טיוטה, ממתין, מתוזמן או מפורסם) |
רשומה שבאוויר (published או hidden) עם draft, review או schedule | השורה החיה לא נוגעת. ה-POST נשמר ב-CRM_content_drafts |
רשומה שבאוויר עם publish, או בלי wz_action ממי שמורשה לפרסם | שמירה חיה רגילה |
רשומה שלא באוויר (draft, review, scheduled) | נשמרת במקום, והפעולה מזיזה את הסטטוס |
publish ו-schedule דורשים הרשאת פרסום. בלי ההרשאה השמירה נדחית עם הודעה ולא נכתב דבר. schedule בלי תאריך תקף נדחה גם הוא.
שמירה בלי wz_action ממי שלא מורשה לפרסם (מגרסה 5.0.167) לא מעלה כלום לאוויר: הליבה מתייחסת אליה כאילו נשלח review, הפעולה שכפתור השמירה של הטופס נותן למנהל כזה. רשומה חדשה נשמרת כ-review, שינוי ברשומה שבאוויר נשמר כטיוטה שממתינה לאישור, ורשומה שעוד לא באוויר עוברת ל-review (גם רשומה מתוזמנת, כך ששינוי שלא אושר לא עולה במועד). שמירה אוטומטית של רשומה חדשה נשמרת כ-draft. טופס פשוט מוסיף להודעת השמירה שורה שאומרת שהרשומה נשלחה לאישור ולא פורסמה, ושמירה מתוכנתת מקבלת את המצב בכותרת AI-Record-Status. מי שמורשה לפרסם שומר בלי wz_action בדיוק כמו קודם.
שמירה אוטומטית. בקשת שמירה עם autosave=1 על רשומה שבאוויר הולכת תמיד לטיוטה, גם בלי wz_action, כך שהקלדה באמצע עריכה לא משנה את האתר. שמירה אוטומטית של רשומה שעוד לא באוויר נשמרת במקום.
שמירה חיה מנקה את הטיוטה של עצמה. שמירה חיה (לא אוטומטית) של רשומה, מאותו מנהל שיש לו עליה טיוטה, מוחקת את הטיוטה, כי היא כבר לא מתארת את מה שהמנהל התכוון.
קבצים. קובץ שהועלה ישירות ב-$_FILES לא ממתין בטיוטה, כי הקובץ הזמני נעלם בסוף הבקשה. שמירת טיוטה עם קובץ כזה נדחית עם הסבר. קלטים ששולחים מזהה של קובץ שכבר הועלה למאגר (כמו wzdrive) עובדים.
בשמירה מתוכנתת (כותרת AI-Form-Insert, כמו ב-MCP), שמירת טיוטה מחזירה את הכותרות AI-Draft-ID ו-AI-Draft-Status, ושמירה שנכתבה לרשומה עצמה מחזירה את AI-Record-Status עם הסטטוס שלה אחרי השמירה. save_record של ה-MCP מחזיר בהתאם mode: "draft" עם draft_id ו-draft_status, או status לצד id.
פרסום טיוטה#
CONTENT_WORKFLOW::publish_draft() מריצה מחדש את ה-POST השמור דרך הפאנל, כשמירה חיה, ואז מוחקת את הטיוטה, מעבירה את הרשומה ל-published ומנקה את המטמון של העמוד. אם אדם אחר שמר את הרשומה החיה אחרי שהטיוטה נפתחה, הפרסום נעצר עם conflict ופרטי ההתנגשות, אלא אם ביקשתם force.
מה האתר מציג: הסינון#
כשהקוד רץ מחוץ לניהול (CONFIG::$system_type שונה מ-admin), כל שאילתה של DB::query על טבלה משתתפת מקבלת את התנאי הבא על הטבלה הראשית (הכינוי tConf בשאילתה שהליבה בונה):
tConf.wz_status = 'published'
AND (tConf.wz_unpublish_at IS NULL OR tConf.wz_unpublish_at > '<now>')
ה-<now> הוא השעון של PHP (date()), אותו שעון שבו המנהל הקליד את התאריכים, ולא NOW() של שרת מסד נתונים שאולי יושב באזור זמן אחר.
המשמעות לכם כמפתחי אתר:
- מסוננות:
DB::query(...), וכל מה שנשען עליו:->get_row(),->get_all(),->num_rows()ו-DB::get_val(). בקרpagesרגיל, שקוראDB::get_val("pages", $id), מקבלfalseעל טיוטה ומחזיר 404, בלי שינוי שורה בקוד האתר. ראו שאילתות. - לא מסוננות: SQL גולמי (
DB::get_all("SELECT ..."),DB::get_row,DB::sql), וטבלאות שמצורפות ב-filterשל שאילתה. אתר שמשתמש ב-SQL גולמי על טבלת תוכן חייב להוסיף את התנאי בעצמו. - הניהול לא מסונן: בפאנלים אתם רואים הכול.
- אתר שלא אימץ סטטוס לא מרגיש שינוי: כל השורות הקיימות הן
published, ולכן הן ממשיכות להופיע.
SQL גולמי: CONTENT::visible_where()#
CONTENT::visible_where(string $table): string
מחזירה את תנאי "מה שהאתר מציג" לטבלה, בלי WHERE. לטבלה שאינה סוג תוכן עם סטטוס, או לאתר שכיבה את הפיצ'ר, היא מחזירה "1=1", כך שאפשר לקרוא לה בלי לבדוק. התנאי כתוב בלי כינוי טבלה, ולכן בשאילתה עם כמה טבלאות ודאו שהוא חל על הטבלה הנכונה.
$rows = DB::get_all("SELECT id FROM CRM_pages WHERE " . CONTENT::visible_where("pages") . " ORDER BY id DESC");
לעקוף את הסינון#
קוד שחייב לראות את כל הסטטוסים (כלי תחזוקה, משימת cron, דוח) בוחר באחת משתי דרכים.
לשאילתה אחת:
$q = DB::query("pages", ["id" => $id]);
$q->workflow_filter = false;
$row = $q->get_row(); // כולל טיוטות
לקטע קוד שלם:
CONTENT_WORKFLOW::$bypass = true;
try {
$all = DB::query("pages", [], "id DESC")->get_all();
} finally {
CONTENT_WORKFLOW::$bypass = false;
}
אל תעקפו את הסינון בקוד שמייצר תוכן לציבור (תבנית, בקר של עמוד, פיד, מפת אתר). טיוטה שדלפה לשם היא תוכן שלא אושר, באתר פתוח למנועי חיפוש. צריך לראות טיוטה באתר? זו תצוגה מקדימה, ראו תזמון ותצוגה מקדימה.
ה-API של content_status#
מסכי הניהול מדברים עם מודול ניהול בשם content_status, בכתובת {admin}/content_status/<method>?pmode=empg. הוא מחזיר JSON, ופתוח למנהל מחובר בלבד. הצפייה דורשת גישה לפאנל של סוג התוכן (השדה panel ב-CRM_content_types). מתודות POST דורשות גם טוקן CSRF: מביאים אותו ב-csrf, ושולחים גוף JSON עם השדה csrf (או את הכותרת X-WZ-CSRF). ראו CSRF, XSS ו-SQLi.
כשל תמיד נראה כך: {"success": false, "error": "<code>"}.
| מתודה | פרמטרים | מחזירה |
|---|---|---|
index | ready, רשימת הסטטוסים והתוויות | |
counts | tbl | כמה רשומות בכל סטטוס, ועוד expired, with_draft, total |
record | tbl, id, lang? | עמודות wz_* של הרשומה, הטיוטה הפתוחה שלה, ומה המנהל הנוכחי רשאי (can.edit, can.publish) |
drafts | tbl, ids (מופרדים בפסיק), lang? | {row_id: סטטוס טיוטה} לעמוד שלם של רשימה |
draft | id | טיוטה אחת עם ה-overlay שלה |
pending | limit? | מה שממתין לאדם, ראו CONTENT_WORKFLOW::pending() |
csrf | הטוקן לבקשות POST | |
set (POST) | tbl, ids[], status, publish_at?, unpublish_at? | changed, skipped, refused, counts |
publish_draft (POST) | draft_id, force? | תוצאת publish_draft() |
discard_draft (POST) | draft_id | {success, draft_id} |
preview | tbl, id, lang? | קישור תצוגה מקדימה, ראו תזמון ותצוגה מקדימה |
share (POST) | tbl, id, lang? | קישור שיתוף, שם |
schedule | מתי המתזמן יבדוק שוב, שם |
כמה כללים:
- ב-
setכל רשומה נבדקת לפי המעבר שלה: מעבר שדורשpublishלמנהל בלי הרשאה נרשם ב-refusedעםforbidden, וההמשך ממשיך. עד 500 רשומות בבקשה. - שינוי תאריך על אותו סטטוס נחשב מעבר של
publish. status: "scheduled"דורשpublish_at.unpublish_atריק מנקה את התאריך.discard_draftשל טיוטה של מנהל אחר דורש הרשאת פרסום. את הטיוטה של עצמכם אפשר לזרוק עםedit.- טיוטה נקראת תמיד עם הטבלה והפאנל שלה, לעולם לא לפי מה שנשלח בבקשה.
קודי שגיאה נפוצים: missing_tbl, type_without_workflow (הטבלה אינה סוג תוכן עם סטטוס), forbidden, not_found, bad_status, missing_ids, too_many, no_draft, post_only, csrf, וב-publish_draft: conflict, save_failed (עם errors לפי שדה), draft_unreadable, record_missing.
// שינוי סטטוס של שתי רשומות, מתוך פאנל הניהול
const base = "{admin}/content_status/";
const c = await (await fetch(base + "csrf?pmode=empg", { credentials: "same-origin" })).json();
const res = await (await fetch(base + "set?pmode=empg", {
method: "POST",
credentials: "same-origin",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ tbl: "pages", ids: [12, 13], status: "hidden", csrf: c.csrf }),
})).json();
ה-MCP והסטטוס#
בכלי הרשימה של ה-MCP (list_rows) כל שורה בפאנל של סוג תוכן עם סטטוס מקבלת wz_status, status_label, ואם צריך publish_at, unpublish_at ו-has_draft, כדי שסוכן לא יחשוב שטיוטה עלתה לאוויר. ראו קטלוג כלי ה-MCP.
ריפרנס: CONTENT_WORKFLOW#
המחלקה נמצאת ב-system/collections/CONTENT_WORKFLOW.php. שיטותיה לא זורקות חריגה: הן עונות, ובכשל רושמות שורה ל-error_log. השיטות של המתזמן מתוארות בתזמון ותצוגה מקדימה.
מאפיינים סטטיים#
| שם | ברירת מחדל | משמעות |
|---|---|---|
CONTENT_WORKFLOW::$bypass | false | true: שאילתות מחוץ לניהול רואות את כל הסטטוסים |
CONTENT_WORKFLOW::$replaying | false | true בזמן שפרסום טיוטה מריץ מחדש את ה-POST: הטופס שומר חי, בלי טיוטה ובלי שינוי סטטוס |
CONTENT_WORKFLOW::$last_save | null | תוצאת שמירת הטופס האחרונה בבקשה: ok, table, id, errors |
CONTENT_WORKFLOW::ready()#
public static function ready(): bool
האם הטבלה CRM_content_drafts קיימת באתר.
CONTENT_WORKFLOW::enabled()#
public static function enabled($table): bool
האם הטבלה משתתפת (שלושת התנאים שבראש העמוד). מקבלת שם עם או בלי CRM_, ושומרת תשובה לבקשה.
CONTENT_WORKFLOW::type()#
public static function type($table): ?array
שורת CRM_content_types של טבלה משתתפת, או null.
CONTENT_WORKFLOW::query_filter()#
public static function query_filter($table): string
התנאי שמתווסף ל-DB::query. מחזירה מחרוזת ריקה בניהול, כש-$bypass דלוק, או לטבלה שאינה משתתפת. בתצוגה מקדימה תקפה היא פותחת גם את הרשומה אחת של התצוגה. את הפונקציה מפעילה הליבה, לא קוד אתר.
CONTENT_WORKFLOW::can_publish() ו-can_edit()#
public static function can_publish($table): bool
public static function can_edit($table): bool
האם המנהל הנוכחי רשאי לפרסם או לערוך את סוג התוכן. false כשאין פאנל לסוג.
CONTENT_WORKFLOW::needs()#
public static function needs($from, $to): ?string
ההרשאה שמעבר סטטוס דורש: "edit" בין draft ל-review, "publish" לכל מעבר אחר, null כשהסטטוס זהה או שאינו סטטוס.
CONTENT_WORKFLOW::record()#
public static function record($table, $id): ?array
עמודות wz_* של רשומה (id, wz_status, wz_publish_at, wz_unpublish_at, wz_published_at, wz_created_by), או null.
CONTENT_WORKFLOW::set_status()#
public static function set_status($table, $ids, $to, $opts = []): array
משנה סטטוס של רשומות. ההרשאות באחריות הקורא (ה-API בודק אותן עם needs()).
| פרמטר | משמעות |
|---|---|
$ids | מזהה או מערך מזהים |
$to | אחד הסטטוסים |
$opts["publish_at"] | חובה כש-$to הוא scheduled |
$opts["unpublish_at"] | תאריך הסתרה, מחרוזת ריקה מנקה אותו |
$opts["source"] | מקור השינוי לאירוע (ברירת מחדל api) |
מחזירה ["success" => true, "changed" => [ids], "skipped" => [id => סיבה]], או ["success" => false, "error" => ...] (not_workflow, bad_status, publish_at_required). פרסום ידני של רשומה שתאריך ההסתרה שלה כבר עבר מנקה את התאריך, כדי שלא תוסתר מיד. כל שינוי שולח אירוע status (אירועי תוכן) ומנקה את מטמון העמוד.
$res = CONTENT_WORKFLOW::set_status("pages", [12, 13], "scheduled", ["publish_at" => "2026-11-01 08:00:00"]);
CONTENT_WORKFLOW::counts()#
public static function counts($table): array
{draft, review, scheduled, published, hidden, expired, with_draft, total}. expired הוא רשומות מפורסמות שתאריך ההסתרה שלהן עבר, ו-with_draft הוא רשומות שיש להן טיוטה פתוחה.
CONTENT_WORKFLOW::pending()#
public static function pending($limit = 30): array
מה שממתין לאדם, מכל סוגי התוכן שהמנהל רשאי לראות: רשומות וטיוטות בסטטוס review או scheduled, מתוזמנות לפי התאריך ואחריהן ממתינות לפי החדשות. כל פריט: tbl, label, panel, row_id, lang_id, title, status, publish_at, kind (record או draft), draft_id, admin_id, updated_at. המקסימום 200.
CONTENT_WORKFLOW::draft(), draft_by_id() ו-draft_ids()#
public static function draft($table, $id, $lang): ?array
public static function draft_by_id($draft_id): ?array
public static function draft_ids($table, $ids, $lang = null): array
הראשונה מחזירה את הטיוטה של רשומה בשפה (עם post_data ו-overlay מפוענחים), השנייה לפי המזהה של הטיוטה. draft_ids מחזירה [row_id => סטטוס] לכמה רשומות בשאילתה אחת, למשל לסימון "יש שינויים שלא פורסמו" בעמוד של רשימה.
CONTENT_WORKFLOW::discard_draft()#
public static function discard_draft($draft_id): bool
זורקת טיוטה. לא נוגעת ברשומה החיה.
CONTENT_WORKFLOW::publish_draft()#
public static function publish_draft($draft_id, $opts = []): array
מפרסמת טיוטה כמתואר למעלה. $opts["force"] מפרסם גם מעל שמירה חיה חדשה יותר. מחזירה ["success" => true, "tbl", "row_id", "lang_id", "version"], או ["success" => false, "error" => ...] עם אחד מהקודים no_draft, not_workflow, record_missing, draft_unreadable, conflict (עם conflict), save_failed (עם errors).
CONTENT_WORKFLOW::form_draft(), form_columns() ו-form_result()#
public static function form_draft($form): ?string
public static function form_columns($form, $qu): void
public static function form_result($form, $ok): void
שלוש נקודות החיבור של Form לתהליך: לפני שמירה (להסיט לטיוטה או לדחות), רגע לפני ה-INSERT או ה-UPDATE (לקבוע את עמודות wz_*), ואחרי שמירה (לתעד את התוצאה ולנקות מטמון). הליבה מפעילה אותן, ופאנל לא אמור לקרוא להן.