את ה-<head> של כל עמוד באתר הציבורי בונה PAGE::output, לא ה-theme. הבקר מגדיר ערכים (SEO::set, PAGE::add_meta, PAGE::$robots), והליבה מדפיסה אותם בסדר קבוע. העמוד הזה מראה את הסדר הזה ואת נקודות ההשפעה שלכם; את הפרטים המלאים של מחלקת SEO, של FormInput_SEO ושל חבילת ה-SEO תמצאו ב-SEO למפתחי אתר, ב-SEO (רפרנס) וב-חבילת ה-SEO.
סדר התגיות ב-<head>#
כך נראה ה-<head> של עמוד באתר הציבורי (CONFIG::$system_type == "client"):
| # | מה נפלט | מקור |
|---|---|---|
| 1 | <meta http-equiv="Content-Type" ... charset=utf-8> | קבוע |
| 2 | <title>, og:*, twitter:*, <meta name="description">, <meta name="keywords">, twitter:card ותגית האימות של Search Console | SEO::tags_summary() |
| 3 | <base href="<protocol>://<original_site_url>"> | CONFIG::$protocol, CONFIG::$original_site_url |
| 4 | תגי CSS של אזור head, ואז תגי JS של אזור head | PAGE::IncludeJsCss (ראו צינור הנכסים) |
| 5 | תגים שנרשמו עם PAGE::add_meta($val) (אזור head, ברירת מחדל) | PAGE::print_meta_tags("head") |
| 6 | <meta name="ROBOTS" content="..."> | PAGE::$robots, ברירת מחדל "ALL" |
| 7 | <meta name="copyright" content="2003-2022, Wizzo CMS3.0"> | נפלט אלא אם CONFIG::$show_wizzo_credits === false |
| 8 | <link rel="shortcut icon"> | PAGE::$favicon, ברירת מחדל /favicon.ico |
| 9 | JSON-LD של WebPage | SEO::get_schema("WebPage") |
| 10 | סקריפטים מהפאנל Scripts עם area = head | טבלת scripts |
האלמנט <html> נפלט עם lang="he" קבוע ו-dir לפי CONFIG::$platform_data["direction"]. בפאנל הניהול ה-<head> שונה: כותרת <seo_title> | CMS, favicon של הפאנל, וללא JSON-LD וללא סקריפטים של האתר.
lang="he" קבוע בקוד, גם באתרים רב-לשוניים. אם אתר באנגלית צריך lang="en", hreflang או alternate אחרים, הוסיפו אותם ב-PAGE::add_meta. הליבה לא מדפיסה hreflang ולא rel="canonical" (ראו SEO למפתחי אתר).מה אתם קובעים#
כותרת, תיאור ו-Open Graph#
class news extends wz_controller
{
function item()
{
$row = DB::query("news", ["id" => (int)$_GET["id"]])->get_row();
if (!$row) return "ERRORPAGE";
SEO::set("title", $row["title"]); // meta_title וגם og_title
SEO::set("description", $row["summary"]); // meta_description וגם og_description
SEO::set("image", (int)$row["image_id"]); // מספר = STORAGE::get_thumb(id, 1200, 627)
SEO::set("url", CONFIG::$site_url . "news/" . (int)$row["id"]);
SEO::set("og_type", "article"); // מפתח לא מוכר נשמר כמו שהוא
return $this->view("news/item", ["row" => $row]);
}
}
SEO::set (כינוי ל-SEO::set_var) מפעיל strip_tags על title, description ו-keywords. שדות שלא הוגדרו מקבלים בסוף ברירת מחדל מהפלטפורמה: seo_title, seo_description ו-seo_keywords מ-CONFIG::$platform_data. כשלא הוגדרה כותרת בכלל, שם האתר לא מתווסף שוב אחרי הכותרת.
דריסה מהפאנל: seo_center#
אחרי שהבקר סיים, tags_summary() בודק אם יש רשומה בטבלת seo_center לעמוד הזה, ואם כן היא דורסת את מה שהבקר קבע, שדה אחר שדה (שדה ריק ברשומה מדולג):
- לפי הנתיב הנוכחי:
page_keyשווה לנתיב (בלי/בתחילה ובסוף, אחריurldecode) ו-is_by_url = 1. - אם לא נמצאה, לפי
SEO::$page_key(מוגדר עםSEO::set_key("news_5")) ו-is_by_url = 0.
כלומר מי שעורך את ה-SEO בפאנל, בדרך כלל דרך FormInput_SEO, תמיד מנצח את ברירות המחדל שבקוד. עמודות מבניות של הטבלה (id, ord, lang, platform_id, is_by_url ועוד) מסוננות ולא הופכות ל-meta.
תגים מותאמים אישית ו-robots#
// תג נוסף ל-head
PAGE::add_meta('<link rel="canonical" href="' . htmlspecialchars(CONFIG::$site_url . "news/5", ENT_QUOTES) . '">');
// תג בסוף ה-body (למשל סקריפט מדידה)
PAGE::add_meta('<script>/* ... */</script>', "body_end");
// עמוד שלא צריך להיכנס לאינדקס
PAGE::$robots = "noindex, follow";
// כיבוי favicon (למשל בדף שמגיש favicon בעצמו)
PAGE::$favicon = false;
add_meta($val, $area = "head") מקבל HTML גולמי ומדפיס אותו כפי שהוא, בלי escaping. אזורים חוקיים: head, body_start, body_end.
PAGE::add_meta לא מסנן כלום. ערך שמגיע מקלט משתמש חייב לעבור htmlspecialchars לפני שהוא נכנס ל-HTML שאתם בונים (ראו XSS).מלכודות ידועות#
אל תשתמשו ב-SEO::get_schema("Organization") ובמיוחד לא ב-get_schema("NewsArticle"). המימוש מכיל נתוני דוגמה של אתר אחר: לוגו מדומיין חיצוני, מחבר "משה משה" ותאריכים קבועים מ-2021. רק WebPage בטוח, והוא נפלט אוטומטית. בנו JSON-LD אחר בעצמכם ורשמו אותו עם PAGE::add_meta. הדוגמה המלאה ב-SEO למפתחי אתר.
<title> נפלט מהערך כפי שהוא, בלי קידוד HTML (CORE-47): & בכותרת נשאר &. שאר ה-meta עוברים htmlspecialchars. בנוסף, שאילתות seo_center רצות בלי מטמון בכל רינדור של עמוד שלא הוגש מ-מטמון עמודים, והחיפוש לא מסנן לפי פלטפורמה או שפה, כך שאותו נתיב מקבל אותו meta בכל הדומיינים.PAGE::$robots אינו מאופס ב-PAGE::reset. הוא משפיע על כל מה שנרנדר באותה בקשה. ערך שהוגדר לפני PAGE::load (ב-application/includes/init.php) נשאר.עמוד שהוגש מהמטמון המלא כבר כולל את כל ה-<head> שנבנה בזמן השמירה. שינוי ב-seo_center או בקוד לא יופיע עד שהמטמון פג או מנוקה (ניקוי מטמון).
ראו גם#
- SEO למפתחי אתר:
SEO::set,FormInput_SEO, robots, 404 מול 503, sitemaps ו-schema - SEO (רפרנס): כל המתודות של
SEO - PAGE API:
add_meta,print_meta_tags, מחזור החיים של העמוד - כתובות ידידותיות
- חבילת ה-SEO: המנוע שבודק את מה שנפלט כאן