PAGE API

מחזור החיים של בקשת עמוד ב-PAGE::load, ההרכבה של מסמך ה-HTML ב-PAGE::output, וכל ה-API הציבורי של המחלקה: נכסים, meta, אירועים, theme, מטמון עמודים ו-parse_page.

⏱ 10 דק' קריאה 1806 מילים ערוך דף זה ב-GitHub

PAGE היא המחלקה שמרכיבה את העמוד. בקר מחזיר מחרוזת, ו-PAGE מניחה אותה בתוך ה-theme, מוסיפה <head> עם הנכסים, תגי ה-SEO והסקריפטים, ומדפיסה מסמך HTML שלם. בעמוד הזה: מה קורה ב-PAGE::load לפי הסדר, איך נראה המסמך שיוצא, ומה כל מתודה ומשתנה ציבורי עושים. פירוט הנכסים בצנרת הנכסים, תגי ה-SEO בתגי SEO, ורשימת חתימות מקוצרת ברפרנס PAGE.

הערה

כל המתודות והמשתנים כאן הם static: קוראים להם PAGE::name(...) מכל מקום. המצב שלהם הוא פר-בקשה (PHP לא חולק זיכרון בין בקשות), ו-PAGE::reset() מאפס אותו בתחילת PAGE::load.

מחזור החיים: PAGE::load#

core.php קורא ל-PAGE::load($_SERVER['REQUEST_URI']). הסדר, כפי שהוא בקוד:

#שלבהערה
1PAGE::reset()מאפס נכסים, meta, אירועים, theme, מטמון עמודים, favicon ו-is_404
2PARAMS::init() ו-SEO::init()טוענים את פרמטרי המערכת ואת ברירות המחדל של ה-SEO
3ROUTER::parse_friendly_url($url)קובע בקר, מתודה ו-$_GET (ניתוב)
4בדיקת דומיין (צד לקוח)die("URL ERROR") כשהדומיין לא מותר. מדלגים כש-CONFIG::$ignore_domain_check === true, ועבור minify ו-Tools
5ROUTER::redirections()הפניות 301 (הפניות), צד לקוח בלבד
6FILES::include_dir("application/includes")כל קבצי ה-*.php שם, לפי סדר שמות, פעם אחת. צד לקוח בלבד
7JS של המערכתכל system/js/*.js נוסף כנכס: system.js ב-head, השאר ב-body_end. רק כש-PAGE::$include_system_js הוא true (ריצת צד לקוח)
8קבוצות minifyלכל קבוצה ב-CRM_minify_groups שה-theme שלה ריק או שווה ל-PAGE::$theme: add_asset_group
9אדמיןטעינת הספריות של האדמין ו-application/admin/includes
10LANGS::init_words() ו-PAGE::trigger("SYSTEM_LOADED")נקודת ההרחבה הראשונה שבה הכל טעון
11בחירת theme והרצת הבקרPAGE::set_theme(platform_data["deftheme"]) אם לא נבחר אחר, ואז MODULE::get_html
12PAGE::output()הרכבת המסמך

שלוש משמעויות מעשיות:

  • קוד ב-application/includes/*.php רץ אחרי reset ולפני הבקר. כאן מוסיפים נכסים גלובליים, PAGE::bind(...) ו-PAGE::set_theme(...). בקר שרץ אחר כך עדיין יכול להוסיף ולהסיר נכסים.
  • שלב 8 תלוי ב-theme בזמן הקריאה. PAGE::set_theme שנקרא בבקר (שלב 11) מאוחר מדי כדי להשפיע על קבוצות ה-minify, שנבחרו בשלב 8 לפי ה-theme באותו רגע. בחירת theme שמשפיעה על קבוצות נעשית ב-application/includes. זה נכון גם הפוך: עד שלב 11 PAGE::$theme ריק, ולכן קבוצה שה-theme שלה מוגדר (למשל default) נטענת רק אם application/includes קרא ל-PAGE::set_theme("default"). קבוצה עם theme ריק נטענת תמיד.
  • application/includes/init.php הוא חריג. core.php טוען אותו לפני PAGE::load, כלומר לפני reset, ולכן bind ו-add_asset שבו נמחקים. מה שצריך לשרוד, כמו PAGE::$parse_page_func (ראו למטה), שייך לשם. נכסים ואירועים שייכים לקובץ אחר באותה תיקייה.

המסמך ש-PAGE::output מרכיבה#

אם $_GET["pmode"] הוא empg או inner, אין theme ואין מעטפת HTML: יוצא רק מה שהבקר החזיר, והנכסים נרשמים בכותרות התשובה (scripts ו-scripts_ver, שבהן system.js משתמש כדי לדעת מה כבר נטען). זו הדרך ל-JSON, לקטעי HTML שנטענים ב-AJAX ולכל פלט שאינו עמוד (בקרים).

אחרת המסמך נבנה כך:

מקוםמה נכנס
<html lang="he" dir="…">ה-lang קבוע ל-he. ה-dir הוא platform_data["direction"]
<head>SEO::tags_summary(), <base href>, נכסי CSS ואז JS של אזור head, print_meta_tags("head"), <meta name="ROBOTS"> מ-PAGE::$robots, <meta name="copyright"> (אלא אם CONFIG::$show_wizzo_credits === false), <link rel="shortcut icon"> מ-PAGE::$favicon, ובצד לקוח גם SEO::get_schema("WebPage") וסקריפטים מטבלת CRM_scripts שאזורם head
<body class="…">המחלקה היא הכיוון ועוד MISC::$GLOBALS["body_class"] אם נקבע. אחריה: נכסי body_start, סקריפטי CRM_scripts של body_start, ו-print_meta_tags("body_start")
גוף העמודה-HTML של ה-theme (בלי תגי <script>, ראו הערה)
סוף הגוףנכסי body_end, ה-JS שנטען אחרי אינטראקציה, תגי ה-<script> של ה-theme (מכווצים ב-JShrink), writeLoadedFile(), סקריפטי CRM_scripts של body_end, print_meta_tags("body_end"), ולבסוף /tag_manager.js?id=system אם קיים system/system_tags.json

כל המסמך עובר minify_html (כיווץ רווחים), אלא אם CONFIG::$minify_html === false.

שימו לב
תגי <script> ב-theme ובתבניות מוצאים מהמקום שלהם ועוברים לסוף ה-<body>. תג <script> בגוף ה-theme נחתך מה-HTML ומודפס אחרי נכסי body_end. תג ששמו כולל את המילה nominify נשאר במקום ולא נגע בו. סקריפט שצריך לרוץ באמצע העמוד (כמו קוד שכותב ל-document.write) חייב להכיל nominify, למשל כתכונה (<script data-x="nominify">) או כהערה בתוכו.

שימו לב
minify_html מבוסס regex ועלול לפגוע בתוכן. הוא מכווץ רווחים, מוחק סוף שורה שנראה כהערת // (גם //localhost בסוף כתובת), ומקצר רצפי whitespace גם בתוך <pre>, <textarea> ו-JS מוטמע (ממצא CORE-21). בעמוד עם בלוקי קוד או טקסט שהרווחים בו משמעותיים, כבו אותו עם CONFIG::$minify_html = false בקובץ ההגדרות (הגדרות).

נכסים: JS ו-CSS#

הנכסים נאספים בזמן הבקשה בשני מערכים ($assets_css, $assets_js), והסוג נקבע לפי תת-מחרוזת בכתובת: מי שמכילה .css היא CSS, מי שמכילה .js היא JS, ומי שמכילה css בלי נקודה גם היא CSS. כתובת יחסית מקבלת את הדומיין של האתר, וכל נכס מקבל ?ver= עם הערך של הפרמטר attaches_version, כך שאחרי מחיקת מטמון הדפדפנים מורידים מחדש.

PAGE::add_asset($fileSrc, $must = false, $area = "head", $order = "append")#

הדרך הרגילה להוסיף קובץ.

פרמטרמשמעות
$fileSrcנתיב יחסי לשורש האתר או כתובת מלאה
$musttrue מסמן נכס חובה, שמועבר גם כש-IncludeJsCss(true) מבקש רק חובה (שימוש פנימי)
$areahead, body_start או body_end
$orderappend (ברירת המחדל) או prepend, שמכניס לתחילת הרשימה

הוספה של קובץ שכבר נרשם מחליפה את הרישום הקודם: הוא עובר לסוף (או לתחילת) הרשימה, ולא נשלח פעמיים.

PAGE::add_asset("themes/default/style.scss.css", false, "head");
PAGE::add_asset("themes/default/app.js", false, "body_end");
PAGE::add_asset("https://cdn.example.com/lib.js", false, "body_end");

PAGE::add_asset_advanced($fileSrc, $m_settings = [])#

כשצריך שליטה בטעינה. המפתחות ב-$m_settings (ברירות המחדל בסוגריים):

מפתחמשמעות
area (head)head, body_start או body_end
async (false)ב-JS: async="async". ב-CSS: טעינה לא חוסמת (preload ואז החלפה ל-stylesheet)
defer (false)ב-JS: defer="defer"
after_user_intraction (false)לא נטען עם העמוד, אלא בלחיצה או בלחיצת מקש הראשונה של המבקר (ריצת צד לקוח)
print (false)ב-CSS: ה-SCSS המקומפל נכנס inline בתוך <style>, בלי בקשה נוספת. אם הקומפילציה נכשלה חוזרים ל-<link>
PAGE::add_asset_advanced("themes/default/chat.js", ["area" => "body_end", "after_user_intraction" => true]);
PAGE::add_asset_advanced("themes/default/critical.scss.css", ["print" => true]);

שימו לב: add_asset_advanced לא מקבל $order, והוא תמיד מוסיף לסוף. הערך after_user_intraction (כך כתוב בקוד, עם שגיאת כתיב) גם מבטל את כל שאר ההגדרות של הנכס.

שאר מתודות הנכסים#

מתודהפירוט
PAGE::remove_asset($fileSrc)מסיר נכס לפי הכתובת המדויקת שנרשם בה. שימושי כדי להוריד נכס של הליבה או של ה-theme בעמוד מסוים
PAGE::add_asset_group($id)מוסיף קבוצת minify לפי ה-id שלה. נקרא אוטומטית ב-load לכל הקבוצות. הקבצים שבקבוצה לא נשלחים בנפרד
PAGE::IncludeJsCss($onlyMust = false, $type = "both", $area = "")מחזיר מחרוזת HTML של התגים, לפי סוג (js, css, both) ואזור. נקראת מ-output, ורק אם בונים מסמך בעצמכם צריך אותה
PAGE::IncludeAfterIntercation()מחזיר את הסקריפט שמאזין ללחיצה ולמקש וטוען את נכסי after_user_intraction
PAGE::JsIncludeJsCss()כותב את רשימת הנכסים לכותרות scripts ו-scripts_ver (במצב pmode)
PAGE::writeLoadedFile($onlyMust = false)מחזיר <script> שמודיע ל-writeLoadedFile של system.js אילו קבצים כבר נטענו, כדי שלא יטענו שוב ב-AJAX
טיפ

בבקר, add_asset נקרא לפני ה-return: הנכסים נאספים בזמן הבקשה, ו-output רץ רק אחרי שהבקר חזר. בקר שנקרא ב-pmode=empg שולח את הנכסים רק בכותרות, ולכן קוד JS צריך לטעון אותם בעצמו.

תגי meta ו-head#

מתודהפירוט
PAGE::add_meta($val, $area = "head")מוסיף מחרוזת HTML גולמית (תג <meta>, <link>, כל דבר) לאזור head, body_start או body_end. הערך לא עובר escape
PAGE::print_meta_tags($area = "")מחזיר את כל המחרוזות של האזור. נקראת מ-output
PAGE::$robotsתוכן תג ROBOTS. ברירת המחדל "ALL". לדוגמה PAGE::$robots = "NOINDEX, FOLLOW";
PAGE::$faviconכתובת ה-favicon. ברירת המחדל "/favicon.ico". false מבטל את התג
PAGE::add_meta('<meta name="viewport" content="width=device-width, initial-scale=1">');
PAGE::add_meta('<link rel="preconnect" href="https://fonts.gstatic.com">');

כותרת, תיאור ותגי Open Graph נקבעים דרך SEO::set, לא דרך add_meta, כדי שלא יופיעו פעמיים (תגי SEO).

אירועים#

מנגנון פשוט של hooks: PAGE::bind($event, Closure $func) רושם מאזין, ו-PAGE::trigger($event, $args = []) מפעיל את כולם לפי סדר הרישום, וכל אחד מקבל את $args. האירועים נמחקים ב-reset, ולכן רושמים אחרי תחילת load (ב-application/includes, לא ב-init.php).

// application/includes/hooks.php
PAGE::bind("SYSTEM_LOADED", function ($args) {
	PAGE::add_asset("themes/default/extra.js", false, "body_end");
});

PAGE::bind("delete.cache", function ($args) {
	// למשל: ניקוי מטמון חיצוני
});

האירועים שהליבה מפעילה בעצמה:

אירועמתי$args
SYSTEM_LOADEDב-PAGE::load, אחרי שהכל נטען ולפני הבקרריק
delete.cacheאחרי "מחיקת מטמון" (Tools::delete_cache, וגשר ה-MCP)ריק
storage.updateאחרי עדכון קובץ באחסון["id" => <מזהה הקובץ>]
words_updateאחרי עדכון מילים בפאנל ה-UIריק

אתם מוזמנים להפעיל אירועים משלכם, כמו PAGE::trigger('order.created', $order), והם עובדים באותה דרך, אבל trigger ו-bind חייבים להיות באותה בקשה.

theme#

PAGE::$theme הוא שם ה-theme של העמוד. PAGE::set_theme($theme) מציבה אותו, ו-PAGE::set_theme(false) מוציאה את העמוד בלי theme (המסמך עדיין עטוף ב-<html>, אבל הגוף הוא הפלט של הבקר). כשאין בחירה אחרת בצד לקוח, load מציבה את platform_data["deftheme"]. הפרטים בתבניות ו-themes.

מטמון עמודים#

חברפירוט
PAGE::$cache_this_pagetrue שומר את העמוד המוגמר בקובץ (ברירת המחדל false)
PAGE::$cache_this_page_hoursמשך החיים בשעות (ברירת המחדל 24)

בפועל לא כותבים אותם ישירות אלא קוראים ל-cache_engine::cache_all_page($hours = 24, $set_page = false) בבקר (מטמון עמודים). PAGE::$cache_this_page נשמר רק בצד לקוח וכש-CONFIG::$allow_cache דלוק, ו-MODULE::errorpage() מאפסת אותו כדי שעמוד 404 לא יישמר.

parse_page: עיבוד אחרי המטמון#

PAGE::$parse_page_func הוא callable אופציונלי שמקבל את ה-HTML המוגמר ומחזיר HTML. הוא רץ גם על עמוד שהוגש מהמטמון, ולכן הוא המקום לתוכן שחייב להיות טרי בכל בקשה (שם המשתמש בכותרת, מונה עגלה, nonce).

// application/includes/init.php  (חייב להיות כאן כדי לרוץ גם בפגיעה במטמון)
PAGE::$parse_page_func = function ($html) {
	return str_replace("{{year}}", date("Y"), $html);
};

PAGE::parse_page($content) מריצה את ה-callable ואחר כך את MASK::out על התוצאה (מצב הסוואה).

שימו לב
parse_page_func חייב להירשם ב-application/includes/init.php, לא ב-application/includes/<other>.php. בפגיעה במטמון, core.php מגיש את הקובץ לפני ש-PAGE::load רץ, ולכן קבצים אחרים ב-application/includes עוד לא נטענו וה-callable לא קיים. בנוסף, כל עוד הוא קיים, הליבה מוותרת על מסלול ההגשה המהיר של קבצי gzip ופותחת כל עמוד מהמטמון, מפענחת ומריצה אותו.

מתודות נוספות#

מתודהפירוט
PAGE::is_mobile()true רק לטלפון (לא לטאבלט), לפי MobileDetect. התוצאה נשמרת לבקשה. מצריכה vendor/autoload.php של הליבה (Composer)
PAGE::reset($params = false)מאפסת את כל המצב. נקראת בתחילת load, ובדרך כלל לא צריך לקרוא לה
PAGE::backup()מחזירה מערך עם כל המצב הנוכחי, בפורמט ש-reset($params) מקבלת. שימושי כדי להריץ עמוד בתוך עמוד ולהחזיר את המצב
PAGE::getAllScripts($html)מחלצת מ-HTML את כל תגי <script> השלמים. משמשת את output להעברת הסקריפטים לסוף הגוף
PAGE::minify_html($body)כיווץ הרווחים, ראו האזהרה למעלה
PAGE::output()מרכיבה ומחזירה את המסמך
PAGE::load($url, $isMobile = null)המחזור המלא. $isMobile בוליאני מכריח את תוצאת is_mobile

ראו גם#

מצאתם טעות או חוסר? תקנו את הדף או פתחו Issue בריפו. התיעוד נכתב מתוך הקוד של ליבה 5.0.115.